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

mendersoftware / gui / 1057188406

01 Nov 2023 04:24AM UTC coverage: 82.824% (-17.1%) from 99.964%
1057188406

Pull #4134

gitlab-ci

web-flow
chore: Bump uuid from 9.0.0 to 9.0.1

Bumps [uuid](https://github.com/uuidjs/uuid) from 9.0.0 to 9.0.1.
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v9.0.0...v9.0.1)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #4134: chore: Bump uuid from 9.0.0 to 9.0.1

4349 of 6284 branches covered (0.0%)

8313 of 10037 relevant lines covered (82.82%)

200.97 hits per line

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

76.92
/src/js/components/settings/organization/organization.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, { useCallback, useEffect, useState } from 'react';
15
import CopyToClipboard from 'react-copy-to-clipboard';
16
import { useDispatch, useSelector } from 'react-redux';
17

18
// material ui
19
import { FileCopy as CopyPasteIcon } from '@mui/icons-material';
20
import { Button, Checkbox, Collapse, FormControlLabel, List } from '@mui/material';
21
import { makeStyles } from 'tss-react/mui';
22

23
import copy from 'copy-to-clipboard';
24
import moment from 'moment';
25

26
import { setSnackbar } from '../../../actions/appActions';
27
import {
28
  changeSamlConfig,
29
  deleteSamlConfig,
30
  downloadLicenseReport,
31
  getSamlConfigs,
32
  getUserOrganization,
33
  storeSamlConfig
34
} from '../../../actions/organizationActions';
35
import { TIMEOUTS } from '../../../constants/appConstants';
36
import { createFileDownload, toggle } from '../../../helpers';
37
import { getFeatures, getIsEnterprise, getIsPreview, getOrganization, getUserRoles } from '../../../selectors';
38
import ExpandableAttribute from '../../common/expandable-attribute';
39
import { HELPTOOLTIPS, MenderHelpTooltip } from '../../helptips/helptooltips';
40
import Billing from './billing';
41
import OrganizationSettingsItem, { maxWidth } from './organizationsettingsitem';
42
import { SAMLConfig } from './samlconfig';
43

44
const useStyles = makeStyles()(theme => ({
13✔
45
  copyNotification: { height: 30, padding: 15 },
46
  deviceLimitBar: { backgroundColor: theme.palette.grey[500], margin: '15px 0' },
47
  ssoToggle: { width: `calc(${maxWidth}px + ${theme.spacing(4)})` },
48
  tenantInfo: { marginTop: 11, paddingBottom: 3, 'span': { marginLeft: theme.spacing(0.5), color: theme.palette.text.disabled } },
49
  tenantToken: { width: `calc(${maxWidth}px - ${theme.spacing(4)})` },
50
  tokenTitle: { paddingRight: 10 },
51
  tokenExplanation: { margin: '1em 0' }
52
}));
53

54
export const OrgHeader = () => {
6✔
55
  const { classes } = useStyles();
15✔
56
  return (
15✔
57
    <div className="flexbox center-aligned">
58
      <div className={classes.tokenTitle}>Organization token</div>
59
      <MenderHelpTooltip id={HELPTOOLTIPS.tenantToken.id} disableHoverListener={false} placement="top" />
60
    </div>
61
  );
62
};
63

64
export const CopyTextToClipboard = ({ token }) => {
6✔
65
  const [copied, setCopied] = useState(false);
24✔
66
  const { classes } = useStyles();
24✔
67

68
  const onCopied = () => {
24✔
69
    setCopied(true);
×
70
    setTimeout(() => setCopied(false), TIMEOUTS.fiveSeconds);
×
71
  };
72

73
  return (
24✔
74
    <div>
75
      <CopyToClipboard text={token} onCopy={onCopied}>
76
        <Button startIcon={<CopyPasteIcon />}>Copy to clipboard</Button>
77
      </CopyToClipboard>
78
      <div className={classes.copyNotification}>{copied && <span className="green fadeIn">Copied to clipboard.</span>}</div>
24!
79
    </div>
80
  );
81
};
82

83
export const Organization = () => {
6✔
84
  const [hasSingleSignOn, setHasSingleSignOn] = useState(false);
17✔
85
  const [isResettingSSO, setIsResettingSSO] = useState(false);
16✔
86
  const [isConfiguringSSO, setIsConfiguringSSO] = useState(false);
16✔
87
  const isEnterprise = useSelector(getIsEnterprise);
16✔
88
  const { isAdmin } = useSelector(getUserRoles);
16✔
89
  const canPreview = useSelector(getIsPreview);
16✔
90
  const { isHosted } = useSelector(getFeatures);
16✔
91
  const org = useSelector(getOrganization);
16✔
92
  const samlConfigs = useSelector(state => state.organization.samlConfigs);
30✔
93
  const dispatch = useDispatch();
16✔
94

95
  const { classes } = useStyles();
16✔
96

97
  useEffect(() => {
16✔
98
    dispatch(getUserOrganization());
3✔
99
  }, [dispatch]);
100

101
  useEffect(() => {
16✔
102
    if (isEnterprise) {
3!
103
      dispatch(getSamlConfigs());
3✔
104
    }
105
  }, [dispatch, isEnterprise]);
106

107
  useEffect(() => {
16✔
108
    setHasSingleSignOn(!!samlConfigs.length);
6✔
109
    setIsConfiguringSSO(!!samlConfigs.length);
6✔
110
  }, [samlConfigs.length]);
111

112
  const onSSOClick = () => {
16✔
113
    if (hasSingleSignOn) {
4!
114
      setIsConfiguringSSO(false);
4✔
115
      return setIsResettingSSO(true);
4✔
116
    }
117
    setIsConfiguringSSO(toggle);
×
118
  };
119

120
  const onCancelSSOSettings = () => {
16✔
121
    setIsResettingSSO(false);
×
122
    setIsConfiguringSSO(hasSingleSignOn);
×
123
  };
124

125
  const onSaveSSOSettings = useCallback(
16✔
126
    (id, fileContent) => {
127
      if (isResettingSSO) {
4!
128
        return dispatch(deleteSamlConfig(samlConfigs[0])).then(() => setIsResettingSSO(false));
4✔
129
      }
130
      if (id) {
×
131
        return dispatch(changeSamlConfig({ id, config: fileContent }));
×
132
      }
133
      return dispatch(storeSamlConfig(fileContent));
×
134
    },
135
    [isResettingSSO, dispatch, samlConfigs]
136
  );
137

138
  const onDownloadReportClick = () =>
16✔
139
    dispatch(downloadLicenseReport()).then(report => createFileDownload(report, `Mender-license-report-${moment().format(moment.HTML5_FMT.DATE)}`));
×
140

141
  const onTenantInfoClick = () => {
16✔
142
    copy(`Organization: ${org.name}, Tenant ID: ${org.id}`);
×
143
    setSnackbar('Copied to clipboard');
×
144
  };
145

146
  return (
16✔
147
    <div className="margin-top-small">
148
      <h2 className="margin-top-small">Organization and billing</h2>
149
      <List>
150
        <OrganizationSettingsItem
151
          title="Organization name"
152
          content={{
153
            action: { action: onTenantInfoClick, internal: true },
154
            description: (
155
              <div className={`clickable ${classes.tenantInfo}`} onClick={onTenantInfoClick}>
156
                {org.name}
157
                <span>({org.id})</span>
158
              </div>
159
            )
160
          }}
161
        />
162
        <OrganizationSettingsItem
163
          title={<OrgHeader />}
164
          content={{}}
165
          secondary={
166
            <ExpandableAttribute
167
              className={classes.tenantToken}
168
              component="div"
169
              disableGutters
170
              dividerDisabled
171
              key="org_token"
172
              secondary={org.tenant_token}
173
              textClasses={{ secondary: 'inventory-text tenant-token-text' }}
174
            />
175
          }
176
          sideBarContent={<CopyTextToClipboard token={org.tenant_token} />}
177
        />
178
      </List>
179
      {isEnterprise && isAdmin && (
48✔
180
        <div className="flexbox center-aligned">
181
          <FormControlLabel
182
            className={`margin-bottom-small ${classes.ssoToggle}`}
183
            control={<Checkbox checked={!isResettingSSO && (hasSingleSignOn || isConfiguringSSO)} onChange={onSSOClick} />}
36✔
184
            label="Enable SAML single sign-on"
185
          />
186
          {isResettingSSO && !isConfiguringSSO && (
24✔
187
            <>
188
              <Button onClick={onCancelSSOSettings}>Cancel</Button>
189
              <Button onClick={onSaveSSOSettings} disabled={!hasSingleSignOn} variant="contained">
190
                Save
191
              </Button>
192
            </>
193
          )}
194
        </div>
195
      )}
196
      <Collapse className="margin-left-large" in={isConfiguringSSO}>
197
        <SAMLConfig configs={samlConfigs} onSave={onSaveSSOSettings} onCancel={onCancelSSOSettings} setSnackbar={message => dispatch(setSnackbar(message))} />
×
198
      </Collapse>
199
      {isHosted && <Billing />}
32✔
200
      {(canPreview || !isHosted) && isEnterprise && isAdmin && (
32!
201
        <Button className="margin-top" onClick={onDownloadReportClick} variant="contained">
202
          Download license report
203
        </Button>
204
      )}
205
    </div>
206
  );
207
};
208

209
export default Organization;
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