From f752fdbcc6ad929ea72a31683555a0f4fbcdd6a1 Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Wed, 2 Jan 2019 14:06:09 +0100 Subject: [PATCH 1/6] implemented success banner for config changes --- .../ui-components/src/config/Configuration.js | 67 ++++++++++++------- scm-ui/public/locales/en/config.json | 1 + scm-ui/src/config/containers/GlobalConfig.js | 31 ++++++++- 3 files changed, 74 insertions(+), 25 deletions(-) diff --git a/scm-ui-components/packages/ui-components/src/config/Configuration.js b/scm-ui-components/packages/ui-components/src/config/Configuration.js index 07b68f39a6..415dcb5f11 100644 --- a/scm-ui-components/packages/ui-components/src/config/Configuration.js +++ b/scm-ui-components/packages/ui-components/src/config/Configuration.js @@ -2,12 +2,7 @@ import React from "react"; import { translate } from "react-i18next"; import type { Links } from "@scm-manager/ui-types"; -import { - apiClient, - SubmitButton, - Loading, - ErrorNotification -} from "../"; +import { apiClient, SubmitButton, Loading, ErrorNotification } from "../"; type RenderProps = { readOnly: boolean, @@ -20,10 +15,10 @@ type Props = { render: (props: RenderProps) => any, // ??? // context props - t: (string) => string + t: string => string }; -type ConfigurationType = { +type ConfigurationType = { _links: Links } & Object; @@ -32,6 +27,7 @@ type State = { fetching: boolean, modifying: boolean, contentType?: string, + configChanged: boolean, configuration?: ConfigurationType, modifiedConfiguration?: ConfigurationType, @@ -43,12 +39,12 @@ type State = { * synchronizing the configuration with the backend. */ class Configuration extends React.Component { - constructor(props: Props) { super(props); this.state = { fetching: true, modifying: false, + configChanged: false, valid: false }; } @@ -56,7 +52,8 @@ class Configuration extends React.Component { componentDidMount() { const { link } = this.props; - apiClient.get(link) + apiClient + .get(link) .then(this.captureContentType) .then(response => response.json()) .then(this.loadConfig) @@ -119,19 +116,39 @@ class Configuration extends React.Component { this.setState({ modifying: true }); - const {modifiedConfiguration} = this.state; + const { modifiedConfiguration } = this.state; - apiClient.put(this.getModificationUrl(), modifiedConfiguration, this.getContentType()) - .then(() => this.setState({ modifying: false })) + apiClient + .put( + this.getModificationUrl(), + modifiedConfiguration, + this.getContentType() + ) + .then(() => this.setState({ modifying: false, configChanged: true })) .catch(this.handleError); }; + renderConfigChangedNotification = () => { + if (this.state.configChanged) { + return ( +
+
+ ); + } + return null; + }; + render() { const { t } = this.props; const { fetching, error, configuration, modifying, valid } = this.state; if (error) { - return ; + return ; } else if (fetching || !configuration) { return ; } else { @@ -144,19 +161,21 @@ class Configuration extends React.Component { }; return ( -
- { this.props.render(renderProps) } -
- - + <> + {this.renderConfigChangedNotification()} +
+ {this.props.render(renderProps)} +
+ + + ); } } - } export default translate("config")(Configuration); diff --git a/scm-ui/public/locales/en/config.json b/scm-ui/public/locales/en/config.json index de02006e79..6f72904dcc 100644 --- a/scm-ui/public/locales/en/config.json +++ b/scm-ui/public/locales/en/config.json @@ -10,6 +10,7 @@ }, "config-form": { "submit": "Submit", + "submit-success-notification": "Configuration changed!", "no-permission-notification": "Please note: You do not have the permission to edit the config!" }, "proxy-settings": { diff --git a/scm-ui/src/config/containers/GlobalConfig.js b/scm-ui/src/config/containers/GlobalConfig.js index 6046aa4a09..71be3fdd7f 100644 --- a/scm-ui/src/config/containers/GlobalConfig.js +++ b/scm-ui/src/config/containers/GlobalConfig.js @@ -34,7 +34,19 @@ type Props = { t: string => string }; -class GlobalConfig extends React.Component { +type State = { + configChanged: boolean +}; + +class GlobalConfig extends React.Component { + constructor(props: Props) { + super(props); + + this.state = { + configChanged: false + }; + } + componentDidMount() { this.props.configReset(); this.props.fetchConfig(this.props.configLink); @@ -42,6 +54,22 @@ class GlobalConfig extends React.Component { modifyConfig = (config: Config) => { this.props.modifyConfig(config); + this.setState({ configChanged: true }); + }; + + renderConfigChangedNotification = () => { + if (this.state.configChanged) { + return ( +
+
+ ); + } + return null; }; render() { @@ -64,6 +92,7 @@ class GlobalConfig extends React.Component { return (
+ {this.renderConfigChangedNotification()} <ConfigForm submitForm={config => this.modifyConfig(config)} config={config} From fc4ed8036b99ab4d18efce224daf17fd6b37fef5 Mon Sep 17 00:00:00 2001 From: Florian Scholdei <florian.scholdei@cloudogu.com> Date: Wed, 2 Jan 2019 14:24:57 +0100 Subject: [PATCH 2/6] disabled button after successful change --- .../packages/ui-components/src/config/Configuration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-ui-components/packages/ui-components/src/config/Configuration.js b/scm-ui-components/packages/ui-components/src/config/Configuration.js index 415dcb5f11..0eb6f6ffc2 100644 --- a/scm-ui-components/packages/ui-components/src/config/Configuration.js +++ b/scm-ui-components/packages/ui-components/src/config/Configuration.js @@ -124,7 +124,7 @@ class Configuration extends React.Component<Props, State> { modifiedConfiguration, this.getContentType() ) - .then(() => this.setState({ modifying: false, configChanged: true })) + .then(() => this.setState({ modifying: false, configChanged: true, valid: false })) .catch(this.handleError); }; From 3c8379bbf43c3d4b6117c7c622b3f70d7b7b24f0 Mon Sep 17 00:00:00 2001 From: Florian Scholdei <florian.scholdei@cloudogu.com> Date: Wed, 2 Jan 2019 14:37:25 +0100 Subject: [PATCH 3/6] disabled button after successful change for global config --- scm-ui/src/config/components/form/ConfigForm.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scm-ui/src/config/components/form/ConfigForm.js b/scm-ui/src/config/components/form/ConfigForm.js index f5bd6531b5..370925eee9 100644 --- a/scm-ui/src/config/components/form/ConfigForm.js +++ b/scm-ui/src/config/components/form/ConfigForm.js @@ -23,7 +23,8 @@ type State = { error: { loginAttemptLimitTimeout: boolean, loginAttemptLimit: boolean - } + }, + valid: boolean }; class ConfigForm extends React.Component<Props, State> { @@ -59,7 +60,8 @@ class ConfigForm extends React.Component<Props, State> { error: { loginAttemptLimitTimeout: false, loginAttemptLimit: false - } + }, + valid: false }; } @@ -156,7 +158,7 @@ class ConfigForm extends React.Component<Props, State> { <SubmitButton loading={loading} label={t("config-form.submit")} - disabled={!configUpdatePermission || this.hasError()} + disabled={!configUpdatePermission || this.hasError() || !this.state.valid} /> </form> ); @@ -172,7 +174,8 @@ class ConfigForm extends React.Component<Props, State> { error: { ...this.state.error, [name]: !isValid - } + }, + valid: true }); }; From f96b16bda4588dc26c8507ddb480779f675a9574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maren=20S=C3=BCwer?= <maren.suewer@cloudogu.com> Date: Fri, 11 Jan 2019 08:24:47 +0100 Subject: [PATCH 4/6] make success message more intuitive --- scm-ui/public/locales/en/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-ui/public/locales/en/config.json b/scm-ui/public/locales/en/config.json index 6f72904dcc..1a33da8c8b 100644 --- a/scm-ui/public/locales/en/config.json +++ b/scm-ui/public/locales/en/config.json @@ -10,7 +10,7 @@ }, "config-form": { "submit": "Submit", - "submit-success-notification": "Configuration changed!", + "submit-success-notification": "Configuration changed successfully!", "no-permission-notification": "Please note: You do not have the permission to edit the config!" }, "proxy-settings": { From 7fc8c1a9059eaeb43022264eafe3ca29aaf14f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maren=20S=C3=BCwer?= <maren.suewer@cloudogu.com> Date: Fri, 11 Jan 2019 08:31:00 +0100 Subject: [PATCH 5/6] disable button after submit-method is triggered and rename state 'valid' to 'changed' as it does not check validity --- scm-ui/src/config/components/form/ConfigForm.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/scm-ui/src/config/components/form/ConfigForm.js b/scm-ui/src/config/components/form/ConfigForm.js index 370925eee9..dc3f20c95d 100644 --- a/scm-ui/src/config/components/form/ConfigForm.js +++ b/scm-ui/src/config/components/form/ConfigForm.js @@ -24,7 +24,7 @@ type State = { loginAttemptLimitTimeout: boolean, loginAttemptLimit: boolean }, - valid: boolean + changed: boolean }; class ConfigForm extends React.Component<Props, State> { @@ -61,7 +61,7 @@ class ConfigForm extends React.Component<Props, State> { loginAttemptLimitTimeout: false, loginAttemptLimit: false }, - valid: false + changed: false }; } @@ -77,6 +77,9 @@ class ConfigForm extends React.Component<Props, State> { submit = (event: Event) => { event.preventDefault(); + this.setState({ + changed: false + }); this.props.submitForm(this.state.config); }; @@ -158,7 +161,9 @@ class ConfigForm extends React.Component<Props, State> { <SubmitButton loading={loading} label={t("config-form.submit")} - disabled={!configUpdatePermission || this.hasError() || !this.state.valid} + disabled={ + !configUpdatePermission || this.hasError() || !this.state.changed + } /> </form> ); @@ -175,7 +180,7 @@ class ConfigForm extends React.Component<Props, State> { ...this.state.error, [name]: !isValid }, - valid: true + changed: true }); }; From 209076c80e842019f0b4438d113082dc2397cbb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maren=20S=C3=BCwer?= <maren.suewer@cloudogu.com> Date: Fri, 11 Jan 2019 08:27:54 +0000 Subject: [PATCH 6/6] Close branch feature/success_banner_for_config