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

mendersoftware / gui / 1350829378

27 Jun 2024 01:46PM UTC coverage: 83.494% (-16.5%) from 99.965%
1350829378

Pull #4465

gitlab-ci

mzedel
chore: test fixes

Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #4465: MEN-7169 - feat: added multi sorting capabilities to devices view

4506 of 6430 branches covered (70.08%)

81 of 100 new or added lines in 14 files covered. (81.0%)

1661 existing lines in 163 files now uncovered.

8574 of 10269 relevant lines covered (83.49%)

160.6 hits per line

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

71.43
/src/js/components/settings/user-management/selfusermanagement.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, { useState } from 'react';
15
import { useDispatch, useSelector } from 'react-redux';
16

17
import { Button, Switch, TextField } from '@mui/material';
18
import { makeStyles } from 'tss-react/mui';
19

20
import { setSnackbar } from '../../../actions/appActions';
21
import { editUser, saveUserSettings } from '../../../actions/userActions';
22
import { DARK_MODE, LIGHT_MODE } from '../../../constants/appConstants';
23
import * as UserConstants from '../../../constants/userConstants';
24
import { isDarkMode, toggle } from '../../../helpers';
25
import { getCurrentSession, getCurrentUser, getFeatures, getIsEnterprise, getUserSettings } from '../../../selectors';
26
import ExpandableAttribute from '../../common/expandable-attribute';
27
import Form from '../../common/forms/form';
28
import PasswordInput from '../../common/forms/passwordinput';
29
import TextInput from '../../common/forms/textinput';
30
import InfoText from '../../common/infotext';
31
import AccessTokenManagement from '../accesstokenmanagement';
32
import { CopyTextToClipboard } from '../organization/organization';
33
import TwoFactorAuthSetup from './twofactorauthsetup';
34
import { UserId, getUserSSOState } from './userdefinition';
35

36
const useStyles = makeStyles()(() => ({
4✔
37
  formField: { width: 400, maxWidth: '100%' },
38
  changeButton: { margin: '30px 0 0 15px' },
39
  infoText: { margin: 0, width: '75%' },
40
  jwt: { maxWidth: '70%' },
41
  oauthIcon: { fontSize: '36px', marginRight: 10 },
42
  userId: { '&.full-width': { maxWidth: '100%' } },
43
  widthLimit: { maxWidth: 750 }
44
}));
45

46
export const SelfUserManagement = () => {
4✔
47
  const [editEmail, setEditEmail] = useState(false);
11✔
48
  const [editPass, setEditPass] = useState(false);
11✔
49
  const { classes } = useStyles();
11✔
50
  const dispatch = useDispatch();
11✔
51

52
  const { isHosted } = useSelector(getFeatures);
11✔
53
  const isEnterprise = useSelector(getIsEnterprise);
11✔
54
  const canHave2FA = isEnterprise || isHosted;
11✔
55
  const currentUser = useSelector(getCurrentUser);
11✔
56
  const { isOAuth2, provider } = getUserSSOState(currentUser);
11✔
57
  const { email, id: userId } = currentUser;
11✔
58
  const hasTracking = useSelector(state => !!state.app.trackerCode);
22✔
59
  const { trackingConsentGiven: hasTrackingConsent, mode } = useSelector(getUserSettings);
11✔
60
  const { token } = useSelector(getCurrentSession);
11✔
61

62
  const editSubmit = userData => {
11✔
UNCOV
63
    if (userData.password != userData.password_confirmation) {
×
UNCOV
64
      dispatch(setSnackbar(`The passwords don't match`));
×
65
    } else {
UNCOV
66
      dispatch(editUser(UserConstants.OWN_USER_ID, userData)).then(() => {
×
UNCOV
67
        setEditEmail(false);
×
UNCOV
68
        setEditPass(false);
×
69
      });
70
    }
71
  };
72

73
  const handleEmail = () => setEditEmail(toggle);
11✔
74

75
  const toggleMode = () => {
11✔
UNCOV
76
    const newMode = isDarkMode(mode) ? LIGHT_MODE : DARK_MODE;
×
UNCOV
77
    dispatch(saveUserSettings({ mode: newMode }));
×
78
  };
79

80
  const handlePass = () => setEditPass(toggle);
11✔
81

82
  return (
11✔
83
    <div className={`margin-top-small ${classes.widthLimit}`}>
84
      <h2 className="margin-top-small">My profile</h2>
85
      <UserId className={`full-width ${classes.userId}`} userId={userId} />
86
      {!editEmail && email ? (
32✔
87
        <div className="flexbox space-between margin-bottom-small">
88
          <TextField className={classes.formField} label="Email" key={email} InputLabelProps={{ shrink: !!email }} disabled defaultValue={email} />
89
          {!isOAuth2 && (
18✔
90
            <Button className={`inline-block ${classes.changeButton}`} color="primary" id="change_email" onClick={handleEmail}>
91
              Change email
92
            </Button>
93
          )}
94
        </div>
95
      ) : (
96
        <Form defaultValues={{ email }} onSubmit={editSubmit} handleCancel={handleEmail} submitLabel="Save" showButtons={editEmail} buttonColor="secondary">
97
          <TextInput disabled={false} hint="Email" id="email" InputLabelProps={{ shrink: !!email }} label="Email" validations="isLength:1,isEmail,trim" />
98
          <PasswordInput id="current_password" label="Current password *" validations={`isLength:8,isNot:${email}`} required={true} />
99
        </Form>
100
      )}
101
      {!isOAuth2 &&
20✔
102
        (!editPass ? (
9✔
103
          <form className="flexbox space-between">
104
            <TextField className={classes.formField} label="Password" key="password-placeholder" disabled defaultValue="********" type="password" />
105
            <Button className={classes.changeButton} color="primary" id="change_password" onClick={handlePass}>
106
              Change password
107
            </Button>
108
          </form>
109
        ) : (
110
          <>
111
            <h3 className="margin-top margin-bottom-none">Change password</h3>
112
            <Form onSubmit={editSubmit} handleCancel={handlePass} submitLabel="Save" buttonColor="secondary" showButtons={editPass}>
113
              <PasswordInput id="current_password" label="Current password *" validations={`isLength:8,isNot:${email}`} required />
114
              <PasswordInput className="edit-pass" id="password" label="Password *" validations={`isLength:8,isNot:${email}`} create generate required />
115
              <PasswordInput id="password_confirmation" label="Confirm password *" validations={`isLength:8,isNot:${email}`} required />
116
            </Form>
117
          </>
118
        ))}
119
      <div className="clickable flexbox space-between margin-top" onClick={toggleMode}>
120
        <p className="help-content">Enable dark theme</p>
121
        <Switch checked={isDarkMode(mode)} />
122
      </div>
123
      {!isOAuth2 ? (
11✔
124
        canHave2FA && <TwoFactorAuthSetup />
16✔
125
      ) : (
126
        <div className="flexbox margin-top">
127
          <div className={classes.oauthIcon}>{provider.icon}</div>
128
          <div className="info">
129
            You are logging in using your <strong>{provider.name}</strong> account.
130
            <br />
131
            Please connect to {provider.name} to update your login settings.
132
          </div>
133
        </div>
134
      )}
135
      <div className="flexbox space-between margin-top-large">
136
        <div className={classes.jwt}>
137
          <div className="help-content">Session token</div>
138
          <ExpandableAttribute
139
            component="div"
140
            disableGutters
141
            dividerDisabled
142
            secondary={token}
143
            textClasses={{ secondary: 'inventory-text tenant-token-text' }}
144
          />
145
        </div>
146
        <div className="flexbox center-aligned">
147
          <CopyTextToClipboard token={token} />
148
        </div>
149
      </div>
150
      <AccessTokenManagement />
151
      {isEnterprise && hasTracking && (
18!
152
        <div className="margin-top">
UNCOV
153
          <div className="clickable flexbox space-between" onClick={() => dispatch(saveUserSettings({ trackingConsentGiven: !hasTrackingConsent }))}>
×
154
            <p className="help-content">Help us improve Mender</p>
155
            <Switch checked={!!hasTrackingConsent} />
156
          </div>
157
          <InfoText className={classes.infoText}>Enable usage data and errors to be sent to help us improve our service.</InfoText>
158
        </div>
159
      )}
160
    </div>
161
  );
162
};
163

164
export default SelfUserManagement;
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