diff --git a/scm-ui/public/locales/en/config.json b/scm-ui/public/locales/en/config.json index df2a12a6dc..53d41e682d 100644 --- a/scm-ui/public/locales/en/config.json +++ b/scm-ui/public/locales/en/config.json @@ -26,8 +26,17 @@ "force-base-url": "Force Base URL" }, "admin-settings": { + "name": "Administration Settings", "admin-groups": "Admin Groups", - "admin-user": "Admin Users" + "admin-users": "Admin Users", + "remove-group-button": "Remove Admin Group", + "remove-user-button": "Remove Admin User", + "add-group-error": "The group name you want to add is not valid", + "add-group-textfield": "Add group you want to add to admin groups here", + "add-group-button": "Add Admin Group", + "add-user-error": "The user name you want to add is not valid", + "add-user-textfield": "Add user you want to add to admin users here", + "add-user-button": "Add Admin User" }, "general-settings": { "realm-description": "Realm Description", diff --git a/scm-ui/src/config/components/buttons/RemoveAdminGroupButton.js b/scm-ui/src/config/components/buttons/RemoveAdminGroupButton.js new file mode 100644 index 0000000000..c7d8f8d85a --- /dev/null +++ b/scm-ui/src/config/components/buttons/RemoveAdminGroupButton.js @@ -0,0 +1,34 @@ +//@flow +import React from "react"; +import { DeleteButton } from "../../../components/buttons"; +import { translate } from "react-i18next"; +import classNames from "classnames"; + +type Props = { + t: string => string, + groupname: string, + removeGroup: string => void +}; + +type State = {}; + + + +class RemoveAdminGroupButton extends React.Component { + render() { + const { t , groupname, removeGroup} = this.props; + return ( +
+ { + event.preventDefault(); + removeGroup(groupname); + }} + /> +
+ ); + } +} + +export default translate("config")(RemoveAdminGroupButton); diff --git a/scm-ui/src/config/components/buttons/RemoveAdminUserButton.js b/scm-ui/src/config/components/buttons/RemoveAdminUserButton.js new file mode 100644 index 0000000000..6bdf06cd28 --- /dev/null +++ b/scm-ui/src/config/components/buttons/RemoveAdminUserButton.js @@ -0,0 +1,34 @@ +//@flow +import React from "react"; +import { DeleteButton } from "../../../components/buttons"; +import { translate } from "react-i18next"; +import classNames from "classnames"; + +type Props = { + t: string => string, + username: string, + removeUser: string => void +}; + +type State = {}; + + + +class RemoveAdminUserButton extends React.Component { + render() { + const { t , username, removeUser} = this.props; + return ( +
+ { + event.preventDefault(); + removeUser(username); + }} + /> +
+ ); + } +} + +export default translate("config")(RemoveAdminUserButton); diff --git a/scm-ui/src/config/components/fields/AddAdminGroupField.js b/scm-ui/src/config/components/fields/AddAdminGroupField.js new file mode 100644 index 0000000000..ed694355d8 --- /dev/null +++ b/scm-ui/src/config/components/fields/AddAdminGroupField.js @@ -0,0 +1,71 @@ +//@flow +import React from "react"; + +import { translate } from "react-i18next"; +import { AddButton } from "../../../components/buttons"; +import InputField from "../../../components/forms/InputField"; + +type Props = { + t: string => string, + addGroup: string => void +}; + +type State = { + groupToAdd: string, + //validationError: boolean +}; + +class AddAdminGroupField extends React.Component { + constructor(props) { + super(props); + this.state = { + groupToAdd: "", + //validationError: false + }; + } + + render() { + const { t } = this.props; + return ( +
+ + +
+ ); + } + + addButtonClicked = (event: Event) => { + event.preventDefault(); + this.appendGroup(); + }; + + appendGroup = () => { + const { groupToAdd } = this.state; + //if (isMemberNameValid(memberToAdd)) { + this.props.addGroup(groupToAdd); + this.setState({ ...this.state, groupToAdd: "" }); + // } + }; + + handleAddGroupChange = (groupname: string) => { + this.setState({ + ...this.state, + groupToAdd: groupname, + //validationError: membername.length > 0 && !isMemberNameValid(membername) + }); + }; +} + +export default translate("config")(AddAdminGroupField); diff --git a/scm-ui/src/config/components/fields/AddAdminUserField.js b/scm-ui/src/config/components/fields/AddAdminUserField.js new file mode 100644 index 0000000000..116144ff3c --- /dev/null +++ b/scm-ui/src/config/components/fields/AddAdminUserField.js @@ -0,0 +1,71 @@ +//@flow +import React from "react"; + +import { translate } from "react-i18next"; +import { AddButton } from "../../../components/buttons"; +import InputField from "../../../components/forms/InputField"; + +type Props = { + t: string => string, + addUser: string => void +}; + +type State = { + userToAdd: string, + //validationError: boolean +}; + +class AddAdminUserField extends React.Component { + constructor(props) { + super(props); + this.state = { + userToAdd: "", + //validationError: false + }; + } + + render() { + const { t } = this.props; + return ( +
+ + +
+ ); + } + + addButtonClicked = (event: Event) => { + event.preventDefault(); + this.appendUser(); + }; + + appendUser = () => { + const { userToAdd } = this.state; + //if (isMemberNameValid(memberToAdd)) { + this.props.addUser(userToAdd); + this.setState({ ...this.state, userToAdd: "" }); + // } + }; + + handleAddUserChange = (username: string) => { + this.setState({ + ...this.state, + userToAdd: username, + //validationError: membername.length > 0 && !isMemberNameValid(membername) + }); + }; +} + +export default translate("config")(AddAdminUserField); diff --git a/scm-ui/src/config/components/form/AdminSettings.js b/scm-ui/src/config/components/form/AdminSettings.js index 5079addca1..bcc6efbbfe 100644 --- a/scm-ui/src/config/components/form/AdminSettings.js +++ b/scm-ui/src/config/components/form/AdminSettings.js @@ -1,8 +1,12 @@ // @flow import React from "react"; import { translate } from "react-i18next"; -import { Checkbox, InputField } from "../../../components/forms/index"; import Subtitle from "../../../components/layout/Subtitle"; +import AdminGroupTable from "../table/AdminGroupTable"; +import ProxySettings from "./ProxySettings"; +import AdminUserTable from "../table/AdminUserTable"; +import AddAdminGroupField from "../fields/AddAdminGroupField"; +import AddAdminUserField from "../fields/AddAdminUserField"; type Props = { adminGroups: string[], @@ -13,17 +17,58 @@ type Props = { //TODO: Einbauen! class AdminSettings extends React.Component { render() { - const { - t, - adminGroups, - adminUsers - } = this.props; + const { t, adminGroups, adminUsers } = this.props; return ( - null +
+ + + this.props.onChange(isValid, changedValue, name) + } + /> + + + this.props.onChange(isValid, changedValue, name) + } + /> + +
); } + 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); diff --git a/scm-ui/src/config/components/form/ConfigForm.js b/scm-ui/src/config/components/form/ConfigForm.js index ac7325e6fc..ec75f3f579 100644 --- a/scm-ui/src/config/components/form/ConfigForm.js +++ b/scm-ui/src/config/components/form/ConfigForm.js @@ -6,12 +6,14 @@ import type { Config } from "../../types/Config"; import ProxySettings from "./ProxySettings"; import GeneralSettings from "./GeneralSettings"; import BaseUrlSettings from "./BaseUrlSettings"; +import AdminSettings from "./AdminSettings"; type Props = { submitForm: Config => void, config?: Config, loading?: boolean, - t: string => string + t: string => string, + configUpdatePermission: boolean }; type State = { @@ -85,6 +87,7 @@ class ConfigForm extends React.Component { this.onChange(isValid, changedValue, name) } /> +
{ this.onChange(isValid, changedValue, name) } /> +
+ + this.onChange(isValid, changedValue, name) + } + /> +
{ this.onChange(isValid, changedValue, name) } /> +
string, + onChange: (boolean, any, string) => void +}; + +type State = {}; + +class AdminGroupTable extends React.Component { + render() { + const { t } = this.props; + return ( +
+ + + + {this.props.adminGroups.map(group => { + return ( + + + + + ); + })} + +
{group} + +
+
+ ); + } + + removeGroup = (groupname: string) => { + const newGroups = this.props.adminGroups.filter(name => name !== groupname); + this.props.onChange(true, newGroups, "adminGroups"); + }; +} + +export default translate("config")(AdminGroupTable); diff --git a/scm-ui/src/config/components/table/AdminUserTable.js b/scm-ui/src/config/components/table/AdminUserTable.js new file mode 100644 index 0000000000..8f1cbe11c4 --- /dev/null +++ b/scm-ui/src/config/components/table/AdminUserTable.js @@ -0,0 +1,47 @@ +//@flow +import React from "react"; +import { translate } from "react-i18next"; +import RemoveAdminUserButton from "../buttons/RemoveAdminUserButton"; + +type Props = { + adminUsers: string[], + t: string => string, + onChange: (boolean, any, string) => void +}; + +type State = {}; + +class AdminUserTable extends React.Component { + render() { + const { t } = this.props; + return ( +
+ + + + {this.props.adminUsers.map(user => { + return ( + + + + + ); + })} + +
{user} + +
+
+ ); + } + + removeUser = (username: string) => { + const newUsers = this.props.adminUsers.filter(name => name !== username); + this.props.onChange(true, newUsers, "adminUsers"); + }; +} + +export default translate("config")(AdminUserTable); diff --git a/scm-ui/src/config/containers/GlobalConfig.js b/scm-ui/src/config/containers/GlobalConfig.js index a6da5f41bf..56e0a06c9b 100644 --- a/scm-ui/src/config/containers/GlobalConfig.js +++ b/scm-ui/src/config/containers/GlobalConfig.js @@ -7,7 +7,8 @@ import { isFetchConfigPending, getConfig, modifyConfig, - isModifyConfigPending + isModifyConfigPending, + getConfigUpdatePermission } from "../modules/config"; import connect from "react-redux/es/connect/connect"; import ErrorPage from "../../components/ErrorPage"; @@ -21,6 +22,7 @@ type Props = { loading: boolean, error: Error, config: Config, + configUpdatePermission: boolean, // dispatch functions modifyConfig: (config: User, callback?: () => void) => void, // context objects @@ -31,6 +33,7 @@ type Props = { class GlobalConfig extends React.Component { configModified = (config: Config) => () => { + this.props.fetchConfig(); this.props.history.push(`/config`); }; @@ -39,11 +42,12 @@ class GlobalConfig extends React.Component { } modifyConfig = (config: Config) => { + console.log(config); this.props.modifyConfig(config, this.configModified(config)); }; render() { - const { t, error, loading, config } = this.props; + const { t, error, loading, config, configUpdatePermission } = this.props; if (error) { return ( @@ -51,6 +55,7 @@ class GlobalConfig extends React.Component { title={t("global-config.error-title")} subtitle={t("global-config.error-subtitle")} error={error} + configUpdatePermission={configUpdatePermission} /> ); } @@ -86,11 +91,13 @@ const mapStateToProps = state => { const loading = isFetchConfigPending(state) || isModifyConfigPending(state); //TODO: Button lädt so nicht, sondern gesamte Seite const error = getFetchConfigFailure(state); const config = getConfig(state); + const configUpdatePermission = getConfigUpdatePermission(state); return { loading, error, - config + config, + configUpdatePermission }; };