Skip to content

Commit

Permalink
Merge pull request #4 from domapic/release-1.0.0-beta.3
Browse files Browse the repository at this point in the history
Release 1.0.0 beta.3
  • Loading branch information
javierbrea committed May 1, 2019
2 parents afaa4e7 + a60fc32 commit 613c5a0
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 31 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion 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": [
Expand Down
2 changes: 1 addition & 1 deletion 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/**
Expand Down
17 changes: 17 additions & 0 deletions src/app/app.css
Expand Up @@ -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;
}
27 changes: 27 additions & 0 deletions 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 }) => (
<Confirm
open={isOpen}
header={
<Header as="h2">
<Icon name="warning" color="red" />
<Header.Content>Danger zone</Header.Content>
</Header>
}
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
};
3 changes: 3 additions & 0 deletions src/components/confirm-delete/index.js
@@ -0,0 +1,3 @@
import { ConfirmDelete } from "./ConfirmDelete";

export const Component = ConfirmDelete;
79 changes: 57 additions & 22 deletions src/components/user/User.js
Expand Up @@ -2,13 +2,15 @@ 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 ConfirmDelete } from "src/components/confirm-delete";

const isPassword = password => password.length > 5;

import "./user.css";

Expand All @@ -22,10 +24,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);
Expand All @@ -39,6 +43,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 => ({
Expand Down Expand Up @@ -77,7 +99,7 @@ export class User extends Component {
...state,
password,
submitSuccess: false,
passwordsValid: password.length && state.repeatPassword === password
passwordsValid: password.length && state.repeatPassword === password && isPassword(password)
}));
}

Expand All @@ -87,7 +109,8 @@ export class User extends Component {
...state,
repeatPassword,
submitSuccess: false,
passwordsValid: repeatPassword.length && state.password === repeatPassword
passwordsValid:
repeatPassword.length && state.password === repeatPassword && isPassword(repeatPassword)
}));
}

Expand All @@ -101,7 +124,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;
}
Expand Down Expand Up @@ -131,12 +154,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() &&
Expand Down Expand Up @@ -203,7 +229,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,
Expand All @@ -215,7 +241,8 @@ export class User extends Component {
name,
email,
password,
role
role,
adminPermissions
})
.then(() => {
if (!this.props.isNew) {
Expand All @@ -229,7 +256,8 @@ export class User extends Component {
roleValid: null,
passwordsValid: null,
submitSuccess: true,
fromCreation: false
fromCreation: false,
adminPermissionsChanged: false
}));
}
})
Expand Down Expand Up @@ -298,7 +326,7 @@ export class User extends Component {
const repeatedPasswordErrorMessage = passwordsValid ? (
<FieldValidationMessage valid />
) : this.repeatedPasswordError() ? (
<FieldValidationMessage message="Passwords are not equal" />
<FieldValidationMessage message="Passwords are not valid" />
) : null;

const nameMessage = nameValid ? (
Expand Down Expand Up @@ -380,6 +408,18 @@ export class User extends Component {
</Form.Group>
);

const adminPermissionsField =
user.role === "plugin" ? (
<Form.Group>
<Form.Field
control={Checkbox}
checked={this.state.adminPermissions}
label="Grant admin permissions"
onChange={this.handleAdminPermissionsChange}
/>
</Form.Group>
) : null;

const passwordFields = user.isSystemRole ? null : (
<Form.Group>
<Form.Input
Expand Down Expand Up @@ -430,9 +470,10 @@ export class User extends Component {
{nameField}
{emailField}
{roleField}
{adminPermissionsField}
{passwordFields}
<Divider />
<div className="user--form--buttons-container" key={submitLoading}>
<div className="form--buttons-container" key={submitLoading}>
{deleteButton}
<Button
floated="right"
Expand All @@ -449,15 +490,9 @@ export class User extends Component {
>
Cancel
</Button>
<Confirm
open={deleteConfirmOpen}
header={
<Header as="h2">
<Icon name="warning" color="red" />
<Header.Content>Danger zone</Header.Content>
</Header>
}
content={`You are going to delete the "${user.name}" user. Are you sure?`}
<ConfirmDelete
isOpen={deleteConfirmOpen}
text={`"${user.name}" user`}
onCancel={this.handleDeleteCancel}
onConfirm={this.handleDeleteConfirm}
/>
Expand Down
4 changes: 2 additions & 2 deletions 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";

Expand All @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions 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";
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions 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";

Expand All @@ -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,
Expand Down

0 comments on commit 613c5a0

Please sign in to comment.