• 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

87.88
/src/js/components/header/header.js
1
// Copyright 2015 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, useRef, useState } from 'react';
15
import { useDispatch, useSelector } from 'react-redux';
16
import { Link } from 'react-router-dom';
17

18
import {
19
  AccountCircle as AccountCircleIcon,
20
  ArrowDropDown as ArrowDropDownIcon,
21
  ArrowDropUp as ArrowDropUpIcon,
22
  ExitToApp as ExitIcon
23
} from '@mui/icons-material';
24
import { Button, IconButton, ListItemSecondaryAction, ListItemText, Menu, MenuItem, Toolbar } from '@mui/material';
25
import { makeStyles } from 'tss-react/mui';
26

27
import moment from 'moment';
28
import Cookies from 'universal-cookie';
29

30
import enterpriseLogo from '../../../assets/img/headerlogo-enterprise.png';
31
import logo from '../../../assets/img/headerlogo.png';
32
import whiteEnterpriseLogo from '../../../assets/img/whiteheaderlogo-enterprise.png';
33
import whiteLogo from '../../../assets/img/whiteheaderlogo.png';
34
import { setFirstLoginAfterSignup, setSearchState } from '../../actions/appActions';
35
import { getAllDeviceCounts } from '../../actions/deviceActions';
36
import { initializeSelf, logoutUser, setAllTooltipsReadState, setHideAnnouncement } from '../../actions/userActions';
37
import { getToken } from '../../auth';
38
import { TIMEOUTS } from '../../constants/appConstants';
39
import { READ_STATES } from '../../constants/userConstants';
40
import { decodeSessionToken, isDarkMode } from '../../helpers';
41
import {
42
  getAcceptedDevices,
43
  getCurrentUser,
44
  getDeviceCountsByStatus,
45
  getDeviceLimit,
46
  getFeatures,
47
  getIsEnterprise,
48
  getOrganization,
49
  getShowHelptips,
50
  getUserCapabilities,
51
  getUserSettings
52
} from '../../selectors';
53
import Tracking from '../../tracking';
54
import { useDebounce } from '../../utils/debouncehook';
55
import Search from '../common/search';
56
import Announcement from './announcement';
57
import DemoNotification from './demonotification';
58
import DeploymentNotifications from './deploymentnotifications';
59
import DeviceNotifications from './devicenotifications';
60
import OfferHeader from './offerheader';
61
import TrialNotification from './trialnotification';
62

63
// Change this when a new feature/offer is introduced
64
const currentOffer = {
3✔
65
  name: 'add-ons',
66
  expires: '2021-12-30',
67
  trial: true,
68
  os: true,
69
  professional: true,
70
  enterprise: true
71
};
72

73
const cookies = new Cookies();
3✔
74

75
const useStyles = makeStyles()(theme => ({
23✔
76
  header: {
77
    minHeight: 'unset',
78
    paddingLeft: theme.spacing(4),
79
    paddingRight: theme.spacing(5),
80
    width: '100%',
81
    borderBottom: `1px solid ${theme.palette.grey[100]}`,
82
    display: 'grid'
83
  },
84
  banner: { gridTemplateRows: `1fr ${theme.mixins.toolbar.minHeight}px` },
85
  buttonColor: { color: theme.palette.grey[600] },
86
  dropDown: { height: '100%', marginLeft: theme.spacing(0.5), textTransform: 'none' },
87
  exitIcon: { color: theme.palette.grey[600], fill: theme.palette.grey[600] },
88
  demoTrialAnnouncement: {
89
    fontSize: 14,
90
    height: 'auto'
91
  },
92
  demoAnnouncementIcon: {
93
    height: 16,
94
    color: theme.palette.primary.main,
95
    '&.MuiButton-textPrimary': {
96
      color: theme.palette.primary.main,
97
      height: 'inherit'
98
    }
99
  },
100
  redAnnouncementIcon: {
101
    color: theme.palette.error.dark
102
  }
103
}));
104

105
export const Header = ({ mode }) => {
3✔
106
  const { classes } = useStyles();
424✔
107
  const [anchorEl, setAnchorEl] = useState(null);
424✔
108
  const [loggingOut, setLoggingOut] = useState(false);
424✔
109
  const [gettingUser, setGettingUser] = useState(false);
424✔
110
  const [hasOfferCookie, setHasOfferCookie] = useState(false);
424✔
111
  const sessionId = useDebounce(getToken(), TIMEOUTS.debounceDefault);
424✔
112

113
  const organization = useSelector(getOrganization);
424✔
114
  const { canManageUsers: allowUserManagement } = useSelector(getUserCapabilities);
424✔
115
  const { total: acceptedDevices = 0 } = useSelector(getAcceptedDevices);
424!
116
  const announcement = useSelector(state => state.app.hostedAnnouncement);
1,463✔
117
  const deviceLimit = useSelector(getDeviceLimit);
424✔
118
  const firstLoginAfterSignup = useSelector(state => state.app.firstLoginAfterSignup);
1,463✔
119
  const { trackingConsentGiven: hasTrackingEnabled } = useSelector(getUserSettings);
424✔
120
  const inProgress = useSelector(state => state.deployments.byStatus.inprogress.total);
1,463✔
121
  const isEnterprise = useSelector(getIsEnterprise);
424✔
122
  const { isDemoMode: demo, hasMultitenancy, isHosted } = useSelector(getFeatures);
424✔
123
  const { isSearching, searchTerm, refreshTrigger } = useSelector(state => state.app.searchState);
1,463✔
124
  const multitenancy = hasMultitenancy || isEnterprise || isHosted;
424✔
125
  const { pending: pendingDevices } = useSelector(getDeviceCountsByStatus);
424✔
126
  const user = useSelector(getCurrentUser);
424✔
127
  const dispatch = useDispatch();
424✔
128
  const deviceTimer = useRef();
424✔
129
  const showHelptips = useSelector(getShowHelptips);
424✔
130

131
  const updateUsername = useCallback(() => {
424✔
132
    const userId = decodeSessionToken(getToken());
3✔
133
    if (gettingUser || !userId) {
3✔
134
      return;
1✔
135
    }
136
    setGettingUser(true);
2✔
137
    // get current user
138
    return dispatch(initializeSelf()).finally(() => setGettingUser(false));
2✔
139
  }, [dispatch, gettingUser]);
140

141
  useEffect(() => {
424✔
142
    if ((!sessionId || !user?.id || !user.email.length) && !gettingUser && !loggingOut) {
11✔
143
      updateUsername();
3✔
144
      return;
3✔
145
    }
146
    Tracking.setTrackingEnabled(hasTrackingEnabled);
8✔
147
    if (hasTrackingEnabled && user.id && organization.id) {
8!
148
      Tracking.setOrganizationUser(organization, user);
×
149
      if (firstLoginAfterSignup) {
×
150
        Tracking.pageview('/signup/complete');
×
151
        dispatch(setFirstLoginAfterSignup(false));
×
152
      }
153
    }
154
  }, [sessionId, user.id, user.email, gettingUser, loggingOut, user, hasTrackingEnabled, organization, updateUsername, firstLoginAfterSignup, dispatch]);
155

156
  useEffect(() => {
424✔
157
    const showOfferCookie = cookies.get('offer') === currentOffer.name;
5✔
158
    setHasOfferCookie(showOfferCookie);
5✔
159
    clearInterval(deviceTimer.current);
5✔
160
    deviceTimer.current = setInterval(() => dispatch(getAllDeviceCounts()), TIMEOUTS.refreshDefault);
180✔
161
    return () => {
5✔
162
      clearInterval(deviceTimer.current);
5✔
163
    };
164
  }, [dispatch]);
165

166
  const onLogoutClick = () => {
424✔
167
    setGettingUser(false);
1✔
168
    setLoggingOut(true);
1✔
169
    setAnchorEl(null);
1✔
170
    dispatch(logoutUser());
1✔
171
  };
172

173
  const onSearch = useCallback((searchTerm, refreshTrigger) => dispatch(setSearchState({ refreshTrigger, searchTerm, page: 1 })), [dispatch]);
424✔
174

175
  const onToggleTooltips = () => dispatch(setAllTooltipsReadState(showHelptips ? READ_STATES.read : READ_STATES.unread));
424!
176

177
  const setHideOffer = () => {
424✔
178
    cookies.set('offer', currentOffer.name, { path: '/', maxAge: 2629746 });
×
179
    setHasOfferCookie(true);
×
180
  };
181

182
  const showOffer =
183
    isHosted && moment().isBefore(currentOffer.expires) && (organization.trial ? currentOffer.trial : currentOffer[organization.plan]) && !hasOfferCookie;
424!
184

185
  const headerLogo = isDarkMode(mode) ? (isEnterprise ? whiteEnterpriseLogo : whiteLogo) : isEnterprise ? enterpriseLogo : logo;
424!
186

187
  return (
424✔
188
    <Toolbar id="fixedHeader" className={showOffer ? `${classes.header} ${classes.banner}` : classes.header}>
424!
189
      {!!announcement && (
436✔
190
        <Announcement
191
          announcement={announcement}
192
          errorIconClassName={classes.redAnnouncementIcon}
193
          iconClassName={classes.demoAnnouncementIcon}
194
          sectionClassName={classes.demoTrialAnnouncement}
195
          onHide={() => dispatch(setHideAnnouncement(true))}
×
196
        />
197
      )}
198
      {showOffer && <OfferHeader onHide={setHideOffer} />}
424!
199
      <div className="flexbox space-between">
200
        <div className="flexbox center-aligned">
201
          <Link to="/">
202
            <img id="logo" src={headerLogo} />
203
          </Link>
204
          {demo && <DemoNotification iconClassName={classes.demoAnnouncementIcon} sectionClassName={classes.demoTrialAnnouncement} />}
424!
205
          {organization.trial && (
424!
206
            <TrialNotification
207
              expiration={organization.trial_expiration}
208
              iconClassName={classes.demoAnnouncementIcon}
209
              sectionClassName={classes.demoTrialAnnouncement}
210
            />
211
          )}
212
        </div>
213
        <Search isSearching={isSearching} searchTerm={searchTerm} onSearch={onSearch} trigger={refreshTrigger} />
214
        <div className="flexbox center-aligned">
215
          <DeviceNotifications pending={pendingDevices} total={acceptedDevices} limit={deviceLimit} />
216
          <DeploymentNotifications inprogress={inProgress} />
217
          <Button
218
            className={`header-dropdown ${classes.dropDown}`}
219
            onClick={e => setAnchorEl(e.currentTarget)}
1✔
220
            startIcon={<AccountCircleIcon className={classes.buttonColor} />}
221
            endIcon={anchorEl ? <ArrowDropUpIcon /> : <ArrowDropDownIcon />}
424✔
222
          >
223
            {user.email}
224
          </Button>
225
          <Menu
226
            anchorEl={anchorEl}
227
            onClose={() => setAnchorEl(null)}
×
228
            open={Boolean(anchorEl)}
229
            anchorOrigin={{
230
              vertical: 'center',
231
              horizontal: 'center'
232
            }}
233
            transformOrigin={{
234
              vertical: 'bottom',
235
              horizontal: 'center'
236
            }}
237
          >
238
            <MenuItem component={Link} to="/settings">
239
              Settings
240
            </MenuItem>
241
            <MenuItem component={Link} to="/settings/my-profile">
242
              My profile
243
            </MenuItem>
244
            {multitenancy && (
839✔
245
              <MenuItem component={Link} to="/settings/organization-and-billing">
246
                My organization
247
              </MenuItem>
248
            )}
249
            {allowUserManagement && (
651✔
250
              <MenuItem component={Link} to="/settings/user-management">
251
                User management
252
              </MenuItem>
253
            )}
254
            <MenuItem onClick={onToggleTooltips}>{`Mark help tips as ${showHelptips ? '' : 'un'}read`}</MenuItem>
424!
255
            <MenuItem component={Link} to="/help/get-started">
256
              Help & support
257
            </MenuItem>
258
            <MenuItem onClick={onLogoutClick}>
259
              <ListItemText primary="Log out" />
260
              <ListItemSecondaryAction>
261
                <IconButton>
262
                  <ExitIcon className={classes.exitIcon} />
263
                </IconButton>
264
              </ListItemSecondaryAction>
265
            </MenuItem>
266
          </Menu>
267
        </div>
268
      </div>
269
    </Toolbar>
270
  );
271
};
272

273
export default Header;
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