mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-16 02:06:18 +01:00
Added first UI changes
This commit is contained in:
@@ -1,86 +1,93 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Subtitle, AddEntryToTableField } from "@scm-manager/ui-components";
|
||||
import AdminGroupTable from "../table/AdminGroupTable";
|
||||
import AdminUserTable from "../table/AdminUserTable";
|
||||
|
||||
type Props = {
|
||||
adminGroups: string[],
|
||||
adminUsers: string[],
|
||||
t: string => string,
|
||||
onChange: (boolean, any, string) => void,
|
||||
hasUpdatePermission: boolean
|
||||
};
|
||||
|
||||
class AdminSettings extends React.Component<Props> {
|
||||
render() {
|
||||
const { t, adminGroups, adminUsers, hasUpdatePermission } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Subtitle subtitle={t("admin-settings.name")} />
|
||||
<AdminGroupTable
|
||||
adminGroups={adminGroups}
|
||||
onChange={(isValid, changedValue, name) =>
|
||||
this.props.onChange(isValid, changedValue, name)
|
||||
}
|
||||
disabled={!hasUpdatePermission}
|
||||
/>
|
||||
<AddEntryToTableField
|
||||
addEntry={this.addGroup}
|
||||
disabled={!hasUpdatePermission}
|
||||
buttonLabel={t("admin-settings.add-group-button")}
|
||||
fieldLabel={t("admin-settings.add-group-textfield")}
|
||||
errorMessage={t("admin-settings.add-group-error")}
|
||||
/>
|
||||
<AdminUserTable
|
||||
adminUsers={adminUsers}
|
||||
onChange={(isValid, changedValue, name) =>
|
||||
this.props.onChange(isValid, changedValue, name)
|
||||
}
|
||||
disabled={!hasUpdatePermission}
|
||||
/>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
addGroup = (groupname: string) => {
|
||||
if (this.isAdminGroupMember(groupname)) {
|
||||
return;
|
||||
}
|
||||
this.props.onChange(
|
||||
true,
|
||||
[...this.props.adminGroups, groupname],
|
||||
"adminGroups"
|
||||
);
|
||||
};
|
||||
|
||||
isAdminGroupMember = (groupname: string) => {
|
||||
return this.props.adminGroups.includes(groupname);
|
||||
};
|
||||
|
||||
addUser = (username: string) => {
|
||||
if (this.isAdminUserMember(username)) {
|
||||
return;
|
||||
}
|
||||
this.props.onChange(
|
||||
true,
|
||||
[...this.props.adminUsers, username],
|
||||
"adminUsers"
|
||||
);
|
||||
};
|
||||
|
||||
isAdminUserMember = (username: string) => {
|
||||
return this.props.adminUsers.includes(username);
|
||||
};
|
||||
}
|
||||
|
||||
export default translate("config")(AdminSettings);
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Subtitle, AddEntryToTableField } from "@scm-manager/ui-components";
|
||||
import AdminGroupTable from "../table/AdminGroupTable";
|
||||
import AdminUserTable from "../table/AdminUserTable";
|
||||
|
||||
type Props = {
|
||||
adminGroups: string[],
|
||||
adminUsers: string[],
|
||||
t: string => string,
|
||||
onChange: (boolean, any, string) => void,
|
||||
hasUpdatePermission: boolean
|
||||
};
|
||||
|
||||
class AdminSettings extends React.Component<Props> {
|
||||
render() {
|
||||
const { t, adminGroups, adminUsers, hasUpdatePermission } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Subtitle subtitle={t("admin-settings.name")} />
|
||||
<div class="columns">
|
||||
<div class="column is-half">
|
||||
<AdminGroupTable
|
||||
adminGroups={adminGroups}
|
||||
onChange={(isValid, changedValue, name) =>
|
||||
this.props.onChange(isValid, changedValue, name)
|
||||
}
|
||||
disabled={!hasUpdatePermission}
|
||||
/>
|
||||
|
||||
<AddEntryToTableField
|
||||
addEntry={this.addGroup}
|
||||
disabled={!hasUpdatePermission}
|
||||
buttonLabel={t("admin-settings.add-group-button")}
|
||||
fieldLabel={t("admin-settings.add-group-textfield")}
|
||||
errorMessage={t("admin-settings.add-group-error")}
|
||||
/>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
<AdminUserTable
|
||||
adminUsers={adminUsers}
|
||||
onChange={(isValid, changedValue, name) =>
|
||||
this.props.onChange(isValid, changedValue, name)
|
||||
}
|
||||
disabled={!hasUpdatePermission}
|
||||
/>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
addGroup = (groupname: string) => {
|
||||
if (this.isAdminGroupMember(groupname)) {
|
||||
return;
|
||||
}
|
||||
this.props.onChange(
|
||||
true,
|
||||
[...this.props.adminGroups, groupname],
|
||||
"adminGroups"
|
||||
);
|
||||
};
|
||||
|
||||
isAdminGroupMember = (groupname: string) => {
|
||||
return this.props.adminGroups.includes(groupname);
|
||||
};
|
||||
|
||||
addUser = (username: string) => {
|
||||
if (this.isAdminUserMember(username)) {
|
||||
return;
|
||||
}
|
||||
this.props.onChange(
|
||||
true,
|
||||
[...this.props.adminUsers, username],
|
||||
"adminUsers"
|
||||
);
|
||||
};
|
||||
|
||||
isAdminUserMember = (username: string) => {
|
||||
return this.props.adminUsers.includes(username);
|
||||
};
|
||||
}
|
||||
|
||||
export default translate("config")(AdminSettings);
|
||||
|
||||
@@ -1,47 +1,54 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Checkbox, InputField, Subtitle } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
baseUrl: string,
|
||||
forceBaseUrl: boolean,
|
||||
t: string => string,
|
||||
onChange: (boolean, any, string) => void,
|
||||
hasUpdatePermission: boolean
|
||||
};
|
||||
|
||||
class BaseUrlSettings extends React.Component<Props> {
|
||||
render() {
|
||||
const { t, baseUrl, forceBaseUrl, hasUpdatePermission } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Subtitle subtitle={t("base-url-settings.name")} />
|
||||
<Checkbox
|
||||
checked={forceBaseUrl}
|
||||
label={t("base-url-settings.force-base-url")}
|
||||
onChange={this.handleForceBaseUrlChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.forceBaseUrlHelpText")}
|
||||
/>
|
||||
<InputField
|
||||
label={t("base-url-settings.base-url")}
|
||||
onChange={this.handleBaseUrlChange}
|
||||
value={baseUrl}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.baseUrlHelpText")}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
handleBaseUrlChange = (value: string) => {
|
||||
this.props.onChange(true, value, "baseUrl");
|
||||
};
|
||||
handleForceBaseUrlChange = (value: boolean) => {
|
||||
this.props.onChange(true, value, "forceBaseUrl");
|
||||
};
|
||||
}
|
||||
|
||||
export default translate("config")(BaseUrlSettings);
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Checkbox, InputField, Subtitle } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
baseUrl: string,
|
||||
forceBaseUrl: boolean,
|
||||
t: string => string,
|
||||
onChange: (boolean, any, string) => void,
|
||||
hasUpdatePermission: boolean
|
||||
};
|
||||
|
||||
class BaseUrlSettings extends React.Component<Props> {
|
||||
render() {
|
||||
const { t, baseUrl, forceBaseUrl, hasUpdatePermission } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Subtitle subtitle={t("base-url-settings.name")} />
|
||||
<div class="columns">
|
||||
<div class="column is-half">
|
||||
|
||||
<Checkbox
|
||||
checked={forceBaseUrl}
|
||||
label={t("base-url-settings.force-base-url")}
|
||||
onChange={this.handleForceBaseUrlChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.forceBaseUrlHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
<InputField
|
||||
label={t("base-url-settings.base-url")}
|
||||
onChange={this.handleBaseUrlChange}
|
||||
value={baseUrl}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.baseUrlHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
handleBaseUrlChange = (value: string) => {
|
||||
this.props.onChange(true, value, "baseUrl");
|
||||
};
|
||||
handleForceBaseUrlChange = (value: boolean) => {
|
||||
this.props.onChange(true, value, "forceBaseUrl");
|
||||
};
|
||||
}
|
||||
|
||||
export default translate("config")(BaseUrlSettings);
|
||||
|
||||
@@ -1,137 +1,165 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Checkbox, InputField } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
realmDescription: string,
|
||||
enableRepositoryArchive: boolean,
|
||||
disableGroupingGrid: boolean,
|
||||
dateFormat: string,
|
||||
anonymousAccessEnabled: boolean,
|
||||
skipFailedAuthenticators: boolean,
|
||||
pluginUrl: string,
|
||||
enabledXsrfProtection: boolean,
|
||||
defaultNamespaceStrategy: string,
|
||||
t: string => string,
|
||||
onChange: (boolean, any, string) => void,
|
||||
hasUpdatePermission: boolean
|
||||
};
|
||||
|
||||
class GeneralSettings extends React.Component<Props> {
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
realmDescription,
|
||||
enableRepositoryArchive,
|
||||
disableGroupingGrid,
|
||||
dateFormat,
|
||||
anonymousAccessEnabled,
|
||||
skipFailedAuthenticators,
|
||||
pluginUrl,
|
||||
enabledXsrfProtection,
|
||||
defaultNamespaceStrategy,
|
||||
hasUpdatePermission
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<InputField
|
||||
label={t("general-settings.realm-description")}
|
||||
onChange={this.handleRealmDescriptionChange}
|
||||
value={realmDescription}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.realmDescriptionHelpText")}
|
||||
/>
|
||||
<InputField
|
||||
label={t("general-settings.date-format")}
|
||||
onChange={this.handleDateFormatChange}
|
||||
value={dateFormat}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.dateFormatHelpText")}
|
||||
/>
|
||||
<InputField
|
||||
label={t("general-settings.plugin-url")}
|
||||
onChange={this.handlePluginUrlChange}
|
||||
value={pluginUrl}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.pluginRepositoryHelpText")}
|
||||
/>
|
||||
<InputField
|
||||
label={t("general-settings.default-namespace-strategy")}
|
||||
onChange={this.handleDefaultNamespaceStrategyChange}
|
||||
value={defaultNamespaceStrategy}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.defaultNameSpaceStrategyHelpText")}
|
||||
/>
|
||||
<Checkbox
|
||||
checked={enabledXsrfProtection}
|
||||
label={t("general-settings.enabled-xsrf-protection")}
|
||||
onChange={this.handleEnabledXsrfProtectionChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.enableXsrfProtectionHelpText")}
|
||||
/>
|
||||
<Checkbox
|
||||
checked={enableRepositoryArchive}
|
||||
label={t("general-settings.enable-repository-archive")}
|
||||
onChange={this.handleEnableRepositoryArchiveChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.enableRepositoryArchiveHelpText")}
|
||||
/>
|
||||
<Checkbox
|
||||
checked={disableGroupingGrid}
|
||||
label={t("general-settings.disable-grouping-grid")}
|
||||
onChange={this.handleDisableGroupingGridChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.disableGroupingGridHelpText")}
|
||||
/>
|
||||
<Checkbox
|
||||
checked={anonymousAccessEnabled}
|
||||
label={t("general-settings.anonymous-access-enabled")}
|
||||
onChange={this.handleAnonymousAccessEnabledChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.allowAnonymousAccessHelpText")}
|
||||
/>
|
||||
<Checkbox
|
||||
checked={skipFailedAuthenticators}
|
||||
label={t("general-settings.skip-failed-authenticators")}
|
||||
onChange={this.handleSkipFailedAuthenticatorsChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.skipFailedAuthenticatorsHelpText")}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
handleRealmDescriptionChange = (value: string) => {
|
||||
this.props.onChange(true, value, "realmDescription");
|
||||
};
|
||||
handleEnableRepositoryArchiveChange = (value: boolean) => {
|
||||
this.props.onChange(true, value, "enableRepositoryArchive");
|
||||
};
|
||||
handleDisableGroupingGridChange = (value: boolean) => {
|
||||
this.props.onChange(true, value, "disableGroupingGrid");
|
||||
};
|
||||
handleDateFormatChange = (value: string) => {
|
||||
this.props.onChange(true, value, "dateFormat");
|
||||
};
|
||||
handleAnonymousAccessEnabledChange = (value: string) => {
|
||||
this.props.onChange(true, value, "anonymousAccessEnabled");
|
||||
};
|
||||
|
||||
handleSkipFailedAuthenticatorsChange = (value: string) => {
|
||||
this.props.onChange(true, value, "skipFailedAuthenticators");
|
||||
};
|
||||
handlePluginUrlChange = (value: string) => {
|
||||
this.props.onChange(true, value, "pluginUrl");
|
||||
};
|
||||
|
||||
handleEnabledXsrfProtectionChange = (value: boolean) => {
|
||||
this.props.onChange(true, value, "enabledXsrfProtection");
|
||||
};
|
||||
handleDefaultNamespaceStrategyChange = (value: string) => {
|
||||
this.props.onChange(true, value, "defaultNamespaceStrategy");
|
||||
};
|
||||
}
|
||||
|
||||
export default translate("config")(GeneralSettings);
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Checkbox, InputField } from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
realmDescription: string,
|
||||
enableRepositoryArchive: boolean,
|
||||
disableGroupingGrid: boolean,
|
||||
dateFormat: string,
|
||||
anonymousAccessEnabled: boolean,
|
||||
skipFailedAuthenticators: boolean,
|
||||
pluginUrl: string,
|
||||
enabledXsrfProtection: boolean,
|
||||
defaultNamespaceStrategy: string,
|
||||
t: string => string,
|
||||
onChange: (boolean, any, string) => void,
|
||||
hasUpdatePermission: boolean
|
||||
};
|
||||
|
||||
class GeneralSettings extends React.Component<Props> {
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
realmDescription,
|
||||
enableRepositoryArchive,
|
||||
disableGroupingGrid,
|
||||
dateFormat,
|
||||
anonymousAccessEnabled,
|
||||
skipFailedAuthenticators,
|
||||
pluginUrl,
|
||||
enabledXsrfProtection,
|
||||
defaultNamespaceStrategy,
|
||||
hasUpdatePermission
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div class="columns">
|
||||
<div class="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.realm-description")}
|
||||
onChange={this.handleRealmDescriptionChange}
|
||||
value={realmDescription}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.realmDescriptionHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.date-format")}
|
||||
onChange={this.handleDateFormatChange}
|
||||
value={dateFormat}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.dateFormatHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.plugin-url")}
|
||||
onChange={this.handlePluginUrlChange}
|
||||
value={pluginUrl}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.pluginRepositoryHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
<InputField
|
||||
label={t("general-settings.default-namespace-strategy")}
|
||||
onChange={this.handleDefaultNamespaceStrategyChange}
|
||||
value={defaultNamespaceStrategy}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.defaultNameSpaceStrategyHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column is-half">
|
||||
<Checkbox
|
||||
checked={enabledXsrfProtection}
|
||||
label={t("general-settings.enabled-xsrf-protection")}
|
||||
onChange={this.handleEnabledXsrfProtectionChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.enableXsrfProtectionHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
<Checkbox
|
||||
checked={enableRepositoryArchive}
|
||||
label={t("general-settings.enable-repository-archive")}
|
||||
onChange={this.handleEnableRepositoryArchiveChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.enableRepositoryArchiveHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column is-half">
|
||||
<Checkbox
|
||||
checked={disableGroupingGrid}
|
||||
label={t("general-settings.disable-grouping-grid")}
|
||||
onChange={this.handleDisableGroupingGridChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.disableGroupingGridHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div class="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 class="columns">
|
||||
<div class="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>
|
||||
);
|
||||
}
|
||||
|
||||
handleRealmDescriptionChange = (value: string) => {
|
||||
this.props.onChange(true, value, "realmDescription");
|
||||
};
|
||||
handleEnableRepositoryArchiveChange = (value: boolean) => {
|
||||
this.props.onChange(true, value, "enableRepositoryArchive");
|
||||
};
|
||||
handleDisableGroupingGridChange = (value: boolean) => {
|
||||
this.props.onChange(true, value, "disableGroupingGrid");
|
||||
};
|
||||
handleDateFormatChange = (value: string) => {
|
||||
this.props.onChange(true, value, "dateFormat");
|
||||
};
|
||||
handleAnonymousAccessEnabledChange = (value: string) => {
|
||||
this.props.onChange(true, value, "anonymousAccessEnabled");
|
||||
};
|
||||
|
||||
handleSkipFailedAuthenticatorsChange = (value: string) => {
|
||||
this.props.onChange(true, value, "skipFailedAuthenticators");
|
||||
};
|
||||
handlePluginUrlChange = (value: string) => {
|
||||
this.props.onChange(true, value, "pluginUrl");
|
||||
};
|
||||
|
||||
handleEnabledXsrfProtectionChange = (value: boolean) => {
|
||||
this.props.onChange(true, value, "enabledXsrfProtection");
|
||||
};
|
||||
handleDefaultNamespaceStrategyChange = (value: string) => {
|
||||
this.props.onChange(true, value, "defaultNamespaceStrategy");
|
||||
};
|
||||
}
|
||||
|
||||
export default translate("config")(GeneralSettings);
|
||||
|
||||
@@ -1,91 +1,97 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import {
|
||||
InputField,
|
||||
Subtitle,
|
||||
validation as validator
|
||||
} from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
loginAttemptLimit: number,
|
||||
loginAttemptLimitTimeout: number,
|
||||
t: string => string,
|
||||
onChange: (boolean, any, string) => void,
|
||||
hasUpdatePermission: boolean
|
||||
};
|
||||
|
||||
type State = {
|
||||
loginAttemptLimitError: boolean,
|
||||
loginAttemptLimitTimeoutError: boolean
|
||||
};
|
||||
|
||||
class LoginAttempt extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
loginAttemptLimitError: false,
|
||||
loginAttemptLimitTimeoutError: false
|
||||
};
|
||||
}
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
loginAttemptLimit,
|
||||
loginAttemptLimitTimeout,
|
||||
hasUpdatePermission
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Subtitle subtitle={t("login-attempt.name")} />
|
||||
<InputField
|
||||
label={t("login-attempt.login-attempt-limit")}
|
||||
onChange={this.handleLoginAttemptLimitChange}
|
||||
value={loginAttemptLimit}
|
||||
disabled={!hasUpdatePermission}
|
||||
validationError={this.state.loginAttemptLimitError}
|
||||
errorMessage={t("validation.login-attempt-limit-invalid")}
|
||||
helpText={t("help.loginAttemptLimitHelpText")}
|
||||
/>
|
||||
<InputField
|
||||
label={t("login-attempt.login-attempt-limit-timeout")}
|
||||
onChange={this.handleLoginAttemptLimitTimeoutChange}
|
||||
value={loginAttemptLimitTimeout}
|
||||
disabled={!hasUpdatePermission}
|
||||
validationError={this.state.loginAttemptLimitTimeoutError}
|
||||
errorMessage={t("validation.login-attempt-limit-timeout-invalid")}
|
||||
helpText={t("help.loginAttemptLimitTimeoutHelpText")}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
//TODO: set Error in ConfigForm to disable Submit Button!
|
||||
handleLoginAttemptLimitChange = (value: string) => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
loginAttemptLimitError: !validator.isNumberValid(value)
|
||||
});
|
||||
this.props.onChange(
|
||||
validator.isNumberValid(value),
|
||||
value,
|
||||
"loginAttemptLimit"
|
||||
);
|
||||
};
|
||||
|
||||
handleLoginAttemptLimitTimeoutChange = (value: string) => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
loginAttemptLimitTimeoutError: !validator.isNumberValid(value)
|
||||
});
|
||||
this.props.onChange(
|
||||
validator.isNumberValid(value),
|
||||
value,
|
||||
"loginAttemptLimitTimeout"
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export default translate("config")(LoginAttempt);
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import {
|
||||
InputField,
|
||||
Subtitle,
|
||||
validation as validator
|
||||
} from "@scm-manager/ui-components";
|
||||
|
||||
type Props = {
|
||||
loginAttemptLimit: number,
|
||||
loginAttemptLimitTimeout: number,
|
||||
t: string => string,
|
||||
onChange: (boolean, any, string) => void,
|
||||
hasUpdatePermission: boolean
|
||||
};
|
||||
|
||||
type State = {
|
||||
loginAttemptLimitError: boolean,
|
||||
loginAttemptLimitTimeoutError: boolean
|
||||
};
|
||||
|
||||
class LoginAttempt extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
loginAttemptLimitError: false,
|
||||
loginAttemptLimitTimeoutError: false
|
||||
};
|
||||
}
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
loginAttemptLimit,
|
||||
loginAttemptLimitTimeout,
|
||||
hasUpdatePermission
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Subtitle subtitle={t("login-attempt.name")} />
|
||||
<div class="columns">
|
||||
<div class="column is-half">
|
||||
<InputField
|
||||
label={t("login-attempt.login-attempt-limit")}
|
||||
onChange={this.handleLoginAttemptLimitChange}
|
||||
value={loginAttemptLimit}
|
||||
disabled={!hasUpdatePermission}
|
||||
validationError={this.state.loginAttemptLimitError}
|
||||
errorMessage={t("validation.login-attempt-limit-invalid")}
|
||||
helpText={t("help.loginAttemptLimitHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
<InputField
|
||||
label={t("login-attempt.login-attempt-limit-timeout")}
|
||||
onChange={this.handleLoginAttemptLimitTimeoutChange}
|
||||
value={loginAttemptLimitTimeout}
|
||||
disabled={!hasUpdatePermission}
|
||||
validationError={this.state.loginAttemptLimitTimeoutError}
|
||||
errorMessage={t("validation.login-attempt-limit-timeout-invalid")}
|
||||
helpText={t("help.loginAttemptLimitTimeoutHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
//TODO: set Error in ConfigForm to disable Submit Button!
|
||||
handleLoginAttemptLimitChange = (value: string) => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
loginAttemptLimitError: !validator.isNumberValid(value)
|
||||
});
|
||||
this.props.onChange(
|
||||
validator.isNumberValid(value),
|
||||
value,
|
||||
"loginAttemptLimit"
|
||||
);
|
||||
};
|
||||
|
||||
handleLoginAttemptLimitTimeoutChange = (value: string) => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
loginAttemptLimitTimeoutError: !validator.isNumberValid(value)
|
||||
});
|
||||
this.props.onChange(
|
||||
validator.isNumberValid(value),
|
||||
value,
|
||||
"loginAttemptLimitTimeout"
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export default translate("config")(LoginAttempt);
|
||||
|
||||
@@ -1,126 +1,146 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import {
|
||||
Checkbox,
|
||||
InputField,
|
||||
Subtitle,
|
||||
AddEntryToTableField
|
||||
} from "@scm-manager/ui-components";
|
||||
import ProxyExcludesTable from "../table/ProxyExcludesTable";
|
||||
|
||||
type Props = {
|
||||
proxyPassword: string,
|
||||
proxyPort: number,
|
||||
proxyServer: string,
|
||||
proxyUser: string,
|
||||
enableProxy: boolean,
|
||||
proxyExcludes: string[],
|
||||
t: string => string,
|
||||
onChange: (boolean, any, string) => void,
|
||||
hasUpdatePermission: boolean
|
||||
};
|
||||
|
||||
class ProxySettings extends React.Component<Props> {
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
proxyPassword,
|
||||
proxyPort,
|
||||
proxyServer,
|
||||
proxyUser,
|
||||
enableProxy,
|
||||
proxyExcludes,
|
||||
hasUpdatePermission
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Subtitle subtitle={t("proxy-settings.name")} />
|
||||
<Checkbox
|
||||
checked={enableProxy}
|
||||
label={t("proxy-settings.enable-proxy")}
|
||||
onChange={this.handleEnableProxyChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.enableProxyHelpText")}
|
||||
/>
|
||||
<InputField
|
||||
label={t("proxy-settings.proxy-password")}
|
||||
onChange={this.handleProxyPasswordChange}
|
||||
value={proxyPassword}
|
||||
type="password"
|
||||
disabled={!enableProxy || !hasUpdatePermission}
|
||||
helpText={t("help.proxyPasswordHelpText")}
|
||||
/>
|
||||
<InputField
|
||||
label={t("proxy-settings.proxy-port")}
|
||||
value={proxyPort}
|
||||
onChange={this.handleProxyPortChange}
|
||||
disabled={!enableProxy || !hasUpdatePermission}
|
||||
helpText={t("help.proxyPortHelpText")}
|
||||
/>
|
||||
<InputField
|
||||
label={t("proxy-settings.proxy-server")}
|
||||
value={proxyServer}
|
||||
onChange={this.handleProxyServerChange}
|
||||
disabled={!enableProxy || !hasUpdatePermission}
|
||||
helpText={t("help.proxyServerHelpText")}
|
||||
/>
|
||||
<InputField
|
||||
label={t("proxy-settings.proxy-user")}
|
||||
value={proxyUser}
|
||||
onChange={this.handleProxyUserChange}
|
||||
disabled={!enableProxy || !hasUpdatePermission}
|
||||
helpText={t("help.proxyUserHelpText")}
|
||||
/>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
handleProxyPasswordChange = (value: string) => {
|
||||
this.props.onChange(true, value, "proxyPassword");
|
||||
};
|
||||
handleProxyPortChange = (value: string) => {
|
||||
this.props.onChange(true, value, "proxyPort");
|
||||
};
|
||||
handleProxyServerChange = (value: string) => {
|
||||
this.props.onChange(true, value, "proxyServer");
|
||||
};
|
||||
handleProxyUserChange = (value: string) => {
|
||||
this.props.onChange(true, value, "proxyUser");
|
||||
};
|
||||
handleEnableProxyChange = (value: string) => {
|
||||
this.props.onChange(true, value, "enableProxy");
|
||||
};
|
||||
|
||||
addProxyExclude = (proxyExcludeName: string) => {
|
||||
if (this.isProxyExcludeMember(proxyExcludeName)) {
|
||||
return;
|
||||
}
|
||||
this.props.onChange(
|
||||
true,
|
||||
[...this.props.proxyExcludes, proxyExcludeName],
|
||||
"proxyExcludes"
|
||||
);
|
||||
};
|
||||
|
||||
isProxyExcludeMember = (proxyExcludeName: string) => {
|
||||
return this.props.proxyExcludes.includes(proxyExcludeName);
|
||||
};
|
||||
}
|
||||
|
||||
export default translate("config")(ProxySettings);
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import {
|
||||
Checkbox,
|
||||
InputField,
|
||||
Subtitle,
|
||||
AddEntryToTableField
|
||||
} from "@scm-manager/ui-components";
|
||||
import ProxyExcludesTable from "../table/ProxyExcludesTable";
|
||||
|
||||
type Props = {
|
||||
proxyPassword: string,
|
||||
proxyPort: number,
|
||||
proxyServer: string,
|
||||
proxyUser: string,
|
||||
enableProxy: boolean,
|
||||
proxyExcludes: string[],
|
||||
t: string => string,
|
||||
onChange: (boolean, any, string) => void,
|
||||
hasUpdatePermission: boolean
|
||||
};
|
||||
|
||||
class ProxySettings extends React.Component<Props> {
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
proxyPassword,
|
||||
proxyPort,
|
||||
proxyServer,
|
||||
proxyUser,
|
||||
enableProxy,
|
||||
proxyExcludes,
|
||||
hasUpdatePermission
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Subtitle subtitle={t("proxy-settings.name")} />
|
||||
<div class="columns">
|
||||
<div class="column is-full">
|
||||
<Checkbox
|
||||
checked={enableProxy}
|
||||
label={t("proxy-settings.enable-proxy")}
|
||||
onChange={this.handleEnableProxyChange}
|
||||
disabled={!hasUpdatePermission}
|
||||
helpText={t("help.enableProxyHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column is-half">
|
||||
<InputField
|
||||
label={t("proxy-settings.proxy-password")}
|
||||
onChange={this.handleProxyPasswordChange}
|
||||
value={proxyPassword}
|
||||
type="password"
|
||||
disabled={!enableProxy || !hasUpdatePermission}
|
||||
helpText={t("help.proxyPasswordHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
<InputField
|
||||
label={t("proxy-settings.proxy-port")}
|
||||
value={proxyPort}
|
||||
onChange={this.handleProxyPortChange}
|
||||
disabled={!enableProxy || !hasUpdatePermission}
|
||||
helpText={t("help.proxyPortHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column is-half">
|
||||
<InputField
|
||||
label={t("proxy-settings.proxy-server")}
|
||||
value={proxyServer}
|
||||
onChange={this.handleProxyServerChange}
|
||||
disabled={!enableProxy || !hasUpdatePermission}
|
||||
helpText={t("help.proxyServerHelpText")}
|
||||
/>
|
||||
</div>
|
||||
<div class="column is-half">
|
||||
<InputField
|
||||
label={t("proxy-settings.proxy-user")}
|
||||
value={proxyUser}
|
||||
onChange={this.handleProxyUserChange}
|
||||
disabled={!enableProxy || !hasUpdatePermission}
|
||||
helpText={t("help.proxyUserHelpText")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="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>
|
||||
);
|
||||
}
|
||||
|
||||
handleProxyPasswordChange = (value: string) => {
|
||||
this.props.onChange(true, value, "proxyPassword");
|
||||
};
|
||||
handleProxyPortChange = (value: string) => {
|
||||
this.props.onChange(true, value, "proxyPort");
|
||||
};
|
||||
handleProxyServerChange = (value: string) => {
|
||||
this.props.onChange(true, value, "proxyServer");
|
||||
};
|
||||
handleProxyUserChange = (value: string) => {
|
||||
this.props.onChange(true, value, "proxyUser");
|
||||
};
|
||||
handleEnableProxyChange = (value: string) => {
|
||||
this.props.onChange(true, value, "enableProxy");
|
||||
};
|
||||
|
||||
addProxyExclude = (proxyExcludeName: string) => {
|
||||
if (this.isProxyExcludeMember(proxyExcludeName)) {
|
||||
return;
|
||||
}
|
||||
this.props.onChange(
|
||||
true,
|
||||
[...this.props.proxyExcludes, proxyExcludeName],
|
||||
"proxyExcludes"
|
||||
);
|
||||
};
|
||||
|
||||
isProxyExcludeMember = (proxyExcludeName: string) => {
|
||||
return this.props.proxyExcludes.includes(proxyExcludeName);
|
||||
};
|
||||
}
|
||||
|
||||
export default translate("config")(ProxySettings);
|
||||
|
||||
@@ -1,86 +1,86 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Route } from "react-router";
|
||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||
|
||||
import type { Links } from "@scm-manager/ui-types";
|
||||
import { Page, Navigation, NavLink, Section } from "@scm-manager/ui-components";
|
||||
import GlobalConfig from "./GlobalConfig";
|
||||
import type { History } from "history";
|
||||
import {connect} from "react-redux";
|
||||
import {compose} from "redux";
|
||||
import { getLinks } from "../../modules/indexResource";
|
||||
|
||||
type Props = {
|
||||
links: Links,
|
||||
|
||||
// context objects
|
||||
t: string => string,
|
||||
match: any,
|
||||
history: History
|
||||
};
|
||||
|
||||
class Config extends React.Component<Props> {
|
||||
stripEndingSlash = (url: string) => {
|
||||
if (url.endsWith("/")) {
|
||||
return url.substring(0, url.length - 2);
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
matchedUrl = () => {
|
||||
return this.stripEndingSlash(this.props.match.url);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { links, t } = this.props;
|
||||
|
||||
const url = this.matchedUrl();
|
||||
const extensionProps = {
|
||||
links,
|
||||
url
|
||||
};
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<div className="columns">
|
||||
<div className="column is-three-quarters">
|
||||
<Route path={url} exact component={GlobalConfig} />
|
||||
<ExtensionPoint name="config.route"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
</div>
|
||||
<div className="column">
|
||||
<Navigation>
|
||||
<Section label={t("config.navigation-title")}>
|
||||
<NavLink
|
||||
to={`${url}`}
|
||||
label={t("global-config.navigation-label")}
|
||||
/>
|
||||
<ExtensionPoint name="config.navigation"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
</Section>
|
||||
</Navigation>
|
||||
</div>
|
||||
</div>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any) => {
|
||||
const links = getLinks(state);
|
||||
return {
|
||||
links
|
||||
};
|
||||
};
|
||||
|
||||
export default compose(
|
||||
connect(mapStateToProps),
|
||||
translate("config")
|
||||
)(Config);
|
||||
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import { Route } from "react-router";
|
||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||
|
||||
import type { Links } from "@scm-manager/ui-types";
|
||||
import { Page, Navigation, NavLink, Section } from "@scm-manager/ui-components";
|
||||
import GlobalConfig from "./GlobalConfig";
|
||||
import type { History } from "history";
|
||||
import {connect} from "react-redux";
|
||||
import {compose} from "redux";
|
||||
import { getLinks } from "../../modules/indexResource";
|
||||
|
||||
type Props = {
|
||||
links: Links,
|
||||
|
||||
// context objects
|
||||
t: string => string,
|
||||
match: any,
|
||||
history: History
|
||||
};
|
||||
|
||||
class Config extends React.Component<Props> {
|
||||
stripEndingSlash = (url: string) => {
|
||||
if (url.endsWith("/")) {
|
||||
return url.substring(0, url.length - 2);
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
matchedUrl = () => {
|
||||
return this.stripEndingSlash(this.props.match.url);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { links, t } = this.props;
|
||||
|
||||
const url = this.matchedUrl();
|
||||
const extensionProps = {
|
||||
links,
|
||||
url
|
||||
};
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<div className="columns">
|
||||
<div className="column is-three-quarters">
|
||||
<Route path={url} exact component={GlobalConfig} />
|
||||
<ExtensionPoint name="config.route"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
</div>
|
||||
<div className="column is-one-quarter">
|
||||
<Navigation>
|
||||
<Section label={t("config.navigation-title")}>
|
||||
<NavLink
|
||||
to={`${url}`}
|
||||
label={t("global-config.navigation-label")}
|
||||
/>
|
||||
<ExtensionPoint name="config.navigation"
|
||||
props={extensionProps}
|
||||
renderAll={true}
|
||||
/>
|
||||
</Section>
|
||||
</Navigation>
|
||||
</div>
|
||||
</div>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: any) => {
|
||||
const links = getLinks(state);
|
||||
return {
|
||||
links
|
||||
};
|
||||
};
|
||||
|
||||
export default compose(
|
||||
connect(mapStateToProps),
|
||||
translate("config")
|
||||
)(Config);
|
||||
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import GroupRow from "./GroupRow";
|
||||
import type { Group } from "@scm-manager/ui-types";
|
||||
|
||||
type Props = {
|
||||
t: string => string,
|
||||
groups: Group[]
|
||||
};
|
||||
|
||||
class GroupTable extends React.Component<Props> {
|
||||
render() {
|
||||
const { groups, t } = this.props;
|
||||
return (
|
||||
<table className="table is-hoverable is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{t("group.name")}</th>
|
||||
<th className="is-hidden-mobile">{t("group.description")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{groups.map((group, index) => {
|
||||
return <GroupRow key={index} group={group} />;
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("groups")(GroupTable);
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import GroupRow from "./GroupRow";
|
||||
import type { Group } from "@scm-manager/ui-types";
|
||||
|
||||
type Props = {
|
||||
t: string => string,
|
||||
groups: Group[]
|
||||
};
|
||||
|
||||
class GroupTable extends React.Component<Props> {
|
||||
render() {
|
||||
const { groups, t } = this.props;
|
||||
return (
|
||||
<table className="card-table table is-hoverable is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{t("group.name")}</th>
|
||||
<th className="is-hidden-mobile">{t("group.description")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{groups.map((group, index) => {
|
||||
return <GroupRow key={index} group={group} />;
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("groups")(GroupTable);
|
||||
|
||||
@@ -1,67 +1,68 @@
|
||||
//@flow
|
||||
import React from "react";
|
||||
import type { RepositoryGroup } from "@scm-manager/ui-types";
|
||||
import injectSheet from "react-jss";
|
||||
import classNames from "classnames";
|
||||
import RepositoryEntry from "./RepositoryEntry";
|
||||
|
||||
const styles = {
|
||||
pointer: {
|
||||
cursor: "pointer"
|
||||
},
|
||||
repoGroup: {
|
||||
marginBottom: "1em"
|
||||
}
|
||||
};
|
||||
|
||||
type Props = {
|
||||
group: RepositoryGroup,
|
||||
|
||||
// context props
|
||||
classes: any
|
||||
};
|
||||
|
||||
type State = {
|
||||
collapsed: boolean
|
||||
};
|
||||
|
||||
class RepositoryGroupEntry extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
collapsed: false
|
||||
};
|
||||
}
|
||||
|
||||
toggleCollapse = () => {
|
||||
this.setState(prevState => ({
|
||||
collapsed: !prevState.collapsed
|
||||
}));
|
||||
};
|
||||
|
||||
render() {
|
||||
const { group, classes } = this.props;
|
||||
const { collapsed } = this.state;
|
||||
|
||||
const icon = collapsed ? "fa-angle-right" : "fa-angle-down";
|
||||
let content = null;
|
||||
if (!collapsed) {
|
||||
content = group.repositories.map((repository, index) => {
|
||||
return <RepositoryEntry repository={repository} key={index} />;
|
||||
});
|
||||
}
|
||||
return (
|
||||
<div className={classes.repoGroup}>
|
||||
<h2>
|
||||
<span className={classes.pointer} onClick={this.toggleCollapse}>
|
||||
<i className={classNames("fa", icon)} /> {group.name}
|
||||
</span>
|
||||
</h2>
|
||||
<hr />
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default injectSheet(styles)(RepositoryGroupEntry);
|
||||
//@flow
|
||||
import React from "react";
|
||||
import type { RepositoryGroup } from "@scm-manager/ui-types";
|
||||
import injectSheet from "react-jss";
|
||||
import classNames from "classnames";
|
||||
import RepositoryEntry from "./RepositoryEntry";
|
||||
|
||||
const styles = {
|
||||
pointer: {
|
||||
cursor: "pointer",
|
||||
fontSize: "1.5rem"
|
||||
},
|
||||
repoGroup: {
|
||||
marginBottom: "1em"
|
||||
}
|
||||
};
|
||||
|
||||
type Props = {
|
||||
group: RepositoryGroup,
|
||||
|
||||
// context props
|
||||
classes: any
|
||||
};
|
||||
|
||||
type State = {
|
||||
collapsed: boolean
|
||||
};
|
||||
|
||||
class RepositoryGroupEntry extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
collapsed: false
|
||||
};
|
||||
}
|
||||
|
||||
toggleCollapse = () => {
|
||||
this.setState(prevState => ({
|
||||
collapsed: !prevState.collapsed
|
||||
}));
|
||||
};
|
||||
|
||||
render() {
|
||||
const { group, classes } = this.props;
|
||||
const { collapsed } = this.state;
|
||||
|
||||
const icon = collapsed ? "fa-angle-right" : "fa-angle-down";
|
||||
let content = null;
|
||||
if (!collapsed) {
|
||||
content = group.repositories.map((repository, index) => {
|
||||
return <RepositoryEntry repository={repository} key={index} />;
|
||||
});
|
||||
}
|
||||
return (
|
||||
<div className={classes.repoGroup}>
|
||||
<h2>
|
||||
<span className={classes.pointer} onClick={this.toggleCollapse}>
|
||||
<i className={classNames("fa", icon)} /> {group.name}
|
||||
</span>
|
||||
</h2>
|
||||
<hr />
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default injectSheet(styles)(RepositoryGroupEntry);
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import type { User } from "@scm-manager/ui-types";
|
||||
|
||||
type Props = {
|
||||
user: User
|
||||
};
|
||||
|
||||
export default class UserRow extends React.Component<Props> {
|
||||
renderLink(to: string, label: string) {
|
||||
return <Link to={to}>{label}</Link>;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { user } = this.props;
|
||||
const to = `/user/${user.name}`;
|
||||
return (
|
||||
<tr>
|
||||
<td className="is-hidden-mobile">{this.renderLink(to, user.name)}</td>
|
||||
<td>{this.renderLink(to, user.displayName)}</td>
|
||||
<td>
|
||||
<a href={`mailto: ${user.mail}`}>{user.mail}</a>
|
||||
</td>
|
||||
<td className="is-hidden-mobile">
|
||||
<input type="checkbox" id="admin" checked={user.admin} readOnly />
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import type { User } from "@scm-manager/ui-types";
|
||||
|
||||
type Props = {
|
||||
user: User
|
||||
};
|
||||
|
||||
export default class UserRow extends React.Component<Props> {
|
||||
renderLink(to: string, label: string) {
|
||||
return <Link to={to}>{label}</Link>;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { user } = this.props;
|
||||
const to = `/user/${user.name}`;
|
||||
return (
|
||||
<tr>
|
||||
<td className="is-hidden-mobile">{this.renderLink(to, user.name)}</td>
|
||||
<td>{this.renderLink(to, user.displayName)}</td>
|
||||
<td>
|
||||
<a href={`mailto: ${user.mail}`}>{user.mail}</a>
|
||||
</td>
|
||||
<td className="is-hidden-mobile">
|
||||
<input type="checkbox" id="admin" checked={user.admin} readOnly />
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,37 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import UserRow from "./UserRow";
|
||||
import type { User } from "@scm-manager/ui-types";
|
||||
|
||||
type Props = {
|
||||
t: string => string,
|
||||
users: User[]
|
||||
};
|
||||
|
||||
class UserTable extends React.Component<Props> {
|
||||
render() {
|
||||
const { users, t } = this.props;
|
||||
return (
|
||||
<table className="table is-hoverable is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="is-hidden-mobile">{t("user.name")}</th>
|
||||
<th>{t("user.displayName")}</th>
|
||||
<th>{t("user.mail")}</th>
|
||||
<th className="is-hidden-mobile">{t("user.admin")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.map((user, index) => {
|
||||
return <UserRow key={index} user={user} />;
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("users")(UserTable);
|
||||
// @flow
|
||||
import React from "react";
|
||||
import { translate } from "react-i18next";
|
||||
import UserRow from "./UserRow";
|
||||
import type { User } from "@scm-manager/ui-types";
|
||||
|
||||
type Props = {
|
||||
t: string => string,
|
||||
users: User[]
|
||||
};
|
||||
|
||||
;
|
||||
|
||||
class UserTable extends React.Component<Props> {
|
||||
render() {
|
||||
const { users, t } = this.props;
|
||||
return (
|
||||
<table className="card-table table is-hoverable is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="is-hidden-mobile">{t("user.name")}</th>
|
||||
<th>{t("user.displayName")}</th>
|
||||
<th>{t("user.mail")}</th>
|
||||
<th className="is-hidden-mobile">{t("user.admin")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.map((user, index) => {
|
||||
return <UserRow key={index} user={user} />;
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate("users")(UserTable);
|
||||
@@ -1,143 +1,143 @@
|
||||
// @flow
|
||||
import React from "react";
|
||||
import type { History } from "history";
|
||||
import { connect } from "react-redux";
|
||||
import { translate } from "react-i18next";
|
||||
|
||||
import {
|
||||
fetchUsersByPage,
|
||||
fetchUsersByLink,
|
||||
getUsersFromState,
|
||||
selectListAsCollection,
|
||||
isPermittedToCreateUsers,
|
||||
isFetchUsersPending,
|
||||
getFetchUsersFailure
|
||||
} from "../modules/users";
|
||||
|
||||
import { Page, Paginator } from "@scm-manager/ui-components";
|
||||
import { UserTable } from "./../components/table";
|
||||
import type { User, PagedCollection } from "@scm-manager/ui-types";
|
||||
import CreateUserButton from "../components/buttons/CreateUserButton";
|
||||
import { getUsersLink } from "../../modules/indexResource";
|
||||
|
||||
type Props = {
|
||||
users: User[],
|
||||
loading: boolean,
|
||||
error: Error,
|
||||
canAddUsers: boolean,
|
||||
list: PagedCollection,
|
||||
page: number,
|
||||
usersLink: string,
|
||||
|
||||
// context objects
|
||||
t: string => string,
|
||||
history: History,
|
||||
|
||||
// dispatch functions
|
||||
fetchUsersByPage: (link: string, page: number) => void,
|
||||
fetchUsersByLink: (link: string) => void
|
||||
};
|
||||
|
||||
class Users extends React.Component<Props> {
|
||||
componentDidMount() {
|
||||
this.props.fetchUsersByPage(this.props.usersLink, this.props.page);
|
||||
}
|
||||
|
||||
onPageChange = (link: string) => {
|
||||
this.props.fetchUsersByLink(link);
|
||||
};
|
||||
|
||||
/**
|
||||
* reflect page transitions in the uri
|
||||
*/
|
||||
componentDidUpdate() {
|
||||
const { page, list } = this.props;
|
||||
if (list && (list.page || list.page === 0)) {
|
||||
// backend starts paging by 0
|
||||
const statePage: number = list.page + 1;
|
||||
if (page !== statePage) {
|
||||
this.props.history.push(`/users/${statePage}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { users, loading, error, t } = this.props;
|
||||
return (
|
||||
<Page
|
||||
title={t("users.title")}
|
||||
subtitle={t("users.subtitle")}
|
||||
loading={loading || !users}
|
||||
error={error}
|
||||
>
|
||||
<UserTable users={users} />
|
||||
{this.renderPaginator()}
|
||||
{this.renderCreateButton()}
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
renderPaginator() {
|
||||
const { list } = this.props;
|
||||
if (list) {
|
||||
return <Paginator collection={list} onPageChange={this.onPageChange} />;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
renderCreateButton() {
|
||||
if (this.props.canAddUsers) {
|
||||
return <CreateUserButton />;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getPageFromProps = props => {
|
||||
let page = props.match.params.page;
|
||||
if (page) {
|
||||
page = parseInt(page, 10);
|
||||
} else {
|
||||
page = 1;
|
||||
}
|
||||
return page;
|
||||
};
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const users = getUsersFromState(state);
|
||||
const loading = isFetchUsersPending(state);
|
||||
const error = getFetchUsersFailure(state);
|
||||
|
||||
const usersLink = getUsersLink(state);
|
||||
|
||||
const page = getPageFromProps(ownProps);
|
||||
const canAddUsers = isPermittedToCreateUsers(state);
|
||||
const list = selectListAsCollection(state);
|
||||
|
||||
return {
|
||||
users,
|
||||
loading,
|
||||
error,
|
||||
canAddUsers,
|
||||
list,
|
||||
page,
|
||||
usersLink
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
fetchUsersByPage: (link: string, page: number) => {
|
||||
dispatch(fetchUsersByPage(link, page));
|
||||
},
|
||||
fetchUsersByLink: (link: string) => {
|
||||
dispatch(fetchUsersByLink(link));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(translate("users")(Users));
|
||||
// @flow
|
||||
import React from "react";
|
||||
import type { History } from "history";
|
||||
import { connect } from "react-redux";
|
||||
import { translate } from "react-i18next";
|
||||
|
||||
import {
|
||||
fetchUsersByPage,
|
||||
fetchUsersByLink,
|
||||
getUsersFromState,
|
||||
selectListAsCollection,
|
||||
isPermittedToCreateUsers,
|
||||
isFetchUsersPending,
|
||||
getFetchUsersFailure
|
||||
} from "../modules/users";
|
||||
|
||||
import { Page, Paginator } from "@scm-manager/ui-components";
|
||||
import { UserTable } from "./../components/table";
|
||||
import type { User, PagedCollection } from "@scm-manager/ui-types";
|
||||
import CreateUserButton from "../components/buttons/CreateUserButton";
|
||||
import { getUsersLink } from "../../modules/indexResource";
|
||||
|
||||
type Props = {
|
||||
users: User[],
|
||||
loading: boolean,
|
||||
error: Error,
|
||||
canAddUsers: boolean,
|
||||
list: PagedCollection,
|
||||
page: number,
|
||||
usersLink: string,
|
||||
|
||||
// context objects
|
||||
t: string => string,
|
||||
history: History,
|
||||
|
||||
// dispatch functions
|
||||
fetchUsersByPage: (link: string, page: number) => void,
|
||||
fetchUsersByLink: (link: string) => void
|
||||
};
|
||||
|
||||
class Users extends React.Component<Props> {
|
||||
componentDidMount() {
|
||||
this.props.fetchUsersByPage(this.props.usersLink, this.props.page);
|
||||
}
|
||||
|
||||
onPageChange = (link: string) => {
|
||||
this.props.fetchUsersByLink(link);
|
||||
};
|
||||
|
||||
/**
|
||||
* reflect page transitions in the uri
|
||||
*/
|
||||
componentDidUpdate() {
|
||||
const { page, list } = this.props;
|
||||
if (list && (list.page || list.page === 0)) {
|
||||
// backend starts paging by 0
|
||||
const statePage: number = list.page + 1;
|
||||
if (page !== statePage) {
|
||||
this.props.history.push(`/users/${statePage}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { users, loading, error, t } = this.props;
|
||||
return (
|
||||
<Page
|
||||
title={t("users.title")}
|
||||
subtitle={t("users.subtitle")}
|
||||
loading={loading || !users}
|
||||
error={error}
|
||||
>
|
||||
<UserTable users={users} />
|
||||
{this.renderPaginator()}
|
||||
{this.renderCreateButton()}
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
renderPaginator() {
|
||||
const { list } = this.props;
|
||||
if (list) {
|
||||
return <Paginator collection={list} onPageChange={this.onPageChange} />;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
renderCreateButton() {
|
||||
if (this.props.canAddUsers) {
|
||||
return <CreateUserButton />;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getPageFromProps = props => {
|
||||
let page = props.match.params.page;
|
||||
if (page) {
|
||||
page = parseInt(page, 10);
|
||||
} else {
|
||||
page = 1;
|
||||
}
|
||||
return page;
|
||||
};
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const users = getUsersFromState(state);
|
||||
const loading = isFetchUsersPending(state);
|
||||
const error = getFetchUsersFailure(state);
|
||||
|
||||
const usersLink = getUsersLink(state);
|
||||
|
||||
const page = getPageFromProps(ownProps);
|
||||
const canAddUsers = isPermittedToCreateUsers(state);
|
||||
const list = selectListAsCollection(state);
|
||||
|
||||
return {
|
||||
users,
|
||||
loading,
|
||||
error,
|
||||
canAddUsers,
|
||||
list,
|
||||
page,
|
||||
usersLink
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
fetchUsersByPage: (link: string, page: number) => {
|
||||
dispatch(fetchUsersByPage(link, page));
|
||||
},
|
||||
fetchUsersByLink: (link: string) => {
|
||||
dispatch(fetchUsersByLink(link));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(translate("users")(Users));
|
||||
|
||||
Reference in New Issue
Block a user