• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / gui / 944676341

pending completion
944676341

Pull #3875

gitlab-ci

mzedel
chore: aligned snapshots with updated design

Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #3875: MEN-5414

4469 of 6446 branches covered (69.33%)

230 of 266 new or added lines in 43 files covered. (86.47%)

1712 existing lines in 161 files now uncovered.

8406 of 10170 relevant lines covered (82.65%)

196.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.57
/src/js/components/settings/user-management/userform.js
1
// Copyright 2017 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14
import React, { useMemo, useState } from 'react';
15

16
import { InfoOutlined } from '@mui/icons-material';
17
import {
18
  Checkbox,
19
  Dialog,
20
  DialogActions,
21
  DialogContent,
22
  DialogTitle,
23
  FormControl,
24
  FormControlLabel,
25
  FormHelperText,
26
  InputLabel,
27
  ListItemText,
28
  MenuItem,
29
  Select,
30
  Tooltip
31
} from '@mui/material';
32

33
import pluralize from 'pluralize';
34

35
import { BENEFITS } from '../../../constants/appConstants';
36
import { rolesById, rolesByName, uiPermissionsById } from '../../../constants/userConstants';
37
import { toggle } from '../../../helpers';
38
import EnterpriseNotification from '../../common/enterpriseNotification';
39
import Form from '../../common/forms/form';
40
import PasswordInput from '../../common/forms/passwordinput';
41
import TextInput from '../../common/forms/textinput';
42

43
export const UserRolesSelect = ({ currentUser, disabled, onSelect, roles, user }) => {
7✔
44
  const [selectedRoleIds, setSelectedRoleIds] = useState(
35✔
45
    (user.roles || [rolesByName.admin]).reduce((accu, roleId) => {
70✔
46
      const foundRole = roles[roleId];
35✔
47
      if (foundRole) {
35✔
48
        accu.push(roleId);
34✔
49
      }
50
      return accu;
35✔
51
    }, [])
52
  );
53

54
  const onInputChange = ({ target: { value } }) => {
35✔
55
    const { roles = [] } = user;
3✔
56
    let newlySelectedRoles = value;
3✔
57
    if (value.includes('')) {
3!
UNCOV
58
      newlySelectedRoles = [];
×
59
    }
60
    const hadRoleChanges =
61
      roles.length !== newlySelectedRoles.length || roles.some(currentRoleId => !newlySelectedRoles.some(roleId => currentRoleId === roleId));
3✔
62
    setSelectedRoleIds(newlySelectedRoles);
3✔
63
    onSelect(newlySelectedRoles, hadRoleChanges);
3✔
64
  };
65

66
  const editableRoles = useMemo(
35✔
67
    () =>
68
      Object.entries(roles).map(([id, role]) => {
7✔
69
        const enabled = selectedRoleIds.some(roleId => id === roleId);
36✔
70
        return { enabled, id, ...role };
36✔
71
      }),
72
    [roles, selectedRoleIds]
73
  );
74

75
  const showRoleUsageNotification = useMemo(
35✔
76
    () =>
77
      selectedRoleIds.reduce((accu, roleId) => {
7✔
78
        const { permissions, uiPermissions } = roles[roleId];
6✔
79
        const hasUiApiAccess = [rolesByName.ci].includes(roleId)
6✔
80
          ? false
81
          : roleId === rolesByName.admin ||
7✔
UNCOV
82
            permissions.some(permission => ![rolesByName.deploymentCreation.action].includes(permission.action)) ||
×
83
            uiPermissions.userManagement.includes(uiPermissionsById.read.value);
84
        if (hasUiApiAccess) {
6✔
85
          return false;
5✔
86
        }
87
        return typeof accu !== 'undefined' ? accu : true;
1!
88
      }, undefined),
89
    [selectedRoleIds]
90
  );
91

92
  return (
35✔
93
    <div className="flexbox" style={{ alignItems: 'flex-end' }}>
94
      <FormControl id="roles-form" style={{ maxWidth: 400 }}>
95
        <InputLabel id="roles-selection-label">Roles</InputLabel>
96
        <Select
97
          labelId="roles-selection-label"
98
          id={`roles-selector-${selectedRoleIds.length}`}
99
          disabled={disabled}
100
          multiple
101
          value={selectedRoleIds}
102
          required
103
          onChange={onInputChange}
104
          renderValue={selected => selected.map(role => roles[role].name).join(', ')}
45✔
105
        >
106
          {editableRoles.map(role => (
107
            <MenuItem id={role.id} key={role.id} value={role.id}>
204✔
108
              <Checkbox id={`${role.id}-checkbox`} checked={role.enabled} />
109
              <ListItemText id={`${role.id}-text`} primary={role.name} />
110
            </MenuItem>
111
          ))}
112
        </Select>
113
        {showRoleUsageNotification && (
36✔
114
          <FormHelperText className="info">
115
            The selected {pluralize('role', selectedRoleIds.length)} may prevent {currentUser.email === user.email ? 'you' : <i>{user.email}</i>} from using the
1!
116
            Mender UI.
117
            <br />
118
            Consider adding the <i>{rolesById[rolesByName.readOnly].name}</i> role as well.
119
          </FormHelperText>
120
        )}
121
      </FormControl>
122
      <EnterpriseNotification className="margin-left-small" id={BENEFITS.rbac.id} />
123
    </div>
124
  );
125
};
126

127
const PasswordLabel = () => (
7✔
128
  <div className="flexbox center-aligned">
9✔
129
    Optional
130
    <Tooltip
131
      title={
132
        <>
133
          <p>You can skip setting a password for now - you can opt to send the new user an email containing a password reset link by checking the box below.</p>
134
          <p>Organizations using Single Sign-On or other means of authorization may want to create users with no password.</p>
135
        </>
136
      }
137
    >
138
      <InfoOutlined fontSize="small" className="margin-left-small" />
139
    </Tooltip>
140
  </div>
141
);
142

143
export const UserForm = ({ closeDialog, currentUser, canManageUsers, isEnterprise, roles, submit }) => {
7✔
144
  const [hadRoleChanges, setHadRoleChanges] = useState(false);
9✔
145
  const [selectedRoles, setSelectedRoles] = useState();
9✔
146
  const [shouldResetPassword, setShouldResetPassword] = useState(false);
9✔
147

148
  const onSelect = (newlySelectedRoles, hadRoleChanges) => {
9✔
UNCOV
149
    setSelectedRoles(newlySelectedRoles);
×
UNCOV
150
    setHadRoleChanges(hadRoleChanges);
×
151
  };
152

153
  const onSubmit = data => {
9✔
154
    const { password, ...remainder } = data;
1✔
155
    const roleData = hadRoleChanges ? { roles: selectedRoles } : {};
1!
156
    return submit({ ...remainder, ...roleData, password }, 'create');
1✔
157
  };
158

159
  const togglePasswordReset = () => setShouldResetPassword(toggle);
9✔
160

161
  return (
9✔
162
    <Dialog open={true} fullWidth={true} maxWidth="sm">
163
      <DialogTitle>Create new user</DialogTitle>
164
      <DialogContent style={{ overflowY: 'initial' }}>
165
        <Form onSubmit={onSubmit} handleCancel={closeDialog} submitLabel="Create user" submitButtonId="submit_button" showButtons={true} autocomplete="off">
166
          <TextInput hint="Email" label="Email" id="email" validations="isLength:1,isEmail" required autocomplete="off" />
167
          <PasswordInput
168
            id="password"
169
            className="edit-pass"
170
            autocomplete="off"
171
            create
172
            edit={false}
173
            generate
174
            InputLabelProps={{ shrink: true }}
175
            label={<PasswordLabel />}
176
            placeholder="Password"
177
            validations="isLength:8"
178
          />
179
          <FormControlLabel
180
            control={<Checkbox checked={shouldResetPassword} onChange={togglePasswordReset} />}
181
            label="Send an email to the user containing a link to reset the password"
182
          />
183
          <UserRolesSelect currentUser={currentUser} disabled={!(canManageUsers && isEnterprise)} onSelect={onSelect} roles={roles} user={{}} />
17✔
184
        </Form>
185
      </DialogContent>
186
      <DialogActions />
187
    </Dialog>
188
  );
189
};
190

191
export default UserForm;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc