mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-12-24 09:19:51 +01:00
@@ -12,6 +12,11 @@ const styles = {
|
|||||||
},
|
},
|
||||||
minWidthOfLabel: {
|
minWidthOfLabel: {
|
||||||
minWidth: "4.5rem"
|
minWidth: "4.5rem"
|
||||||
|
},
|
||||||
|
wrapper: {
|
||||||
|
padding: "1rem 1.5rem 0.25rem 1.5rem",
|
||||||
|
border: "1px solid #eee",
|
||||||
|
borderRadius: "5px 5px 0 0"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,7 +48,13 @@ class BranchSelector extends React.Component<Props, State> {
|
|||||||
|
|
||||||
if (branches) {
|
if (branches) {
|
||||||
return (
|
return (
|
||||||
<div className="box field is-horizontal">
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"has-background-light field",
|
||||||
|
"is-horizontal",
|
||||||
|
classes.wrapper
|
||||||
|
)}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"field-label",
|
"field-label",
|
||||||
|
|||||||
@@ -1,14 +1,23 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import injectSheet from "react-jss";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
classes: any
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
textinfo: {
|
||||||
|
color: "#98d8f3 !important"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class HelpIcon extends React.Component<Props> {
|
class HelpIcon extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
return <i className={classNames("fa fa-question has-text-info")} />
|
const { classes } = this.props;
|
||||||
|
return <i className={classNames("fa fa-question-circle has-text-info", classes.textinfo)}></i>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HelpIcon;
|
export default injectSheet(styles)(HelpIcon);
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Button, { type ButtonProps } from "./Button";
|
import Button, { type ButtonProps } from "./Button";
|
||||||
|
|
||||||
class AddButton extends React.Component<ButtonProps> {
|
class AddButton extends React.Component<ButtonProps> {
|
||||||
render() {
|
render() {
|
||||||
return <Button color="default" {...this.props} />;
|
return <Button color="default" {...this.props} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AddButton;
|
export default AddButton;
|
||||||
|
|||||||
@@ -1,24 +1,27 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import injectSheet from "react-jss";
|
import injectSheet from "react-jss";
|
||||||
import AddButton, { type ButtonProps } from "./Button";
|
import SubmitButton, { type ButtonProps } from "./SubmitButton";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
spacing: {
|
spacing: {
|
||||||
margin: "1em 0 0 1em"
|
marginTop: "2em",
|
||||||
}
|
border: "2px solid #e9f7fd",
|
||||||
};
|
padding: "1em 1em"
|
||||||
|
}
|
||||||
class CreateButton extends React.Component<ButtonProps> {
|
|
||||||
render() {
|
};
|
||||||
const { classes } = this.props;
|
|
||||||
return (
|
class CreateButton extends React.Component<ButtonProps> {
|
||||||
<div className={classNames("is-pulled-right", classes.spacing)}>
|
render() {
|
||||||
<AddButton {...this.props} />
|
const { classes } = this.props;
|
||||||
</div>
|
return (
|
||||||
);
|
<div className={classNames("has-text-centered", classes.spacing)}>
|
||||||
}
|
<SubmitButton {...this.props} />
|
||||||
}
|
</div>
|
||||||
|
);
|
||||||
export default injectSheet(styles)(CreateButton);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default injectSheet(styles)(CreateButton);
|
||||||
|
|||||||
@@ -1,31 +1,31 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import Logo from "./../Logo";
|
import Logo from "./../Logo";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children?: React.Node
|
children?: React.Node
|
||||||
};
|
};
|
||||||
|
|
||||||
class Header extends React.Component<Props> {
|
class Header extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { children } = this.props;
|
const { children } = this.props;
|
||||||
return (
|
return (
|
||||||
<section className="hero is-dark is-small">
|
<section className="hero is-dark is-small">
|
||||||
<div className="hero-body">
|
<div className="hero-body">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="columns is-vcentered">
|
<div className="columns is-vcentered">
|
||||||
<div className="column">
|
<div className="column">
|
||||||
<Logo />
|
<Logo />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="hero-foot">
|
<div className="hero-foot">
|
||||||
<div className="container">{children}</div>
|
<div className="container">{children}</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Header;
|
export default Header;
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 48 KiB |
BIN
scm-ui/public/images/scmManagerHero.jpg
Normal file
BIN
scm-ui/public/images/scmManagerHero.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
@@ -20,34 +20,41 @@ class AdminSettings extends React.Component<Props> {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Subtitle subtitle={t("admin-settings.name")} />
|
<Subtitle subtitle={t("admin-settings.name")} />
|
||||||
<AdminGroupTable
|
<div className="columns">
|
||||||
adminGroups={adminGroups}
|
<div className="column is-half">
|
||||||
onChange={(isValid, changedValue, name) =>
|
<AdminGroupTable
|
||||||
this.props.onChange(isValid, changedValue, name)
|
adminGroups={adminGroups}
|
||||||
}
|
onChange={(isValid, changedValue, name) =>
|
||||||
disabled={!hasUpdatePermission}
|
this.props.onChange(isValid, changedValue, name)
|
||||||
/>
|
}
|
||||||
<AddEntryToTableField
|
disabled={!hasUpdatePermission}
|
||||||
addEntry={this.addGroup}
|
/>
|
||||||
disabled={!hasUpdatePermission}
|
|
||||||
buttonLabel={t("admin-settings.add-group-button")}
|
<AddEntryToTableField
|
||||||
fieldLabel={t("admin-settings.add-group-textfield")}
|
addEntry={this.addGroup}
|
||||||
errorMessage={t("admin-settings.add-group-error")}
|
disabled={!hasUpdatePermission}
|
||||||
/>
|
buttonLabel={t("admin-settings.add-group-button")}
|
||||||
<AdminUserTable
|
fieldLabel={t("admin-settings.add-group-textfield")}
|
||||||
adminUsers={adminUsers}
|
errorMessage={t("admin-settings.add-group-error")}
|
||||||
onChange={(isValid, changedValue, name) =>
|
/>
|
||||||
this.props.onChange(isValid, changedValue, name)
|
</div>
|
||||||
}
|
<div className="column is-half">
|
||||||
disabled={!hasUpdatePermission}
|
<AdminUserTable
|
||||||
/>
|
adminUsers={adminUsers}
|
||||||
<AddEntryToTableField
|
onChange={(isValid, changedValue, name) =>
|
||||||
addEntry={this.addUser}
|
this.props.onChange(isValid, changedValue, name)
|
||||||
disabled={!hasUpdatePermission}
|
}
|
||||||
buttonLabel={t("admin-settings.add-user-button")}
|
disabled={!hasUpdatePermission}
|
||||||
fieldLabel={t("admin-settings.add-user-textfield")}
|
/>
|
||||||
errorMessage={t("admin-settings.add-user-error")}
|
<AddEntryToTableField
|
||||||
/>
|
addEntry={this.addUser}
|
||||||
|
disabled={!hasUpdatePermission}
|
||||||
|
buttonLabel={t("admin-settings.add-user-button")}
|
||||||
|
fieldLabel={t("admin-settings.add-user-textfield")}
|
||||||
|
errorMessage={t("admin-settings.add-user-error")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,26 @@ class BaseUrlSettings extends React.Component<Props> {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Subtitle subtitle={t("base-url-settings.name")} />
|
<Subtitle subtitle={t("base-url-settings.name")} />
|
||||||
<Checkbox
|
<div className="columns">
|
||||||
checked={forceBaseUrl}
|
<div className="column is-half">
|
||||||
label={t("base-url-settings.force-base-url")}
|
<Checkbox
|
||||||
onChange={this.handleForceBaseUrlChange}
|
checked={forceBaseUrl}
|
||||||
disabled={!hasUpdatePermission}
|
label={t("base-url-settings.force-base-url")}
|
||||||
helpText={t("help.forceBaseUrlHelpText")}
|
onChange={this.handleForceBaseUrlChange}
|
||||||
/>
|
disabled={!hasUpdatePermission}
|
||||||
<InputField
|
helpText={t("help.forceBaseUrlHelpText")}
|
||||||
label={t("base-url-settings.base-url")}
|
/>
|
||||||
onChange={this.handleBaseUrlChange}
|
</div>
|
||||||
value={baseUrl}
|
<div className="column is-half">
|
||||||
disabled={!hasUpdatePermission}
|
<InputField
|
||||||
helpText={t("help.baseUrlHelpText")}
|
label={t("base-url-settings.base-url")}
|
||||||
/>
|
onChange={this.handleBaseUrlChange}
|
||||||
|
value={baseUrl}
|
||||||
|
disabled={!hasUpdatePermission}
|
||||||
|
helpText={t("help.baseUrlHelpText")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,70 +36,98 @@ class GeneralSettings extends React.Component<Props> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<InputField
|
<div className="columns">
|
||||||
label={t("general-settings.realm-description")}
|
<div className="column is-half">
|
||||||
onChange={this.handleRealmDescriptionChange}
|
<InputField
|
||||||
value={realmDescription}
|
label={t("general-settings.realm-description")}
|
||||||
disabled={!hasUpdatePermission}
|
onChange={this.handleRealmDescriptionChange}
|
||||||
helpText={t("help.realmDescriptionHelpText")}
|
value={realmDescription}
|
||||||
/>
|
disabled={!hasUpdatePermission}
|
||||||
<InputField
|
helpText={t("help.realmDescriptionHelpText")}
|
||||||
label={t("general-settings.date-format")}
|
/>
|
||||||
onChange={this.handleDateFormatChange}
|
</div>
|
||||||
value={dateFormat}
|
<div className="column is-half">
|
||||||
disabled={!hasUpdatePermission}
|
<InputField
|
||||||
helpText={t("help.dateFormatHelpText")}
|
label={t("general-settings.date-format")}
|
||||||
/>
|
onChange={this.handleDateFormatChange}
|
||||||
<InputField
|
value={dateFormat}
|
||||||
label={t("general-settings.plugin-url")}
|
disabled={!hasUpdatePermission}
|
||||||
onChange={this.handlePluginUrlChange}
|
helpText={t("help.dateFormatHelpText")}
|
||||||
value={pluginUrl}
|
/>
|
||||||
disabled={!hasUpdatePermission}
|
</div>
|
||||||
helpText={t("help.pluginRepositoryHelpText")}
|
</div>
|
||||||
/>
|
<div className="columns">
|
||||||
<InputField
|
<div className="column is-half">
|
||||||
label={t("general-settings.default-namespace-strategy")}
|
<InputField
|
||||||
onChange={this.handleDefaultNamespaceStrategyChange}
|
label={t("general-settings.plugin-url")}
|
||||||
value={defaultNamespaceStrategy}
|
onChange={this.handlePluginUrlChange}
|
||||||
disabled={!hasUpdatePermission}
|
value={pluginUrl}
|
||||||
helpText={t("help.defaultNameSpaceStrategyHelpText")}
|
disabled={!hasUpdatePermission}
|
||||||
/>
|
helpText={t("help.pluginRepositoryHelpText")}
|
||||||
<Checkbox
|
/>
|
||||||
checked={enabledXsrfProtection}
|
</div>
|
||||||
label={t("general-settings.enabled-xsrf-protection")}
|
<div className="column is-half">
|
||||||
onChange={this.handleEnabledXsrfProtectionChange}
|
<InputField
|
||||||
disabled={!hasUpdatePermission}
|
label={t("general-settings.default-namespace-strategy")}
|
||||||
helpText={t("help.enableXsrfProtectionHelpText")}
|
onChange={this.handleDefaultNamespaceStrategyChange}
|
||||||
/>
|
value={defaultNamespaceStrategy}
|
||||||
<Checkbox
|
disabled={!hasUpdatePermission}
|
||||||
checked={enableRepositoryArchive}
|
helpText={t("help.defaultNameSpaceStrategyHelpText")}
|
||||||
label={t("general-settings.enable-repository-archive")}
|
/>
|
||||||
onChange={this.handleEnableRepositoryArchiveChange}
|
</div>
|
||||||
disabled={!hasUpdatePermission}
|
</div>
|
||||||
helpText={t("help.enableRepositoryArchiveHelpText")}
|
<div className="columns">
|
||||||
/>
|
<div className="column is-half">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={disableGroupingGrid}
|
checked={enabledXsrfProtection}
|
||||||
label={t("general-settings.disable-grouping-grid")}
|
label={t("general-settings.enabled-xsrf-protection")}
|
||||||
onChange={this.handleDisableGroupingGridChange}
|
onChange={this.handleEnabledXsrfProtectionChange}
|
||||||
disabled={!hasUpdatePermission}
|
disabled={!hasUpdatePermission}
|
||||||
helpText={t("help.disableGroupingGridHelpText")}
|
helpText={t("help.enableXsrfProtectionHelpText")}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
</div>
|
||||||
checked={anonymousAccessEnabled}
|
<div className="column is-half">
|
||||||
label={t("general-settings.anonymous-access-enabled")}
|
<Checkbox
|
||||||
onChange={this.handleAnonymousAccessEnabledChange}
|
checked={enableRepositoryArchive}
|
||||||
disabled={!hasUpdatePermission}
|
label={t("general-settings.enable-repository-archive")}
|
||||||
helpText={t("help.allowAnonymousAccessHelpText")}
|
onChange={this.handleEnableRepositoryArchiveChange}
|
||||||
/>
|
disabled={!hasUpdatePermission}
|
||||||
<Checkbox
|
helpText={t("help.enableRepositoryArchiveHelpText")}
|
||||||
checked={skipFailedAuthenticators}
|
/>
|
||||||
label={t("general-settings.skip-failed-authenticators")}
|
</div>
|
||||||
onChange={this.handleSkipFailedAuthenticatorsChange}
|
</div>
|
||||||
disabled={!hasUpdatePermission}
|
<div className="columns">
|
||||||
helpText={t("help.skipFailedAuthenticatorsHelpText")}
|
<div className="column is-half">
|
||||||
/>
|
<Checkbox
|
||||||
</div>
|
checked={disableGroupingGrid}
|
||||||
|
label={t("general-settings.disable-grouping-grid")}
|
||||||
|
onChange={this.handleDisableGroupingGridChange}
|
||||||
|
disabled={!hasUpdatePermission}
|
||||||
|
helpText={t("help.disableGroupingGridHelpText")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="column is-half">
|
||||||
|
<Checkbox
|
||||||
|
checked={anonymousAccessEnabled}
|
||||||
|
label={t("general-settings.anonymous-access-enabled")}
|
||||||
|
onChange={this.handleAnonymousAccessEnabledChange}
|
||||||
|
disabled={!hasUpdatePermission}
|
||||||
|
helpText={t("help.allowAnonymousAccessHelpText")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="columns">
|
||||||
|
<div className="column is-half">
|
||||||
|
<Checkbox
|
||||||
|
checked={skipFailedAuthenticators}
|
||||||
|
label={t("general-settings.skip-failed-authenticators")}
|
||||||
|
onChange={this.handleSkipFailedAuthenticatorsChange}
|
||||||
|
disabled={!hasUpdatePermission}
|
||||||
|
helpText={t("help.skipFailedAuthenticatorsHelpText")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,24 +40,30 @@ class LoginAttempt extends React.Component<Props, State> {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Subtitle subtitle={t("login-attempt.name")} />
|
<Subtitle subtitle={t("login-attempt.name")} />
|
||||||
<InputField
|
<div className="columns">
|
||||||
label={t("login-attempt.login-attempt-limit")}
|
<div className="column is-half">
|
||||||
onChange={this.handleLoginAttemptLimitChange}
|
<InputField
|
||||||
value={loginAttemptLimit}
|
label={t("login-attempt.login-attempt-limit")}
|
||||||
disabled={!hasUpdatePermission}
|
onChange={this.handleLoginAttemptLimitChange}
|
||||||
validationError={this.state.loginAttemptLimitError}
|
value={loginAttemptLimit}
|
||||||
errorMessage={t("validation.login-attempt-limit-invalid")}
|
disabled={!hasUpdatePermission}
|
||||||
helpText={t("help.loginAttemptLimitHelpText")}
|
validationError={this.state.loginAttemptLimitError}
|
||||||
/>
|
errorMessage={t("validation.login-attempt-limit-invalid")}
|
||||||
<InputField
|
helpText={t("help.loginAttemptLimitHelpText")}
|
||||||
label={t("login-attempt.login-attempt-limit-timeout")}
|
/>
|
||||||
onChange={this.handleLoginAttemptLimitTimeoutChange}
|
</div>
|
||||||
value={loginAttemptLimitTimeout}
|
<div className="column is-half">
|
||||||
disabled={!hasUpdatePermission}
|
<InputField
|
||||||
validationError={this.state.loginAttemptLimitTimeoutError}
|
label={t("login-attempt.login-attempt-limit-timeout")}
|
||||||
errorMessage={t("validation.login-attempt-limit-timeout-invalid")}
|
onChange={this.handleLoginAttemptLimitTimeoutChange}
|
||||||
helpText={t("help.loginAttemptLimitTimeoutHelpText")}
|
value={loginAttemptLimitTimeout}
|
||||||
/>
|
disabled={!hasUpdatePermission}
|
||||||
|
validationError={this.state.loginAttemptLimitTimeoutError}
|
||||||
|
errorMessage={t("validation.login-attempt-limit-timeout-invalid")}
|
||||||
|
helpText={t("help.loginAttemptLimitTimeoutHelpText")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,56 +37,76 @@ class ProxySettings extends React.Component<Props> {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Subtitle subtitle={t("proxy-settings.name")} />
|
<Subtitle subtitle={t("proxy-settings.name")} />
|
||||||
<Checkbox
|
<div className="columns">
|
||||||
checked={enableProxy}
|
<div className="column is-full">
|
||||||
label={t("proxy-settings.enable-proxy")}
|
<Checkbox
|
||||||
onChange={this.handleEnableProxyChange}
|
checked={enableProxy}
|
||||||
disabled={!hasUpdatePermission}
|
label={t("proxy-settings.enable-proxy")}
|
||||||
helpText={t("help.enableProxyHelpText")}
|
onChange={this.handleEnableProxyChange}
|
||||||
/>
|
disabled={!hasUpdatePermission}
|
||||||
<InputField
|
helpText={t("help.enableProxyHelpText")}
|
||||||
label={t("proxy-settings.proxy-password")}
|
/>
|
||||||
onChange={this.handleProxyPasswordChange}
|
</div>
|
||||||
value={proxyPassword}
|
</div>
|
||||||
type="password"
|
<div className="columns">
|
||||||
disabled={!enableProxy || !hasUpdatePermission}
|
<div className="column is-half">
|
||||||
helpText={t("help.proxyPasswordHelpText")}
|
<InputField
|
||||||
/>
|
label={t("proxy-settings.proxy-password")}
|
||||||
<InputField
|
onChange={this.handleProxyPasswordChange}
|
||||||
label={t("proxy-settings.proxy-port")}
|
value={proxyPassword}
|
||||||
value={proxyPort}
|
type="password"
|
||||||
onChange={this.handleProxyPortChange}
|
disabled={!enableProxy || !hasUpdatePermission}
|
||||||
disabled={!enableProxy || !hasUpdatePermission}
|
helpText={t("help.proxyPasswordHelpText")}
|
||||||
helpText={t("help.proxyPortHelpText")}
|
/>
|
||||||
/>
|
</div>
|
||||||
<InputField
|
<div className="column is-half">
|
||||||
label={t("proxy-settings.proxy-server")}
|
<InputField
|
||||||
value={proxyServer}
|
label={t("proxy-settings.proxy-port")}
|
||||||
onChange={this.handleProxyServerChange}
|
value={proxyPort}
|
||||||
disabled={!enableProxy || !hasUpdatePermission}
|
onChange={this.handleProxyPortChange}
|
||||||
helpText={t("help.proxyServerHelpText")}
|
disabled={!enableProxy || !hasUpdatePermission}
|
||||||
/>
|
helpText={t("help.proxyPortHelpText")}
|
||||||
<InputField
|
/>
|
||||||
label={t("proxy-settings.proxy-user")}
|
</div>
|
||||||
value={proxyUser}
|
</div>
|
||||||
onChange={this.handleProxyUserChange}
|
<div className="columns">
|
||||||
disabled={!enableProxy || !hasUpdatePermission}
|
<div className="column is-half">
|
||||||
helpText={t("help.proxyUserHelpText")}
|
<InputField
|
||||||
/>
|
label={t("proxy-settings.proxy-server")}
|
||||||
<ProxyExcludesTable
|
value={proxyServer}
|
||||||
proxyExcludes={proxyExcludes}
|
onChange={this.handleProxyServerChange}
|
||||||
onChange={(isValid, changedValue, name) =>
|
disabled={!enableProxy || !hasUpdatePermission}
|
||||||
this.props.onChange(isValid, changedValue, name)
|
helpText={t("help.proxyServerHelpText")}
|
||||||
}
|
/>
|
||||||
disabled={!enableProxy || !hasUpdatePermission}
|
</div>
|
||||||
/>
|
<div className="column is-half">
|
||||||
<AddEntryToTableField
|
<InputField
|
||||||
addEntry={this.addProxyExclude}
|
label={t("proxy-settings.proxy-user")}
|
||||||
disabled={!enableProxy || !hasUpdatePermission}
|
value={proxyUser}
|
||||||
buttonLabel={t("proxy-settings.add-proxy-exclude-button")}
|
onChange={this.handleProxyUserChange}
|
||||||
fieldLabel={t("proxy-settings.add-proxy-exclude-textfield")}
|
disabled={!enableProxy || !hasUpdatePermission}
|
||||||
errorMessage={t("proxy-settings.add-proxy-exclude-error")}
|
helpText={t("help.proxyUserHelpText")}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="columns">
|
||||||
|
<div className="column is-full">
|
||||||
|
<ProxyExcludesTable
|
||||||
|
proxyExcludes={proxyExcludes}
|
||||||
|
onChange={(isValid, changedValue, name) =>
|
||||||
|
this.props.onChange(isValid, changedValue, name)
|
||||||
|
}
|
||||||
|
disabled={!enableProxy || !hasUpdatePermission}
|
||||||
|
/>
|
||||||
|
<AddEntryToTableField
|
||||||
|
addEntry={this.addProxyExclude}
|
||||||
|
disabled={!enableProxy || !hasUpdatePermission}
|
||||||
|
buttonLabel={t("proxy-settings.add-proxy-exclude-button")}
|
||||||
|
fieldLabel={t("proxy-settings.add-proxy-exclude-textfield")}
|
||||||
|
errorMessage={t("proxy-settings.add-proxy-exclude-error")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,86 +1,86 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import { Route } from "react-router";
|
import { Route } from "react-router";
|
||||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
|
|
||||||
import type { Links } from "@scm-manager/ui-types";
|
import type { Links } from "@scm-manager/ui-types";
|
||||||
import { Page, Navigation, NavLink, Section } from "@scm-manager/ui-components";
|
import { Page, Navigation, NavLink, Section } from "@scm-manager/ui-components";
|
||||||
import GlobalConfig from "./GlobalConfig";
|
import GlobalConfig from "./GlobalConfig";
|
||||||
import type { History } from "history";
|
import type { History } from "history";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {compose} from "redux";
|
import {compose} from "redux";
|
||||||
import { getLinks } from "../../modules/indexResource";
|
import { getLinks } from "../../modules/indexResource";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
links: Links,
|
links: Links,
|
||||||
|
|
||||||
// context objects
|
// context objects
|
||||||
t: string => string,
|
t: string => string,
|
||||||
match: any,
|
match: any,
|
||||||
history: History
|
history: History
|
||||||
};
|
};
|
||||||
|
|
||||||
class Config extends React.Component<Props> {
|
class Config extends React.Component<Props> {
|
||||||
stripEndingSlash = (url: string) => {
|
stripEndingSlash = (url: string) => {
|
||||||
if (url.endsWith("/")) {
|
if (url.endsWith("/")) {
|
||||||
return url.substring(0, url.length - 2);
|
return url.substring(0, url.length - 2);
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
};
|
};
|
||||||
|
|
||||||
matchedUrl = () => {
|
matchedUrl = () => {
|
||||||
return this.stripEndingSlash(this.props.match.url);
|
return this.stripEndingSlash(this.props.match.url);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { links, t } = this.props;
|
const { links, t } = this.props;
|
||||||
|
|
||||||
const url = this.matchedUrl();
|
const url = this.matchedUrl();
|
||||||
const extensionProps = {
|
const extensionProps = {
|
||||||
links,
|
links,
|
||||||
url
|
url
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<div className="columns">
|
<div className="columns">
|
||||||
<div className="column is-three-quarters">
|
<div className="column is-three-quarters">
|
||||||
<Route path={url} exact component={GlobalConfig} />
|
<Route path={url} exact component={GlobalConfig} />
|
||||||
<ExtensionPoint name="config.route"
|
<ExtensionPoint name="config.route"
|
||||||
props={extensionProps}
|
props={extensionProps}
|
||||||
renderAll={true}
|
renderAll={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="column">
|
<div className="column is-one-quarter">
|
||||||
<Navigation>
|
<Navigation>
|
||||||
<Section label={t("config.navigation-title")}>
|
<Section label={t("config.navigation-title")}>
|
||||||
<NavLink
|
<NavLink
|
||||||
to={`${url}`}
|
to={`${url}`}
|
||||||
label={t("global-config.navigation-label")}
|
label={t("global-config.navigation-label")}
|
||||||
/>
|
/>
|
||||||
<ExtensionPoint name="config.navigation"
|
<ExtensionPoint name="config.navigation"
|
||||||
props={extensionProps}
|
props={extensionProps}
|
||||||
renderAll={true}
|
renderAll={true}
|
||||||
/>
|
/>
|
||||||
</Section>
|
</Section>
|
||||||
</Navigation>
|
</Navigation>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state: any) => {
|
const mapStateToProps = (state: any) => {
|
||||||
const links = getLinks(state);
|
const links = getLinks(state);
|
||||||
return {
|
return {
|
||||||
links
|
links
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
connect(mapStateToProps),
|
connect(mapStateToProps),
|
||||||
translate("config")
|
translate("config")
|
||||||
)(Config);
|
)(Config);
|
||||||
|
|
||||||
|
|||||||
@@ -1,53 +1,53 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { Me } from "@scm-manager/ui-types";
|
import type { Me } from "@scm-manager/ui-types";
|
||||||
import { MailLink, AvatarWrapper, AvatarImage } from "@scm-manager/ui-components";
|
import { MailLink, AvatarWrapper, AvatarImage } from "@scm-manager/ui-components";
|
||||||
import { compose } from "redux";
|
import { compose } from "redux";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
me: Me,
|
me: Me,
|
||||||
|
|
||||||
// Context props
|
// Context props
|
||||||
t: string => string
|
t: string => string
|
||||||
};
|
};
|
||||||
type State = {};
|
type State = {};
|
||||||
|
|
||||||
class ProfileInfo extends React.Component<Props, State> {
|
class ProfileInfo extends React.Component<Props, State> {
|
||||||
render() {
|
render() {
|
||||||
const { me, t } = this.props;
|
const { me, t } = this.props;
|
||||||
return (
|
return (
|
||||||
<div className="media">
|
<div className="media">
|
||||||
<AvatarWrapper>
|
<AvatarWrapper>
|
||||||
<figure className="media-left">
|
<figure className="media-left">
|
||||||
<p className="image is-64x64">
|
<p className="image is-64x64">
|
||||||
<AvatarImage person={ me }/>
|
<AvatarImage person={ me }/>
|
||||||
</p>
|
</p>
|
||||||
</figure>
|
</figure>
|
||||||
</AvatarWrapper>
|
</AvatarWrapper>
|
||||||
<div className="media-content">
|
<div className="media-content">
|
||||||
<table className="table">
|
<table className="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("profile.username")}</td>
|
<td className="has-text-weight-semibold">{t("profile.username")}</td>
|
||||||
<td>{me.name}</td>
|
<td>{me.name}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("profile.displayName")}</td>
|
<td className="has-text-weight-semibold">{t("profile.displayName")}</td>
|
||||||
<td>{me.displayName}</td>
|
<td>{me.displayName}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("profile.mail")}</td>
|
<td className="has-text-weight-semibold">{t("profile.mail")}</td>
|
||||||
<td>
|
<td>
|
||||||
<MailLink address={me.mail} />
|
<MailLink address={me.mail} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(translate("commons"))(ProfileInfo);
|
export default compose(translate("commons"))(ProfileInfo);
|
||||||
|
|||||||
@@ -1,69 +1,69 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { Group } from "@scm-manager/ui-types";
|
import type { Group } from "@scm-manager/ui-types";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import GroupMember from "./GroupMember";
|
import GroupMember from "./GroupMember";
|
||||||
import { DateFromNow } from "@scm-manager/ui-components";
|
import { DateFromNow } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
group: Group,
|
group: Group,
|
||||||
t: string => string
|
t: string => string
|
||||||
};
|
};
|
||||||
|
|
||||||
class Details extends React.Component<Props> {
|
class Details extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { group, t } = this.props;
|
const { group, t } = this.props;
|
||||||
return (
|
return (
|
||||||
<table className="table content">
|
<table className="table content">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("group.name")}</td>
|
<td className="has-text-weight-semibold">{t("group.name")}</td>
|
||||||
<td>{group.name}</td>
|
<td>{group.name}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("group.description")}</td>
|
<td className="has-text-weight-semibold">{t("group.description")}</td>
|
||||||
<td>{group.description}</td>
|
<td>{group.description}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("group.type")}</td>
|
<td className="has-text-weight-semibold">{t("group.type")}</td>
|
||||||
<td>{group.type}</td>
|
<td>{group.type}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("group.creationDate")}</td>
|
<td className="has-text-weight-semibold">{t("group.creationDate")}</td>
|
||||||
<td>
|
<td>
|
||||||
<DateFromNow date={group.creationDate} />
|
<DateFromNow date={group.creationDate} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("group.lastModified")}</td>
|
<td className="has-text-weight-semibold">{t("group.lastModified")}</td>
|
||||||
<td>
|
<td>
|
||||||
<DateFromNow date={group.lastModified} />
|
<DateFromNow date={group.lastModified} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{this.renderMembers()}
|
{this.renderMembers()}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderMembers() {
|
renderMembers() {
|
||||||
if (this.props.group.members.length > 0) {
|
if (this.props.group.members.length > 0) {
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
{this.props.t("group.members")}
|
{this.props.t("group.members")}
|
||||||
<ul>
|
<ul>
|
||||||
{this.props.group._embedded.members.map((member, index) => {
|
{this.props.group._embedded.members.map((member, index) => {
|
||||||
return <GroupMember key={index} member={member} />;
|
return <GroupMember key={index} member={member} />;
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translate("groups")(Details);
|
export default translate("groups")(Details);
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import type { Group } from "@scm-manager/ui-types";
|
import type { Group } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
group: Group
|
group: Group
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class GroupRow extends React.Component<Props> {
|
export default class GroupRow extends React.Component<Props> {
|
||||||
renderLink(to: string, label: string) {
|
renderLink(to: string, label: string) {
|
||||||
return <Link to={to}>{label}</Link>;
|
return <Link to={to}>{label}</Link>;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { group } = this.props;
|
const { group } = this.props;
|
||||||
const to = `/group/${group.name}`;
|
const to = `/group/${group.name}`;
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
<td>{this.renderLink(to, group.name)}</td>
|
<td>{this.renderLink(to, group.name)}</td>
|
||||||
<td className="is-hidden-mobile">{group.description}</td>
|
<td className="is-hidden-mobile">{group.description}</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import GroupRow from "./GroupRow";
|
import GroupRow from "./GroupRow";
|
||||||
import type { Group } from "@scm-manager/ui-types";
|
import type { Group } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
t: string => string,
|
t: string => string,
|
||||||
groups: Group[]
|
groups: Group[]
|
||||||
};
|
};
|
||||||
|
|
||||||
class GroupTable extends React.Component<Props> {
|
class GroupTable extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { groups, t } = this.props;
|
const { groups, t } = this.props;
|
||||||
return (
|
return (
|
||||||
<table className="table is-hoverable is-fullwidth">
|
<table className="card-table table is-hoverable is-fullwidth">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{t("group.name")}</th>
|
<th>{t("group.name")}</th>
|
||||||
<th className="is-hidden-mobile">{t("group.description")}</th>
|
<th className="is-hidden-mobile">{t("group.description")}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{groups.map((group, index) => {
|
{groups.map((group, index) => {
|
||||||
return <GroupRow key={index} group={group} />;
|
return <GroupRow key={index} group={group} />;
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translate("groups")(GroupTable);
|
export default translate("groups")(GroupTable);
|
||||||
|
|||||||
@@ -1,55 +1,55 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { Repository } from "@scm-manager/ui-types";
|
import type { Repository } from "@scm-manager/ui-types";
|
||||||
import { MailLink, DateFromNow } from "@scm-manager/ui-components";
|
import { MailLink, DateFromNow } from "@scm-manager/ui-components";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
repository: Repository,
|
repository: Repository,
|
||||||
// context props
|
// context props
|
||||||
t: string => string
|
t: string => string
|
||||||
};
|
};
|
||||||
|
|
||||||
class RepositoryDetailTable extends React.Component<Props> {
|
class RepositoryDetailTable extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { repository, t } = this.props;
|
const { repository, t } = this.props;
|
||||||
return (
|
return (
|
||||||
<table className="table">
|
<table className="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("repository.name")}</td>
|
<td className="has-text-weight-semibold">{t("repository.name")}</td>
|
||||||
<td>{repository.name}</td>
|
<td>{repository.name}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("repository.type")}</td>
|
<td className="has-text-weight-semibold">{t("repository.type")}</td>
|
||||||
<td>{repository.type}</td>
|
<td>{repository.type}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("repository.contact")}</td>
|
<td className="has-text-weight-semibold">{t("repository.contact")}</td>
|
||||||
<td>
|
<td>
|
||||||
<MailLink address={repository.contact} />
|
<MailLink address={repository.contact} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("repository.description")}</td>
|
<td className="has-text-weight-semibold">{t("repository.description")}</td>
|
||||||
<td>{repository.description}</td>
|
<td>{repository.description}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("repository.creationDate")}</td>
|
<td className="has-text-weight-semibold">{t("repository.creationDate")}</td>
|
||||||
<td>
|
<td>
|
||||||
<DateFromNow date={repository.creationDate} />
|
<DateFromNow date={repository.creationDate} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("repository.lastModified")}</td>
|
<td className="has-text-weight-semibold">{t("repository.lastModified")}</td>
|
||||||
<td>
|
<td>
|
||||||
<DateFromNow date={repository.lastModified} />
|
<DateFromNow date={repository.lastModified} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translate("repos")(RepositoryDetailTable);
|
export default translate("repos")(RepositoryDetailTable);
|
||||||
|
|||||||
@@ -1,29 +1,30 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { Repository } from "@scm-manager/ui-types";
|
import type { Repository } from "@scm-manager/ui-types";
|
||||||
import RepositoryDetailTable from "./RepositoryDetailTable";
|
import RepositoryDetailTable from "./RepositoryDetailTable";
|
||||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
repository: Repository
|
repository: Repository
|
||||||
};
|
};
|
||||||
|
|
||||||
class RepositoryDetails extends React.Component<Props> {
|
class RepositoryDetails extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { repository } = this.props;
|
const { repository } = this.props;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<RepositoryDetailTable repository={repository} />
|
<RepositoryDetailTable repository={repository} />
|
||||||
<div className="content">
|
<hr />
|
||||||
<ExtensionPoint
|
<div className="content">
|
||||||
name="repos.repository-details.information"
|
<ExtensionPoint
|
||||||
renderAll={true}
|
name="repos.repository-details.information"
|
||||||
props={{ repository }}
|
renderAll={true}
|
||||||
/>
|
props={{ repository }}
|
||||||
</div>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
export default RepositoryDetails;
|
|
||||||
|
export default RepositoryDetails;
|
||||||
|
|||||||
@@ -9,15 +9,10 @@ import classNames from "classnames";
|
|||||||
import RepositoryAvatar from "./RepositoryAvatar";
|
import RepositoryAvatar from "./RepositoryAvatar";
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
outer: {
|
|
||||||
position: "relative"
|
|
||||||
},
|
|
||||||
overlay: {
|
overlay: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
left: 0,
|
height: "calc(120px - 1.5rem)",
|
||||||
top: 0,
|
width: "calc(50% - 3rem)"
|
||||||
bottom: 0,
|
|
||||||
right: 0
|
|
||||||
},
|
},
|
||||||
inner: {
|
inner: {
|
||||||
position: "relative",
|
position: "relative",
|
||||||
@@ -26,11 +21,16 @@ const styles = {
|
|||||||
},
|
},
|
||||||
innerLink: {
|
innerLink: {
|
||||||
pointerEvents: "all"
|
pointerEvents: "all"
|
||||||
|
},
|
||||||
|
centerImage: {
|
||||||
|
marginTop: "0.8em",
|
||||||
|
marginLeft: "1em !important"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
repository: Repository,
|
repository: Repository,
|
||||||
|
fullColumnWidth?: boolean,
|
||||||
// context props
|
// context props
|
||||||
classes: any
|
classes: any
|
||||||
};
|
};
|
||||||
@@ -44,7 +44,7 @@ class RepositoryEntry extends React.Component<Props> {
|
|||||||
if (repository._links["changesets"]) {
|
if (repository._links["changesets"]) {
|
||||||
return (
|
return (
|
||||||
<RepositoryEntryLink
|
<RepositoryEntryLink
|
||||||
iconClass="fa-code-branch"
|
iconClass="fa-code-branch fa-lg"
|
||||||
to={repositoryLink + "/changesets"}
|
to={repositoryLink + "/changesets"}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -56,7 +56,7 @@ class RepositoryEntry extends React.Component<Props> {
|
|||||||
if (repository._links["sources"]) {
|
if (repository._links["sources"]) {
|
||||||
return (
|
return (
|
||||||
<RepositoryEntryLink
|
<RepositoryEntryLink
|
||||||
iconClass="fa-code"
|
iconClass="fa-code fa-lg"
|
||||||
to={repositoryLink + "/sources"}
|
to={repositoryLink + "/sources"}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -67,29 +67,40 @@ class RepositoryEntry extends React.Component<Props> {
|
|||||||
renderModifyLink = (repository: Repository, repositoryLink: string) => {
|
renderModifyLink = (repository: Repository, repositoryLink: string) => {
|
||||||
if (repository._links["update"]) {
|
if (repository._links["update"]) {
|
||||||
return (
|
return (
|
||||||
<RepositoryEntryLink iconClass="fa-cog" to={repositoryLink + "/edit"} />
|
<RepositoryEntryLink
|
||||||
|
iconClass="fa-cog fa-lg"
|
||||||
|
to={repositoryLink + "/edit"}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { repository, classes } = this.props;
|
const { repository, classes, fullColumnWidth } = this.props;
|
||||||
const repositoryLink = this.createLink(repository);
|
const repositoryLink = this.createLink(repository);
|
||||||
|
const halfColumn = fullColumnWidth ? "is-full" : "is-half";
|
||||||
return (
|
return (
|
||||||
<div className={classNames("box", "box-link-shadow", classes.outer)}>
|
<div
|
||||||
<Link className={classes.overlay} to={repositoryLink} />
|
className={classNames(
|
||||||
|
"box",
|
||||||
|
"box-link-shadow",
|
||||||
|
"column",
|
||||||
|
"is-clipped",
|
||||||
|
halfColumn
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Link className={classNames(classes.overlay)} to={repositoryLink} />
|
||||||
<article className={classNames("media", classes.inner)}>
|
<article className={classNames("media", classes.inner)}>
|
||||||
<figure className="media-left">
|
<figure className={classNames(classes.centerImage, "media-left")}>
|
||||||
<RepositoryAvatar repository={repository} />
|
<RepositoryAvatar repository={repository} />
|
||||||
</figure>
|
</figure>
|
||||||
<div className="media-content">
|
<div className="media-content">
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<p>
|
<p className="is-marginless">
|
||||||
<strong>{repository.name}</strong>
|
<strong>{repository.name}</strong>
|
||||||
<br />
|
|
||||||
{repository.description}
|
|
||||||
</p>
|
</p>
|
||||||
|
<p className={"shorten-text"}>{repository.description}</p>
|
||||||
</div>
|
</div>
|
||||||
<nav className="level is-mobile">
|
<nav className="level is-mobile">
|
||||||
<div className="level-left">
|
<div className="level-left">
|
||||||
|
|||||||
@@ -1,34 +1,35 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import injectSheet from "react-jss";
|
import injectSheet from "react-jss";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
link: {
|
link: {
|
||||||
pointerEvents: "all"
|
pointerEvents: "all",
|
||||||
}
|
marginRight: "1.25rem !important"
|
||||||
};
|
}
|
||||||
|
};
|
||||||
type Props = {
|
|
||||||
to: string,
|
type Props = {
|
||||||
iconClass: string,
|
to: string,
|
||||||
|
iconClass: string,
|
||||||
// context props
|
|
||||||
classes: any
|
// context props
|
||||||
};
|
classes: any
|
||||||
|
};
|
||||||
class RepositoryEntryLink extends React.Component<Props> {
|
|
||||||
render() {
|
class RepositoryEntryLink extends React.Component<Props> {
|
||||||
const { to, iconClass, classes } = this.props;
|
render() {
|
||||||
return (
|
const { to, iconClass, classes } = this.props;
|
||||||
<Link className={classNames("level-item", classes.link)} to={to}>
|
return (
|
||||||
<span className="icon is-small">
|
<Link className={classNames("level-item", classes.link)} to={to}>
|
||||||
<i className={classNames("fa", iconClass)} />
|
<span className="icon is-small">
|
||||||
</span>
|
<i className={classNames("fa", iconClass)} />
|
||||||
</Link>
|
</span>
|
||||||
);
|
</Link>
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
export default injectSheet(styles)(RepositoryEntryLink);
|
|
||||||
|
export default injectSheet(styles)(RepositoryEntryLink);
|
||||||
|
|||||||
@@ -1,16 +1,23 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { RepositoryGroup } from "@scm-manager/ui-types";
|
import type { RepositoryGroup, Repository } from "@scm-manager/ui-types";
|
||||||
import injectSheet from "react-jss";
|
import injectSheet from "react-jss";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import RepositoryEntry from "./RepositoryEntry";
|
import RepositoryEntry from "./RepositoryEntry";
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
pointer: {
|
pointer: {
|
||||||
cursor: "pointer"
|
cursor: "pointer",
|
||||||
|
fontSize: "1.5rem"
|
||||||
},
|
},
|
||||||
repoGroup: {
|
repoGroup: {
|
||||||
marginBottom: "1em"
|
marginBottom: "1em"
|
||||||
|
},
|
||||||
|
wrapper: {
|
||||||
|
padding: "0 0.75rem"
|
||||||
|
},
|
||||||
|
clearfix: {
|
||||||
|
clear: "both"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,6 +46,18 @@ class RepositoryGroupEntry extends React.Component<Props, State> {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
isLastEntry = (array: Repository[], index: number) => {
|
||||||
|
return index === array.length - 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
isLengthOdd = (array: Repository[]) => {
|
||||||
|
return array.length % 2 !== 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
isFullSize = (array: Repository[], index: number) => {
|
||||||
|
return this.isLastEntry(array, index) && this.isLengthOdd(array);
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { group, classes } = this.props;
|
const { group, classes } = this.props;
|
||||||
const { collapsed } = this.state;
|
const { collapsed } = this.state;
|
||||||
@@ -47,7 +66,10 @@ class RepositoryGroupEntry extends React.Component<Props, State> {
|
|||||||
let content = null;
|
let content = null;
|
||||||
if (!collapsed) {
|
if (!collapsed) {
|
||||||
content = group.repositories.map((repository, index) => {
|
content = group.repositories.map((repository, index) => {
|
||||||
return <RepositoryEntry repository={repository} key={index} />;
|
const fullColumnWidth = this.isFullSize(group.repositories, index);
|
||||||
|
return (
|
||||||
|
<RepositoryEntry repository={repository} fullColumnWidth={fullColumnWidth} key={index} />
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
@@ -58,7 +80,10 @@ class RepositoryGroupEntry extends React.Component<Props, State> {
|
|||||||
</span>
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
<hr />
|
<hr />
|
||||||
{content}
|
<div className={classNames("columns", "is-multiline", classes.wrapper)}>
|
||||||
|
{content}
|
||||||
|
</div>
|
||||||
|
<div className={classes.clearfix} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<hr />
|
||||||
<h2 className="subtitle">
|
<h2 className="subtitle">
|
||||||
{t("permission.add-permission.add-permission-heading")}
|
{t("permission.add-permission.add-permission-heading")}
|
||||||
</h2>
|
</h2>
|
||||||
@@ -153,19 +154,29 @@ class CreatePermissionForm extends React.Component<Props, State> {
|
|||||||
{t("permission.group-permission")}
|
{t("permission.group-permission")}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{this.renderAutocompletionField()}
|
|
||||||
|
|
||||||
<TypeSelector
|
<div className="columns">
|
||||||
label={t("permission.type")}
|
<div className="column is-three-quarters">
|
||||||
helpText={t("permission.help.typeHelpText")}
|
{this.renderAutocompletionField()}
|
||||||
handleTypeChange={this.handleTypeChange}
|
</div>
|
||||||
type={type ? type : "READ"}
|
<div className="column is-one-quarter">
|
||||||
/>
|
<TypeSelector
|
||||||
<SubmitButton
|
label={t("permission.type")}
|
||||||
label={t("permission.add-permission.submit-button")}
|
helpText={t("permission.help.typeHelpText")}
|
||||||
loading={loading}
|
handleTypeChange={this.handleTypeChange}
|
||||||
disabled={!this.state.valid || this.state.name === ""}
|
type={type ? type : "READ"}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="columns">
|
||||||
|
<div className="column">
|
||||||
|
<SubmitButton
|
||||||
|
label={t("permission.add-permission.submit-button")}
|
||||||
|
loading={loading}
|
||||||
|
disabled={!this.state.valid || this.state.name === ""}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import { Select } from "@scm-manager/ui-components";
|
import { Select } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
t: string => string,
|
t: string => string,
|
||||||
handleTypeChange: string => void,
|
handleTypeChange: string => void,
|
||||||
type: string,
|
type: string,
|
||||||
label?: string,
|
label?: string,
|
||||||
helpText?: string,
|
helpText?: string,
|
||||||
loading?: boolean
|
loading?: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
class TypeSelector extends React.Component<Props> {
|
class TypeSelector extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { type, handleTypeChange, loading, label, helpText } = this.props;
|
const { type, handleTypeChange, loading, label, helpText } = this.props;
|
||||||
const types = ["READ", "OWNER", "WRITE"];
|
const types = ["READ", "OWNER", "WRITE"];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
onChange={handleTypeChange}
|
onChange={handleTypeChange}
|
||||||
value={type ? type : "READ"}
|
value={type ? type : "READ"}
|
||||||
options={this.createSelectOptions(types)}
|
options={this.createSelectOptions(types)}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
label={label}
|
label={label}
|
||||||
helpText={helpText}
|
helpText={helpText}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
createSelectOptions(types: string[]) {
|
createSelectOptions(types: string[]) {
|
||||||
return types.map(type => {
|
return types.map(type => {
|
||||||
return {
|
return {
|
||||||
label: type,
|
label: type,
|
||||||
value: type
|
value: type
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translate("repos")(TypeSelector);
|
export default translate("repos")(TypeSelector);
|
||||||
|
|||||||
@@ -1,225 +1,225 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import {
|
import {
|
||||||
fetchPermissions,
|
fetchPermissions,
|
||||||
getFetchPermissionsFailure,
|
getFetchPermissionsFailure,
|
||||||
isFetchPermissionsPending,
|
isFetchPermissionsPending,
|
||||||
getPermissionsOfRepo,
|
getPermissionsOfRepo,
|
||||||
hasCreatePermission,
|
hasCreatePermission,
|
||||||
createPermission,
|
createPermission,
|
||||||
isCreatePermissionPending,
|
isCreatePermissionPending,
|
||||||
getCreatePermissionFailure,
|
getCreatePermissionFailure,
|
||||||
createPermissionReset,
|
createPermissionReset,
|
||||||
getDeletePermissionsFailure,
|
getDeletePermissionsFailure,
|
||||||
getModifyPermissionsFailure,
|
getModifyPermissionsFailure,
|
||||||
modifyPermissionReset,
|
modifyPermissionReset,
|
||||||
deletePermissionReset
|
deletePermissionReset
|
||||||
} from "../modules/permissions";
|
} from "../modules/permissions";
|
||||||
import { Loading, ErrorPage } from "@scm-manager/ui-components";
|
import { Loading, ErrorPage } from "@scm-manager/ui-components";
|
||||||
import type {
|
import type {
|
||||||
Permission,
|
Permission,
|
||||||
PermissionCollection,
|
PermissionCollection,
|
||||||
PermissionCreateEntry
|
PermissionCreateEntry
|
||||||
} from "@scm-manager/ui-types";
|
} from "@scm-manager/ui-types";
|
||||||
import SinglePermission from "./SinglePermission";
|
import SinglePermission from "./SinglePermission";
|
||||||
import CreatePermissionForm from "../components/CreatePermissionForm";
|
import CreatePermissionForm from "../components/CreatePermissionForm";
|
||||||
import type { History } from "history";
|
import type { History } from "history";
|
||||||
import { getPermissionsLink } from "../../modules/repos";
|
import { getPermissionsLink } from "../../modules/repos";
|
||||||
import {
|
import {
|
||||||
getGroupAutoCompleteLink,
|
getGroupAutoCompleteLink,
|
||||||
getUserAutoCompleteLink
|
getUserAutoCompleteLink
|
||||||
} from "../../../modules/indexResource";
|
} from "../../../modules/indexResource";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
namespace: string,
|
namespace: string,
|
||||||
repoName: string,
|
repoName: string,
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
error: Error,
|
error: Error,
|
||||||
permissions: PermissionCollection,
|
permissions: PermissionCollection,
|
||||||
hasPermissionToCreate: boolean,
|
hasPermissionToCreate: boolean,
|
||||||
loadingCreatePermission: boolean,
|
loadingCreatePermission: boolean,
|
||||||
permissionsLink: string,
|
permissionsLink: string,
|
||||||
groupAutoCompleteLink: string,
|
groupAutoCompleteLink: string,
|
||||||
userAutoCompleteLink: string,
|
userAutoCompleteLink: string,
|
||||||
|
|
||||||
//dispatch functions
|
//dispatch functions
|
||||||
fetchPermissions: (link: string, namespace: string, repoName: string) => void,
|
fetchPermissions: (link: string, namespace: string, repoName: string) => void,
|
||||||
createPermission: (
|
createPermission: (
|
||||||
link: string,
|
link: string,
|
||||||
permission: PermissionCreateEntry,
|
permission: PermissionCreateEntry,
|
||||||
namespace: string,
|
namespace: string,
|
||||||
repoName: string,
|
repoName: string,
|
||||||
callback?: () => void
|
callback?: () => void
|
||||||
) => void,
|
) => void,
|
||||||
createPermissionReset: (string, string) => void,
|
createPermissionReset: (string, string) => void,
|
||||||
modifyPermissionReset: (string, string) => void,
|
modifyPermissionReset: (string, string) => void,
|
||||||
deletePermissionReset: (string, string) => void,
|
deletePermissionReset: (string, string) => void,
|
||||||
// context props
|
// context props
|
||||||
t: string => string,
|
t: string => string,
|
||||||
match: any,
|
match: any,
|
||||||
history: History
|
history: History
|
||||||
};
|
};
|
||||||
|
|
||||||
class Permissions extends React.Component<Props> {
|
class Permissions extends React.Component<Props> {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const {
|
const {
|
||||||
fetchPermissions,
|
fetchPermissions,
|
||||||
namespace,
|
namespace,
|
||||||
repoName,
|
repoName,
|
||||||
modifyPermissionReset,
|
modifyPermissionReset,
|
||||||
createPermissionReset,
|
createPermissionReset,
|
||||||
deletePermissionReset,
|
deletePermissionReset,
|
||||||
permissionsLink
|
permissionsLink
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
createPermissionReset(namespace, repoName);
|
createPermissionReset(namespace, repoName);
|
||||||
modifyPermissionReset(namespace, repoName);
|
modifyPermissionReset(namespace, repoName);
|
||||||
deletePermissionReset(namespace, repoName);
|
deletePermissionReset(namespace, repoName);
|
||||||
fetchPermissions(permissionsLink, namespace, repoName);
|
fetchPermissions(permissionsLink, namespace, repoName);
|
||||||
}
|
}
|
||||||
|
|
||||||
createPermission = (permission: Permission) => {
|
createPermission = (permission: Permission) => {
|
||||||
this.props.createPermission(
|
this.props.createPermission(
|
||||||
this.props.permissionsLink,
|
this.props.permissionsLink,
|
||||||
permission,
|
permission,
|
||||||
this.props.namespace,
|
this.props.namespace,
|
||||||
this.props.repoName
|
this.props.repoName
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
permissions,
|
permissions,
|
||||||
t,
|
t,
|
||||||
namespace,
|
namespace,
|
||||||
repoName,
|
repoName,
|
||||||
loadingCreatePermission,
|
loadingCreatePermission,
|
||||||
hasPermissionToCreate,
|
hasPermissionToCreate,
|
||||||
userAutoCompleteLink,
|
userAutoCompleteLink,
|
||||||
groupAutoCompleteLink
|
groupAutoCompleteLink
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<ErrorPage
|
<ErrorPage
|
||||||
title={t("permission.error-title")}
|
title={t("permission.error-title")}
|
||||||
subtitle={t("permission.error-subtitle")}
|
subtitle={t("permission.error-subtitle")}
|
||||||
error={error}
|
error={error}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loading || !permissions) {
|
if (loading || !permissions) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createPermissionForm = hasPermissionToCreate ? (
|
const createPermissionForm = hasPermissionToCreate ? (
|
||||||
<CreatePermissionForm
|
<CreatePermissionForm
|
||||||
createPermission={permission => this.createPermission(permission)}
|
createPermission={permission => this.createPermission(permission)}
|
||||||
loading={loadingCreatePermission}
|
loading={loadingCreatePermission}
|
||||||
currentPermissions={permissions}
|
currentPermissions={permissions}
|
||||||
userAutoCompleteLink={userAutoCompleteLink}
|
userAutoCompleteLink={userAutoCompleteLink}
|
||||||
groupAutoCompleteLink={groupAutoCompleteLink}
|
groupAutoCompleteLink={groupAutoCompleteLink}
|
||||||
/>
|
/>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<table className="table is-hoverable is-fullwidth">
|
<table className="has-background-light table is-hoverable is-fullwidth">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{t("permission.name")}</th>
|
<th>{t("permission.name")}</th>
|
||||||
<th className="is-hidden-mobile">
|
<th className="is-hidden-mobile">
|
||||||
{t("permission.group-permission")}
|
{t("permission.group-permission")}
|
||||||
</th>
|
</th>
|
||||||
<th>{t("permission.type")}</th>
|
<th>{t("permission.type")}</th>
|
||||||
<th />
|
<th />
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{permissions.map(permission => {
|
{permissions.map(permission => {
|
||||||
return (
|
return (
|
||||||
<SinglePermission
|
<SinglePermission
|
||||||
key={permission.name + permission.groupPermission.toString()}
|
key={permission.name + permission.groupPermission.toString()}
|
||||||
namespace={namespace}
|
namespace={namespace}
|
||||||
repoName={repoName}
|
repoName={repoName}
|
||||||
permission={permission}
|
permission={permission}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{createPermissionForm}
|
{createPermissionForm}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => {
|
const mapStateToProps = (state, ownProps) => {
|
||||||
const namespace = ownProps.namespace;
|
const namespace = ownProps.namespace;
|
||||||
const repoName = ownProps.repoName;
|
const repoName = ownProps.repoName;
|
||||||
const error =
|
const error =
|
||||||
getFetchPermissionsFailure(state, namespace, repoName) ||
|
getFetchPermissionsFailure(state, namespace, repoName) ||
|
||||||
getCreatePermissionFailure(state, namespace, repoName) ||
|
getCreatePermissionFailure(state, namespace, repoName) ||
|
||||||
getDeletePermissionsFailure(state, namespace, repoName) ||
|
getDeletePermissionsFailure(state, namespace, repoName) ||
|
||||||
getModifyPermissionsFailure(state, namespace, repoName);
|
getModifyPermissionsFailure(state, namespace, repoName);
|
||||||
const loading = isFetchPermissionsPending(state, namespace, repoName);
|
const loading = isFetchPermissionsPending(state, namespace, repoName);
|
||||||
const permissions = getPermissionsOfRepo(state, namespace, repoName);
|
const permissions = getPermissionsOfRepo(state, namespace, repoName);
|
||||||
const loadingCreatePermission = isCreatePermissionPending(
|
const loadingCreatePermission = isCreatePermissionPending(
|
||||||
state,
|
state,
|
||||||
namespace,
|
namespace,
|
||||||
repoName
|
repoName
|
||||||
);
|
);
|
||||||
const hasPermissionToCreate = hasCreatePermission(state, namespace, repoName);
|
const hasPermissionToCreate = hasCreatePermission(state, namespace, repoName);
|
||||||
const permissionsLink = getPermissionsLink(state, namespace, repoName);
|
const permissionsLink = getPermissionsLink(state, namespace, repoName);
|
||||||
const groupAutoCompleteLink = getGroupAutoCompleteLink(state);
|
const groupAutoCompleteLink = getGroupAutoCompleteLink(state);
|
||||||
const userAutoCompleteLink = getUserAutoCompleteLink(state);
|
const userAutoCompleteLink = getUserAutoCompleteLink(state);
|
||||||
return {
|
return {
|
||||||
namespace,
|
namespace,
|
||||||
repoName,
|
repoName,
|
||||||
error,
|
error,
|
||||||
loading,
|
loading,
|
||||||
permissions,
|
permissions,
|
||||||
hasPermissionToCreate,
|
hasPermissionToCreate,
|
||||||
loadingCreatePermission,
|
loadingCreatePermission,
|
||||||
permissionsLink,
|
permissionsLink,
|
||||||
groupAutoCompleteLink,
|
groupAutoCompleteLink,
|
||||||
userAutoCompleteLink
|
userAutoCompleteLink
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
fetchPermissions: (link: string, namespace: string, repoName: string) => {
|
fetchPermissions: (link: string, namespace: string, repoName: string) => {
|
||||||
dispatch(fetchPermissions(link, namespace, repoName));
|
dispatch(fetchPermissions(link, namespace, repoName));
|
||||||
},
|
},
|
||||||
createPermission: (
|
createPermission: (
|
||||||
link: string,
|
link: string,
|
||||||
permission: PermissionCreateEntry,
|
permission: PermissionCreateEntry,
|
||||||
namespace: string,
|
namespace: string,
|
||||||
repoName: string,
|
repoName: string,
|
||||||
callback?: () => void
|
callback?: () => void
|
||||||
) => {
|
) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
createPermission(link, permission, namespace, repoName, callback)
|
createPermission(link, permission, namespace, repoName, callback)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
createPermissionReset: (namespace: string, repoName: string) => {
|
createPermissionReset: (namespace: string, repoName: string) => {
|
||||||
dispatch(createPermissionReset(namespace, repoName));
|
dispatch(createPermissionReset(namespace, repoName));
|
||||||
},
|
},
|
||||||
modifyPermissionReset: (namespace: string, repoName: string) => {
|
modifyPermissionReset: (namespace: string, repoName: string) => {
|
||||||
dispatch(modifyPermissionReset(namespace, repoName));
|
dispatch(modifyPermissionReset(namespace, repoName));
|
||||||
},
|
},
|
||||||
deletePermissionReset: (namespace: string, repoName: string) => {
|
deletePermissionReset: (namespace: string, repoName: string) => {
|
||||||
dispatch(deletePermissionReset(namespace, repoName));
|
dispatch(deletePermissionReset(namespace, repoName));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(translate("repos")(Permissions));
|
)(translate("repos")(Permissions));
|
||||||
|
|||||||
@@ -1,176 +1,176 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { Permission } from "@scm-manager/ui-types";
|
import type { Permission } from "@scm-manager/ui-types";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import {
|
import {
|
||||||
modifyPermission,
|
modifyPermission,
|
||||||
isModifyPermissionPending,
|
isModifyPermissionPending,
|
||||||
deletePermission,
|
deletePermission,
|
||||||
isDeletePermissionPending
|
isDeletePermissionPending
|
||||||
} from "../modules/permissions";
|
} from "../modules/permissions";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import type { History } from "history";
|
import type { History } from "history";
|
||||||
import { Checkbox } from "@scm-manager/ui-components";
|
import { Checkbox } from "@scm-manager/ui-components";
|
||||||
import DeletePermissionButton from "../components/buttons/DeletePermissionButton";
|
import DeletePermissionButton from "../components/buttons/DeletePermissionButton";
|
||||||
import TypeSelector from "../components/TypeSelector";
|
import TypeSelector from "../components/TypeSelector";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
submitForm: Permission => void,
|
submitForm: Permission => void,
|
||||||
modifyPermission: (Permission, string, string) => void,
|
modifyPermission: (Permission, string, string) => void,
|
||||||
permission: Permission,
|
permission: Permission,
|
||||||
t: string => string,
|
t: string => string,
|
||||||
namespace: string,
|
namespace: string,
|
||||||
repoName: string,
|
repoName: string,
|
||||||
match: any,
|
match: any,
|
||||||
history: History,
|
history: History,
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
deletePermission: (Permission, string, string) => void,
|
deletePermission: (Permission, string, string) => void,
|
||||||
deleteLoading: boolean
|
deleteLoading: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
permission: Permission
|
permission: Permission
|
||||||
};
|
};
|
||||||
|
|
||||||
class SinglePermission extends React.Component<Props, State> {
|
class SinglePermission extends React.Component<Props, State> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
permission: {
|
permission: {
|
||||||
name: "",
|
name: "",
|
||||||
type: "READ",
|
type: "READ",
|
||||||
groupPermission: false,
|
groupPermission: false,
|
||||||
_links: {}
|
_links: {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { permission } = this.props;
|
const { permission } = this.props;
|
||||||
if (permission) {
|
if (permission) {
|
||||||
this.setState({
|
this.setState({
|
||||||
permission: {
|
permission: {
|
||||||
name: permission.name,
|
name: permission.name,
|
||||||
type: permission.type,
|
type: permission.type,
|
||||||
groupPermission: permission.groupPermission,
|
groupPermission: permission.groupPermission,
|
||||||
_links: permission._links
|
_links: permission._links
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deletePermission = () => {
|
deletePermission = () => {
|
||||||
this.props.deletePermission(
|
this.props.deletePermission(
|
||||||
this.props.permission,
|
this.props.permission,
|
||||||
this.props.namespace,
|
this.props.namespace,
|
||||||
this.props.repoName
|
this.props.repoName
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { permission } = this.state;
|
const { permission } = this.state;
|
||||||
const { loading, namespace, repoName } = this.props;
|
const { loading, namespace, repoName } = this.props;
|
||||||
const typeSelector =
|
const typeSelector =
|
||||||
this.props.permission._links && this.props.permission._links.update ? (
|
this.props.permission._links && this.props.permission._links.update ? (
|
||||||
<td>
|
<td>
|
||||||
<TypeSelector
|
<TypeSelector
|
||||||
handleTypeChange={this.handleTypeChange}
|
handleTypeChange={this.handleTypeChange}
|
||||||
type={permission.type ? permission.type : "READ"}
|
type={permission.type ? permission.type : "READ"}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
) : (
|
) : (
|
||||||
<td>{permission.type}</td>
|
<td>{permission.type}</td>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
<td>{permission.name}</td>
|
<td>{permission.name}</td>
|
||||||
<td>
|
<td>
|
||||||
<Checkbox checked={permission ? permission.groupPermission : false} />
|
<Checkbox checked={permission ? permission.groupPermission : false} />
|
||||||
</td>
|
</td>
|
||||||
{typeSelector}
|
{typeSelector}
|
||||||
<td>
|
<td>
|
||||||
<DeletePermissionButton
|
<DeletePermissionButton
|
||||||
permission={permission}
|
permission={permission}
|
||||||
namespace={namespace}
|
namespace={namespace}
|
||||||
repoName={repoName}
|
repoName={repoName}
|
||||||
deletePermission={this.deletePermission}
|
deletePermission={this.deletePermission}
|
||||||
loading={this.props.deleteLoading}
|
loading={this.props.deleteLoading}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTypeChange = (type: string) => {
|
handleTypeChange = (type: string) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
permission: {
|
permission: {
|
||||||
...this.state.permission,
|
...this.state.permission,
|
||||||
type: type
|
type: type
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.modifyPermission(type);
|
this.modifyPermission(type);
|
||||||
};
|
};
|
||||||
|
|
||||||
modifyPermission = (type: string) => {
|
modifyPermission = (type: string) => {
|
||||||
let permission = this.state.permission;
|
let permission = this.state.permission;
|
||||||
permission.type = type;
|
permission.type = type;
|
||||||
this.props.modifyPermission(
|
this.props.modifyPermission(
|
||||||
permission,
|
permission,
|
||||||
this.props.namespace,
|
this.props.namespace,
|
||||||
this.props.repoName
|
this.props.repoName
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
createSelectOptions(types: string[]) {
|
createSelectOptions(types: string[]) {
|
||||||
return types.map(type => {
|
return types.map(type => {
|
||||||
return {
|
return {
|
||||||
label: type,
|
label: type,
|
||||||
value: type
|
value: type
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => {
|
const mapStateToProps = (state, ownProps) => {
|
||||||
const permission = ownProps.permission;
|
const permission = ownProps.permission;
|
||||||
const loading = isModifyPermissionPending(
|
const loading = isModifyPermissionPending(
|
||||||
state,
|
state,
|
||||||
ownProps.namespace,
|
ownProps.namespace,
|
||||||
ownProps.repoName,
|
ownProps.repoName,
|
||||||
permission
|
permission
|
||||||
);
|
);
|
||||||
const deleteLoading = isDeletePermissionPending(
|
const deleteLoading = isDeletePermissionPending(
|
||||||
state,
|
state,
|
||||||
ownProps.namespace,
|
ownProps.namespace,
|
||||||
ownProps.repoName,
|
ownProps.repoName,
|
||||||
permission
|
permission
|
||||||
);
|
);
|
||||||
|
|
||||||
return { loading, deleteLoading };
|
return { loading, deleteLoading };
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
modifyPermission: (
|
modifyPermission: (
|
||||||
permission: Permission,
|
permission: Permission,
|
||||||
namespace: string,
|
namespace: string,
|
||||||
repoName: string
|
repoName: string
|
||||||
) => {
|
) => {
|
||||||
dispatch(modifyPermission(permission, namespace, repoName));
|
dispatch(modifyPermission(permission, namespace, repoName));
|
||||||
},
|
},
|
||||||
deletePermission: (
|
deletePermission: (
|
||||||
permission: Permission,
|
permission: Permission,
|
||||||
namespace: string,
|
namespace: string,
|
||||||
repoName: string
|
repoName: string
|
||||||
) => {
|
) => {
|
||||||
dispatch(deletePermission(permission, namespace, repoName));
|
dispatch(deletePermission(permission, namespace, repoName));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(translate("repos")(SinglePermission));
|
)(translate("repos")(SinglePermission));
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ const styles = {
|
|||||||
isVerticalCenter: {
|
isVerticalCenter: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center"
|
alignItems: "center"
|
||||||
|
},
|
||||||
|
hasBackground: {
|
||||||
|
backgroundColor: "#FBFBFB"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -120,8 +123,14 @@ class Content extends React.Component<Props, State> {
|
|||||||
const fileSize = file.directory ? "" : <FileSize bytes={file.length} />;
|
const fileSize = file.directory ? "" : <FileSize bytes={file.length} />;
|
||||||
if (!collapsed) {
|
if (!collapsed) {
|
||||||
return (
|
return (
|
||||||
<div className={classNames("panel-block", classes.toCenterContent)}>
|
<div
|
||||||
<table className="table">
|
className={classNames(
|
||||||
|
"panel-block",
|
||||||
|
classes.toCenterContent,
|
||||||
|
classes.hasBackground
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<table className={classNames("table", classes.hasBackground)}>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("sources.content.path")}</td>
|
<td>{t("sources.content.path")}</td>
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class Sources extends React.Component<Props> {
|
|||||||
|
|
||||||
if (currentFileIsDirectory) {
|
if (currentFileIsDirectory) {
|
||||||
return (
|
return (
|
||||||
<>
|
<div className={"has-border-around"}>
|
||||||
{this.renderBranchSelector()}
|
{this.renderBranchSelector()}
|
||||||
<FileTree
|
<FileTree
|
||||||
repository={repository}
|
repository={repository}
|
||||||
@@ -101,7 +101,7 @@ class Sources extends React.Component<Props> {
|
|||||||
path={path}
|
path={path}
|
||||||
baseUrl={baseUrl}
|
baseUrl={baseUrl}
|
||||||
/>
|
/>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -105,41 +105,55 @@ class UserForm extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this.submit}>
|
<form onSubmit={this.submit}>
|
||||||
{nameField}
|
<div className="columns">
|
||||||
<InputField
|
<div className="column is-half">
|
||||||
label={t("user.displayName")}
|
{nameField}
|
||||||
onChange={this.handleDisplayNameChange}
|
<InputField
|
||||||
value={user ? user.displayName : ""}
|
label={t("user.displayName")}
|
||||||
validationError={this.state.displayNameValidationError}
|
onChange={this.handleDisplayNameChange}
|
||||||
errorMessage={t("validation.displayname-invalid")}
|
value={user ? user.displayName : ""}
|
||||||
helpText={t("help.displayNameHelpText")}
|
validationError={this.state.displayNameValidationError}
|
||||||
/>
|
errorMessage={t("validation.displayname-invalid")}
|
||||||
<InputField
|
helpText={t("help.displayNameHelpText")}
|
||||||
label={t("user.mail")}
|
/>
|
||||||
onChange={this.handleEmailChange}
|
</div>
|
||||||
value={user ? user.mail : ""}
|
<div className="column is-half">
|
||||||
validationError={this.state.mailValidationError}
|
<InputField
|
||||||
errorMessage={t("validation.mail-invalid")}
|
label={t("user.mail")}
|
||||||
helpText={t("help.mailHelpText")}
|
onChange={this.handleEmailChange}
|
||||||
/>
|
value={user ? user.mail : ""}
|
||||||
{passwordChangeField}
|
validationError={this.state.mailValidationError}
|
||||||
<Checkbox
|
errorMessage={t("validation.mail-invalid")}
|
||||||
label={t("user.admin")}
|
helpText={t("help.mailHelpText")}
|
||||||
onChange={this.handleAdminChange}
|
/>
|
||||||
checked={user ? user.admin : false}
|
</div>
|
||||||
helpText={t("help.adminHelpText")}
|
</div>
|
||||||
/>
|
<div className="columns">
|
||||||
<Checkbox
|
<div className="column">
|
||||||
label={t("user.active")}
|
{passwordChangeField}
|
||||||
onChange={this.handleActiveChange}
|
<Checkbox
|
||||||
checked={user ? user.active : false}
|
label={t("user.admin")}
|
||||||
helpText={t("help.activeHelpText")}
|
onChange={this.handleAdminChange}
|
||||||
/>
|
checked={user ? user.admin : false}
|
||||||
<SubmitButton
|
helpText={t("help.adminHelpText")}
|
||||||
disabled={!this.isValid()}
|
/>
|
||||||
loading={loading}
|
<Checkbox
|
||||||
label={t("user-form.submit")}
|
label={t("user.active")}
|
||||||
/>
|
onChange={this.handleActiveChange}
|
||||||
|
checked={user ? user.active : false}
|
||||||
|
helpText={t("help.activeHelpText")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="columns">
|
||||||
|
<div className="column">
|
||||||
|
<SubmitButton
|
||||||
|
disabled={!this.isValid()}
|
||||||
|
loading={loading}
|
||||||
|
label={t("user-form.submit")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,66 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { User } from "@scm-manager/ui-types";
|
import type { User } from "@scm-manager/ui-types";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import { Checkbox, MailLink, DateFromNow } from "@scm-manager/ui-components";
|
import { Checkbox, MailLink, DateFromNow } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
user: User,
|
user: User,
|
||||||
t: string => string
|
t: string => string
|
||||||
};
|
};
|
||||||
|
|
||||||
class Details extends React.Component<Props> {
|
class Details extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { user, t } = this.props;
|
const { user, t } = this.props;
|
||||||
return (
|
return (
|
||||||
<table className="table">
|
<table className="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("user.name")}</td>
|
<td className="has-text-weight-semibold">{t("user.name")}</td>
|
||||||
<td>{user.name}</td>
|
<td>{user.name}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("user.displayName")}</td>
|
<td className="has-text-weight-semibold">{t("user.displayName")}</td>
|
||||||
<td>{user.displayName}</td>
|
<td>{user.displayName}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("user.mail")}</td>
|
<td className="has-text-weight-semibold">{t("user.mail")}</td>
|
||||||
<td>
|
<td>
|
||||||
<MailLink address={user.mail} />
|
<MailLink address={user.mail} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("user.admin")}</td>
|
<td className="has-text-weight-semibold">{t("user.admin")}</td>
|
||||||
<td>
|
<td>
|
||||||
<Checkbox checked={user.admin} />
|
<Checkbox checked={user.admin} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("user.active")}</td>
|
<td className="has-text-weight-semibold">{t("user.active")}</td>
|
||||||
<td>
|
<td>
|
||||||
<Checkbox checked={user.active} />
|
<Checkbox checked={user.active} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("user.type")}</td>
|
<td className="has-text-weight-semibold">{t("user.type")}</td>
|
||||||
<td>{user.type}</td>
|
<td>{user.type}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("user.creationDate")}</td>
|
<td className="has-text-weight-semibold">{t("user.creationDate")}</td>
|
||||||
<td>
|
<td>
|
||||||
<DateFromNow date={user.creationDate} />
|
<DateFromNow date={user.creationDate} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("user.lastModified")}</td>
|
<td className="has-text-weight-semibold">{t("user.lastModified")}</td>
|
||||||
<td>
|
<td>
|
||||||
<DateFromNow date={user.lastModified} />
|
<DateFromNow date={user.lastModified} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translate("users")(Details);
|
export default translate("users")(Details);
|
||||||
|
|||||||
@@ -1,31 +1,31 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import type { User } from "@scm-manager/ui-types";
|
import type { User } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
user: User
|
user: User
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class UserRow extends React.Component<Props> {
|
export default class UserRow extends React.Component<Props> {
|
||||||
renderLink(to: string, label: string) {
|
renderLink(to: string, label: string) {
|
||||||
return <Link to={to}>{label}</Link>;
|
return <Link to={to}>{label}</Link>;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { user } = this.props;
|
const { user } = this.props;
|
||||||
const to = `/user/${user.name}`;
|
const to = `/user/${user.name}`;
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
<td className="is-hidden-mobile">{this.renderLink(to, user.name)}</td>
|
<td className="is-hidden-mobile">{this.renderLink(to, user.name)}</td>
|
||||||
<td>{this.renderLink(to, user.displayName)}</td>
|
<td>{this.renderLink(to, user.displayName)}</td>
|
||||||
<td>
|
<td>
|
||||||
<a href={`mailto: ${user.mail}`}>{user.mail}</a>
|
<a href={`mailto: ${user.mail}`}>{user.mail}</a>
|
||||||
</td>
|
</td>
|
||||||
<td className="is-hidden-mobile">
|
<td className="is-hidden-mobile">
|
||||||
<input type="checkbox" id="admin" checked={user.admin} readOnly />
|
<input type="checkbox" id="admin" checked={user.admin} readOnly />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,37 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
import UserRow from "./UserRow";
|
import UserRow from "./UserRow";
|
||||||
import type { User } from "@scm-manager/ui-types";
|
import type { User } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
t: string => string,
|
t: string => string,
|
||||||
users: User[]
|
users: User[]
|
||||||
};
|
};
|
||||||
|
|
||||||
class UserTable extends React.Component<Props> {
|
;
|
||||||
render() {
|
|
||||||
const { users, t } = this.props;
|
class UserTable extends React.Component<Props> {
|
||||||
return (
|
render() {
|
||||||
<table className="table is-hoverable is-fullwidth">
|
const { users, t } = this.props;
|
||||||
<thead>
|
return (
|
||||||
<tr>
|
<table className="card-table table is-hoverable is-fullwidth">
|
||||||
<th className="is-hidden-mobile">{t("user.name")}</th>
|
<thead>
|
||||||
<th>{t("user.displayName")}</th>
|
<tr>
|
||||||
<th>{t("user.mail")}</th>
|
<th className="is-hidden-mobile">{t("user.name")}</th>
|
||||||
<th className="is-hidden-mobile">{t("user.admin")}</th>
|
<th>{t("user.displayName")}</th>
|
||||||
</tr>
|
<th>{t("user.mail")}</th>
|
||||||
</thead>
|
<th className="is-hidden-mobile">{t("user.admin")}</th>
|
||||||
<tbody>
|
</tr>
|
||||||
{users.map((user, index) => {
|
</thead>
|
||||||
return <UserRow key={index} user={user} />;
|
<tbody>
|
||||||
})}
|
{users.map((user, index) => {
|
||||||
</tbody>
|
return <UserRow key={index} user={user} />;
|
||||||
</table>
|
})}
|
||||||
);
|
</tbody>
|
||||||
}
|
</table>
|
||||||
}
|
);
|
||||||
|
}
|
||||||
export default translate("users")(UserTable);
|
}
|
||||||
|
|
||||||
|
export default translate("users")(UserTable);
|
||||||
@@ -1,143 +1,143 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { History } from "history";
|
import type { History } from "history";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { translate } from "react-i18next";
|
import { translate } from "react-i18next";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
fetchUsersByPage,
|
fetchUsersByPage,
|
||||||
fetchUsersByLink,
|
fetchUsersByLink,
|
||||||
getUsersFromState,
|
getUsersFromState,
|
||||||
selectListAsCollection,
|
selectListAsCollection,
|
||||||
isPermittedToCreateUsers,
|
isPermittedToCreateUsers,
|
||||||
isFetchUsersPending,
|
isFetchUsersPending,
|
||||||
getFetchUsersFailure
|
getFetchUsersFailure
|
||||||
} from "../modules/users";
|
} from "../modules/users";
|
||||||
|
|
||||||
import { Page, Paginator } from "@scm-manager/ui-components";
|
import { Page, Paginator } from "@scm-manager/ui-components";
|
||||||
import { UserTable } from "./../components/table";
|
import { UserTable } from "./../components/table";
|
||||||
import type { User, PagedCollection } from "@scm-manager/ui-types";
|
import type { User, PagedCollection } from "@scm-manager/ui-types";
|
||||||
import CreateUserButton from "../components/buttons/CreateUserButton";
|
import CreateUserButton from "../components/buttons/CreateUserButton";
|
||||||
import { getUsersLink } from "../../modules/indexResource";
|
import { getUsersLink } from "../../modules/indexResource";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
users: User[],
|
users: User[],
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
error: Error,
|
error: Error,
|
||||||
canAddUsers: boolean,
|
canAddUsers: boolean,
|
||||||
list: PagedCollection,
|
list: PagedCollection,
|
||||||
page: number,
|
page: number,
|
||||||
usersLink: string,
|
usersLink: string,
|
||||||
|
|
||||||
// context objects
|
// context objects
|
||||||
t: string => string,
|
t: string => string,
|
||||||
history: History,
|
history: History,
|
||||||
|
|
||||||
// dispatch functions
|
// dispatch functions
|
||||||
fetchUsersByPage: (link: string, page: number) => void,
|
fetchUsersByPage: (link: string, page: number) => void,
|
||||||
fetchUsersByLink: (link: string) => void
|
fetchUsersByLink: (link: string) => void
|
||||||
};
|
};
|
||||||
|
|
||||||
class Users extends React.Component<Props> {
|
class Users extends React.Component<Props> {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchUsersByPage(this.props.usersLink, this.props.page);
|
this.props.fetchUsersByPage(this.props.usersLink, this.props.page);
|
||||||
}
|
}
|
||||||
|
|
||||||
onPageChange = (link: string) => {
|
onPageChange = (link: string) => {
|
||||||
this.props.fetchUsersByLink(link);
|
this.props.fetchUsersByLink(link);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* reflect page transitions in the uri
|
* reflect page transitions in the uri
|
||||||
*/
|
*/
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
const { page, list } = this.props;
|
const { page, list } = this.props;
|
||||||
if (list && (list.page || list.page === 0)) {
|
if (list && (list.page || list.page === 0)) {
|
||||||
// backend starts paging by 0
|
// backend starts paging by 0
|
||||||
const statePage: number = list.page + 1;
|
const statePage: number = list.page + 1;
|
||||||
if (page !== statePage) {
|
if (page !== statePage) {
|
||||||
this.props.history.push(`/users/${statePage}`);
|
this.props.history.push(`/users/${statePage}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { users, loading, error, t } = this.props;
|
const { users, loading, error, t } = this.props;
|
||||||
return (
|
return (
|
||||||
<Page
|
<Page
|
||||||
title={t("users.title")}
|
title={t("users.title")}
|
||||||
subtitle={t("users.subtitle")}
|
subtitle={t("users.subtitle")}
|
||||||
loading={loading || !users}
|
loading={loading || !users}
|
||||||
error={error}
|
error={error}
|
||||||
>
|
>
|
||||||
<UserTable users={users} />
|
<UserTable users={users} />
|
||||||
{this.renderPaginator()}
|
{this.renderPaginator()}
|
||||||
{this.renderCreateButton()}
|
{this.renderCreateButton()}
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPaginator() {
|
renderPaginator() {
|
||||||
const { list } = this.props;
|
const { list } = this.props;
|
||||||
if (list) {
|
if (list) {
|
||||||
return <Paginator collection={list} onPageChange={this.onPageChange} />;
|
return <Paginator collection={list} onPageChange={this.onPageChange} />;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCreateButton() {
|
renderCreateButton() {
|
||||||
if (this.props.canAddUsers) {
|
if (this.props.canAddUsers) {
|
||||||
return <CreateUserButton />;
|
return <CreateUserButton />;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getPageFromProps = props => {
|
const getPageFromProps = props => {
|
||||||
let page = props.match.params.page;
|
let page = props.match.params.page;
|
||||||
if (page) {
|
if (page) {
|
||||||
page = parseInt(page, 10);
|
page = parseInt(page, 10);
|
||||||
} else {
|
} else {
|
||||||
page = 1;
|
page = 1;
|
||||||
}
|
}
|
||||||
return page;
|
return page;
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => {
|
const mapStateToProps = (state, ownProps) => {
|
||||||
const users = getUsersFromState(state);
|
const users = getUsersFromState(state);
|
||||||
const loading = isFetchUsersPending(state);
|
const loading = isFetchUsersPending(state);
|
||||||
const error = getFetchUsersFailure(state);
|
const error = getFetchUsersFailure(state);
|
||||||
|
|
||||||
const usersLink = getUsersLink(state);
|
const usersLink = getUsersLink(state);
|
||||||
|
|
||||||
const page = getPageFromProps(ownProps);
|
const page = getPageFromProps(ownProps);
|
||||||
const canAddUsers = isPermittedToCreateUsers(state);
|
const canAddUsers = isPermittedToCreateUsers(state);
|
||||||
const list = selectListAsCollection(state);
|
const list = selectListAsCollection(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
users,
|
users,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
canAddUsers,
|
canAddUsers,
|
||||||
list,
|
list,
|
||||||
page,
|
page,
|
||||||
usersLink
|
usersLink
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
fetchUsersByPage: (link: string, page: number) => {
|
fetchUsersByPage: (link: string, page: number) => {
|
||||||
dispatch(fetchUsersByPage(link, page));
|
dispatch(fetchUsersByPage(link, page));
|
||||||
},
|
},
|
||||||
fetchUsersByLink: (link: string) => {
|
fetchUsersByLink: (link: string) => {
|
||||||
dispatch(fetchUsersByLink(link));
|
dispatch(fetchUsersByLink(link));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(translate("users")(Users));
|
)(translate("users")(Users));
|
||||||
|
|||||||
10277
scm-ui/styles/scm.css
10277
scm-ui/styles/scm.css
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
|||||||
@import "bulma/sass/utilities/initial-variables";
|
@import "bulma/sass/utilities/initial-variables";
|
||||||
@import "bulma/sass/utilities/functions";
|
@import "bulma/sass/utilities/functions";
|
||||||
|
|
||||||
|
$blue: #33b2e8;
|
||||||
$blue: #33B2E8;
|
$mint: #11dfd0;
|
||||||
|
|
||||||
// $footer-background-color
|
// $footer-background-color
|
||||||
|
|
||||||
@@ -51,15 +51,239 @@ $blue: #33B2E8;
|
|||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus {
|
||||||
box-shadow: $box-link-hover-shadow;
|
box-shadow: $box-link-hover-shadow;
|
||||||
}
|
}
|
||||||
&:active {
|
&:active {
|
||||||
box-shadow: $box-link-active-shadow;
|
box-shadow: $box-link-active-shadow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@import "@fortawesome/fontawesome-free/scss/fontawesome.scss";
|
@import "@fortawesome/fontawesome-free/scss/fontawesome.scss";
|
||||||
$fa-font-path: "webfonts";
|
$fa-font-path: "webfonts";
|
||||||
@import "@fortawesome/fontawesome-free/scss/solid.scss";
|
@import "@fortawesome/fontawesome-free/scss/solid.scss";
|
||||||
|
|
||||||
@import "diff2html/dist/diff2html";
|
@import "diff2html/dist/diff2html";
|
||||||
|
|
||||||
|
// NEW STYLES
|
||||||
|
|
||||||
|
//typography
|
||||||
|
.subtitle {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.has-border-white {
|
||||||
|
border-color: #fff !important;
|
||||||
|
}
|
||||||
|
// buttons
|
||||||
|
.button {
|
||||||
|
padding-left: 1.5em;
|
||||||
|
padding-right: 1.5em;
|
||||||
|
height: 2.5rem;
|
||||||
|
|
||||||
|
&.is-primary {
|
||||||
|
background-color: $mint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//border around options
|
||||||
|
.has-border-around {
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
border-left: 1px solid #eee;
|
||||||
|
border-right: 1px solid #eee;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiline Columns
|
||||||
|
.columns.is-multiline {
|
||||||
|
.column.is-half {
|
||||||
|
width: calc(50% - 0.75rem);
|
||||||
|
max-height: 120px;
|
||||||
|
|
||||||
|
&:nth-child(odd) {
|
||||||
|
margin-right: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.column.is-half {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&:nth-child(odd) {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.media {
|
||||||
|
.media-content {
|
||||||
|
width: calc(50% - 0.75rem);
|
||||||
|
max-height: 120px;
|
||||||
|
.shorten-text {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tables
|
||||||
|
.table {
|
||||||
|
width: 100%;
|
||||||
|
td {
|
||||||
|
border-color: #eee;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// card tables
|
||||||
|
.card-table {
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0px 5px;
|
||||||
|
|
||||||
|
tr {
|
||||||
|
a {
|
||||||
|
color: #363636;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
td {
|
||||||
|
background-color: whitesmoke;
|
||||||
|
&:nth-child(4) {
|
||||||
|
background-color: #e1e1e1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
border-bottom: 1px solid whitesmoke;
|
||||||
|
background-color: #fafafa;
|
||||||
|
padding: 1em 1.25em;
|
||||||
|
&:first-child {
|
||||||
|
border-left: 3px solid $mint;
|
||||||
|
}
|
||||||
|
&:nth-child(4) {
|
||||||
|
background-color: whitesmoke;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.is-hoverable tbody tr:not(.is-selected):hover {
|
||||||
|
background-color: whitesmoke;
|
||||||
|
}
|
||||||
|
thead th {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// forms
|
||||||
|
.field:not(.is-grouped) {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.input,
|
||||||
|
.textarea {
|
||||||
|
/*background-color: whitesmoke;*/
|
||||||
|
border-color: #98d8f3;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pagination
|
||||||
|
.pagination-next,
|
||||||
|
.pagination-link,
|
||||||
|
.pagination-ellipsis {
|
||||||
|
padding-left: 1.5em;
|
||||||
|
padding-right: 1.5em;
|
||||||
|
height: 2.5rem;
|
||||||
|
}
|
||||||
|
.pagination-previous,
|
||||||
|
.pagination-next {
|
||||||
|
min-width: 6.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dark hero colors
|
||||||
|
.hero.is-dark {
|
||||||
|
background-color: #002e4b;
|
||||||
|
background-image: url(../images/scmManagerHero.jpg);
|
||||||
|
background-size: cover;
|
||||||
|
background-position: top center;
|
||||||
|
|
||||||
|
.tabs.is-boxed li.is-active a,
|
||||||
|
.tabs.is-boxed li.is-active a:hover,
|
||||||
|
.tabs.is-toggle li.is-active a,
|
||||||
|
.tabs.is-toggle li.is-active a:hover {
|
||||||
|
background-color: #28b1e8;
|
||||||
|
border-color: #28b1e8;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// footer
|
||||||
|
.footer {
|
||||||
|
background-color: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sidebar menu
|
||||||
|
.aside-background {
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
background-color: whitesmoke;
|
||||||
|
}
|
||||||
|
.menu {
|
||||||
|
div {
|
||||||
|
height: 100%;
|
||||||
|
/*border: 1px solid #eee;*/
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-label {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: 600;
|
||||||
|
background-color: #bbb;
|
||||||
|
border-radius: 5px 5px 0 0;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
text-transform: none;
|
||||||
|
|
||||||
|
&:last-child,
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.menu div:first-child .menu-label {
|
||||||
|
background-color: $blue;
|
||||||
|
}
|
||||||
|
.menu-list {
|
||||||
|
a {
|
||||||
|
border-radius: 0;
|
||||||
|
color: #333;
|
||||||
|
padding: 1rem;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
border-left: 1px solid #eee;
|
||||||
|
border-right: 1px solid #eee;
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
color: $blue;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
position: relative;
|
||||||
|
content: " ";
|
||||||
|
background: $blue;
|
||||||
|
height: 53px;
|
||||||
|
width: 2px;
|
||||||
|
display: block;
|
||||||
|
left: -17px;
|
||||||
|
float: left;
|
||||||
|
top: -16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> li:first-child > a {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
li:last-child > a {
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user