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

mendersoftware / gui / 901187442

pending completion
901187442

Pull #3795

gitlab-ci

mzedel
feat: increased chances of adopting our intended navigation patterns instead of unsupported browser navigation

Ticket: None
Changelog: None
Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #3795: feat: increased chances of adopting our intended navigation patterns instead of unsupported browser navigation

4389 of 6365 branches covered (68.96%)

5 of 5 new or added lines in 1 file covered. (100.0%)

1729 existing lines in 165 files now uncovered.

8274 of 10019 relevant lines covered (82.58%)

144.86 hits per line

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

67.61
/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 { rolesById, rolesByName, uiPermissionsById } from '../../../constants/userConstants';
36
import { toggle } from '../../../helpers';
37
import Form from '../../common/forms/form';
38
import PasswordInput from '../../common/forms/passwordinput';
39
import TextInput from '../../common/forms/textinput';
40

41
export const UserRolesSelect = ({ currentUser, onSelect, roles, user }) => {
7✔
42
  const [selectedRoleIds, setSelectedRoleIds] = useState(
25✔
43
    (user.roles || []).reduce((accu, roleId) => {
50✔
UNCOV
44
      const foundRole = roles[roleId];
×
UNCOV
45
      if (foundRole) {
×
UNCOV
46
        accu.push(roleId);
×
47
      }
UNCOV
48
      return accu;
×
49
    }, [])
50
  );
51

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

64
  const editableRoles = useMemo(
25✔
65
    () =>
66
      Object.entries(roles).map(([id, role]) => {
4✔
67
        const enabled = selectedRoleIds.some(roleId => id === roleId);
24✔
68
        return { enabled, id, ...role };
24✔
69
      }),
70
    [roles, selectedRoleIds]
71
  );
72

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

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

121
const PasswordLabel = () => (
7✔
122
  <div className="flexbox center-aligned">
1✔
123
    Optional
124
    <Tooltip
125
      title={
126
        <>
127
          <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>
128
          <p>Organizations using Single Sign-On or other means of authorization may want to create users with no password.</p>
129
        </>
130
      }
131
    >
132
      <InfoOutlined fontSize="small" className="margin-left-small" />
133
    </Tooltip>
134
  </div>
135
);
136

137
export const UserForm = ({ closeDialog, currentUser, canManageUsers, isEnterprise, roles, submit }) => {
7✔
138
  const [hadRoleChanges, setHadRoleChanges] = useState(false);
1✔
139
  const [selectedRoles, setSelectedRoles] = useState();
1✔
140
  const [shouldResetPassword, setShouldResetPassword] = useState(false);
1✔
141

142
  const onSelect = (newlySelectedRoles, hadRoleChanges) => {
1✔
UNCOV
143
    setSelectedRoles(newlySelectedRoles);
×
UNCOV
144
    setHadRoleChanges(hadRoleChanges);
×
145
  };
146

147
  const onSubmit = data => {
1✔
UNCOV
148
    const { password_new: password, ...remainder } = data;
×
UNCOV
149
    const roleData = hadRoleChanges ? { roles: selectedRoles } : {};
×
UNCOV
150
    return submit({ ...remainder, ...roleData, password }, 'create');
×
151
  };
152

153
  const togglePasswordReset = () => setShouldResetPassword(toggle);
1✔
154

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

194
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