From 554d730f270dec912b061a3078a2da5774c57ebf Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Wed, 1 May 2019 19:02:15 +0200 Subject: [PATCH 1/4] Add adminPermissions check to users form when user as plugin role --- src/components/user/User.js | 86 +++++++++++++------ src/modules/account/views/UpdateUser.js | 4 +- src/modules/users/views/CreateOrUpdateUser.js | 4 +- src/modules/users/views/UpdateUser.js | 4 +- 4 files changed, 66 insertions(+), 32 deletions(-) diff --git a/src/components/user/User.js b/src/components/user/User.js index 22b59ea..99fa69a 100644 --- a/src/components/user/User.js +++ b/src/components/user/User.js @@ -2,13 +2,14 @@ import React, { Component } from "react"; import PropTypes from "prop-types"; import { debounce } from "lodash"; -import { Form, Button, Divider, Message, Confirm, Header, Icon } from "semantic-ui-react"; +import { Form, Button, Divider, Message, Checkbox } from "semantic-ui-react"; -import { Component as Container } from "src/components/container-content"; -import { Component as UserAvatar } from "src/components/user-avatar"; -import { Component as Breadcrumbs } from "src/components/breadcrumbs"; - -import { Component as FieldValidationMessage } from "src/components/field-validation-message"; +import { Component as Container } from "components/container-content"; +import { Component as UserAvatar } from "components/user-avatar"; +import { Component as Breadcrumbs } from "components/breadcrumbs"; +import { Component as FieldValidationMessage } from "components/field-validation-message"; +import { Component as ConfirmDelete } from "components/confirm-delete"; +import { isPassword } from "helpers/validators"; import "./user.css"; @@ -22,10 +23,12 @@ export class User extends Component { submitSuccess: props.fromCreation, submitted: false, fromCreation: props.fromCreation, - deleteConfirmOpen: false + deleteConfirmOpen: false, + adminPermissions: this.props.user && this.props.user.adminPermissions }; this.handleNameChange = this.handleNameChange.bind(this); + this.handleAdminPermissionsChange = this.handleAdminPermissionsChange.bind(this); this.handleNameBlur = this.handleNameBlur.bind(this); this.handleEmailChange = this.handleEmailChange.bind(this); this.handleEmailBlur = this.handleEmailBlur.bind(this); @@ -39,6 +42,24 @@ export class User extends Component { this.handleDeleteConfirm = this.handleDeleteConfirm.bind(this); } + componentDidUpdate(prevProps) { + if (prevProps.user && prevProps.user.adminPermissions !== this.props.user.adminPermissions) { + this.setState(state => ({ + ...state, + adminPermissions: this.props.user.adminPermissions + })); + } + } + + handleAdminPermissionsChange(event, data) { + this.setState(state => ({ + ...state, + adminPermissions: data.checked, + adminPermissionsChanged: !!this.props.user.adminPermissions !== data.checked, + submitSuccess: false + })); + } + handleNameChange(event, data) { const name = data.value !== this.props.user.name ? data.value : null; this.setState(state => ({ @@ -77,7 +98,7 @@ export class User extends Component { ...state, password, submitSuccess: false, - passwordsValid: password.length && state.repeatPassword === password + passwordsValid: password.length && state.repeatPassword === password && isPassword(password) })); } @@ -87,7 +108,8 @@ export class User extends Component { ...state, repeatPassword, submitSuccess: false, - passwordsValid: repeatPassword.length && state.password === repeatPassword + passwordsValid: + repeatPassword.length && state.password === repeatPassword && isPassword(repeatPassword) })); } @@ -101,7 +123,7 @@ export class User extends Component { repeatedPasswordError() { if (this.hasChangedPassword() || this.hasChangedRepeatPassword()) { - return this.state.password !== this.state.repeatPassword; + return !isPassword(this.state.password) || this.state.password !== this.state.repeatPassword; } return false; } @@ -131,12 +153,15 @@ export class User extends Component { } hasValidPassword() { - return this.state.email && this.state.email.length; + return this.state.password && isPassword(this.state.password); } submitEnabled() { if (!this.props.isNew) { - return (this.hasChangedPassword() || this.state.role) && !this.repeatedPasswordError(); + return ( + (this.hasChangedPassword() || this.state.role || this.state.adminPermissionsChanged) && + !this.repeatedPasswordError() + ); } return ( this.hasChangedName() && @@ -203,7 +228,7 @@ export class User extends Component { handleSubmit(event) { event.preventDefault(); - const { name, email, password, role } = this.state; + const { name, email, password, role, adminPermissions } = this.state; this.setState(state => ({ ...state, submitSuccess: false, @@ -215,7 +240,8 @@ export class User extends Component { name, email, password, - role + role, + adminPermissions }) .then(() => { if (!this.props.isNew) { @@ -229,7 +255,8 @@ export class User extends Component { roleValid: null, passwordsValid: null, submitSuccess: true, - fromCreation: false + fromCreation: false, + adminPermissionsChanged: false })); } }) @@ -298,7 +325,7 @@ export class User extends Component { const repeatedPasswordErrorMessage = passwordsValid ? ( ) : this.repeatedPasswordError() ? ( - + ) : null; const nameMessage = nameValid ? ( @@ -380,6 +407,18 @@ export class User extends Component { ); + const adminPermissionsField = + user.role === "plugin" ? ( + + + + ) : null; + const passwordFields = user.isSystemRole ? null : ( -
+
{deleteButton} - - - Danger zone - - } - content={`You are going to delete the "${user.name}" user. Are you sure?`} + diff --git a/src/modules/account/views/UpdateUser.js b/src/modules/account/views/UpdateUser.js index f67fafa..ce8e973 100644 --- a/src/modules/account/views/UpdateUser.js +++ b/src/modules/account/views/UpdateUser.js @@ -1,4 +1,4 @@ -import { pickBy, identity } from "lodash"; +import { pickBy, isNil } from "lodash"; import { plugins } from "reactive-data-source"; @@ -21,7 +21,7 @@ export const mapDataSourceToProps = ({ id }) => { const updateUser = user.update; const deleteUser = user.delete; - const submitUpdateUser = userData => updateUser(pickBy(userData, identity)); + const submitUpdateUser = userData => updateUser(pickBy(userData, value => !isNil(value))); return { currentUserIsAdmin: userMeIsAdmin.read.getters.value, diff --git a/src/modules/users/views/CreateOrUpdateUser.js b/src/modules/users/views/CreateOrUpdateUser.js index d9a0460..f8e2eb5 100644 --- a/src/modules/users/views/CreateOrUpdateUser.js +++ b/src/modules/users/views/CreateOrUpdateUser.js @@ -1,6 +1,6 @@ import React, { Component } from "react"; import PropTypes from "prop-types"; -import { pickBy, identity } from "lodash"; +import { pickBy, isNil } from "lodash"; import { RoutesContext } from "src/contexts/RoutesContext"; import { usersCollection, userModels, usersCollectionExactFiltered } from "src/data-layer/users"; @@ -20,7 +20,7 @@ export class CreateOrUpdateUser extends Component { } createUser(userData) { - return usersCollection.create(pickBy(userData, identity)).then(() => { + return usersCollection.create(pickBy(userData, value => !isNil(value))).then(() => { return usersCollectionExactFiltered .filter({ name: userData.name diff --git a/src/modules/users/views/UpdateUser.js b/src/modules/users/views/UpdateUser.js index 4a081e6..d70a6e3 100644 --- a/src/modules/users/views/UpdateUser.js +++ b/src/modules/users/views/UpdateUser.js @@ -1,4 +1,4 @@ -import { pickBy, identity } from "lodash"; +import { pickBy, isNil } from "lodash"; import { plugins } from "reactive-data-source"; @@ -21,7 +21,7 @@ export const mapDataSourceToProps = ({ id, deleting }) => { const updateUser = user.update; const deleteUser = user.delete; - const submitUpdateUser = userData => updateUser(pickBy(userData, identity)); + const submitUpdateUser = userData => updateUser(pickBy(userData, value => !isNil(value))); return { currentUserIsAdmin: userMeIsAdmin.read.getters.value, From e419fbc8f2bfb7ebb2481cb41c429a72ec789324 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Wed, 1 May 2019 19:18:37 +0200 Subject: [PATCH 2/4] Add confirm-delete component. Fix styles --- src/app/app.css | 17 ++++++++++++ .../confirm-delete/ConfirmDelete.js | 27 +++++++++++++++++++ src/components/confirm-delete/index.js | 3 +++ src/components/user/User.js | 13 ++++----- 4 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 src/components/confirm-delete/ConfirmDelete.js create mode 100644 src/components/confirm-delete/index.js diff --git a/src/app/app.css b/src/app/app.css index 6b6fdb7..c01a9d1 100644 --- a/src/app/app.css +++ b/src/app/app.css @@ -74,3 +74,20 @@ a:hover { .ui.toggle.checkbox input:checked~.box:before, .ui.toggle.checkbox input:checked~label:before, .ui.toggle.checkbox input:focus:checked~.box:before, .ui.toggle.checkbox input:focus:checked~label:before { background-color:#554f7c!important; } + +@media (max-width: 767px) { + .ui.form .fields { + margin-top:1em; + } +} + +.form-help { + font-size: 0.9em; + color:#999; + font-style: italic; + padding-left: .5em; +} + +.form--buttons-container { + min-height: 40px; +} diff --git a/src/components/confirm-delete/ConfirmDelete.js b/src/components/confirm-delete/ConfirmDelete.js new file mode 100644 index 0000000..b825da9 --- /dev/null +++ b/src/components/confirm-delete/ConfirmDelete.js @@ -0,0 +1,27 @@ +import React from "react"; + +import PropTypes from "prop-types"; + +import { Confirm, Header, Icon } from "semantic-ui-react"; + +export const ConfirmDelete = ({ isOpen, text, onCancel, onConfirm }) => ( + + + Danger zone + + } + content={`You are going to delete the ${text}. This can't be undone. Are you sure?`} + onCancel={onCancel} + onConfirm={onConfirm} + /> +); + +ConfirmDelete.propTypes = { + isOpen: PropTypes.bool.isRequired, + onCancel: PropTypes.func, + onConfirm: PropTypes.func, + text: PropTypes.string.isRequired +}; diff --git a/src/components/confirm-delete/index.js b/src/components/confirm-delete/index.js new file mode 100644 index 0000000..846eaf6 --- /dev/null +++ b/src/components/confirm-delete/index.js @@ -0,0 +1,3 @@ +import { ConfirmDelete } from "./ConfirmDelete"; + +export const Component = ConfirmDelete; diff --git a/src/components/user/User.js b/src/components/user/User.js index 99fa69a..d59041b 100644 --- a/src/components/user/User.js +++ b/src/components/user/User.js @@ -4,12 +4,13 @@ import { debounce } from "lodash"; import { Form, Button, Divider, Message, Checkbox } from "semantic-ui-react"; -import { Component as Container } from "components/container-content"; -import { Component as UserAvatar } from "components/user-avatar"; -import { Component as Breadcrumbs } from "components/breadcrumbs"; -import { Component as FieldValidationMessage } from "components/field-validation-message"; -import { Component as ConfirmDelete } from "components/confirm-delete"; -import { isPassword } from "helpers/validators"; +import { Component as Container } from "src/components/container-content"; +import { Component as UserAvatar } from "src/components/user-avatar"; +import { Component as Breadcrumbs } from "src/components/breadcrumbs"; +import { Component as FieldValidationMessage } from "src/components/field-validation-message"; +import { Component as ConfirmDelete } from "src/components/confirm-delete"; + +const isPassword = password => password.length > 5 import "./user.css"; From 37febe8480d70e936a4245c79c82de9bcdca8ab8 Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Wed, 1 May 2019 19:23:54 +0200 Subject: [PATCH 3/4] Upgrade version --- CHANGELOG.md | 4 ++++ package-lock.json | 2 +- package.json | 2 +- sonar-project.properties | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e39b89..01d82c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed ### Removed +## [1.0.0-beta.3] - 2019-05-01 +### Added +- Add adminPermissions check to users form when user has plugin role + ## [1.0.0-beta.2] - 2019-03-03 ### Fixed - Fix url validator. Now it is configured as in api. diff --git a/package-lock.json b/package-lock.json index b2885f2..ae55478 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "domapic-controller-ui", - "version": "1.0.0-beta.2", + "version": "1.0.0-beta.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a863f44..a450d96 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "domapic-controller-ui", - "version": "1.0.0-beta.2", + "version": "1.0.0-beta.3", "description": "Web user interface for Domapic Controller", "main": "index.js", "keywords": [ diff --git a/sonar-project.properties b/sonar-project.properties index 255198a..7b5c38a 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,6 +1,6 @@ sonar.organization=domapic sonar.projectKey=domapic-controller-ui -sonar.projectVersion=1.0.0-beta.2 +sonar.projectVersion=1.0.0-beta.3 sonar.sources=src sonar.exclusions=node_modules/** From a60fc322ce93e34e59bccc666b49c6a0a3a1bdbb Mon Sep 17 00:00:00 2001 From: Javier Brea Date: Wed, 1 May 2019 19:34:56 +0200 Subject: [PATCH 4/4] Fix lint --- src/components/user/User.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/user/User.js b/src/components/user/User.js index d59041b..a0cd3d3 100644 --- a/src/components/user/User.js +++ b/src/components/user/User.js @@ -10,7 +10,7 @@ import { Component as Breadcrumbs } from "src/components/breadcrumbs"; import { Component as FieldValidationMessage } from "src/components/field-validation-message"; import { Component as ConfirmDelete } from "src/components/confirm-delete"; -const isPassword = password => password.length > 5 +const isPassword = password => password.length > 5; import "./user.css";