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

mendersoftware / gui / 951400782

pending completion
951400782

Pull #3900

gitlab-ci

web-flow
chore: bump @testing-library/jest-dom from 5.16.5 to 5.17.0

Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 5.16.5 to 5.17.0.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v5.16.5...v5.17.0)

---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #3900: chore: bump @testing-library/jest-dom from 5.16.5 to 5.17.0

4446 of 6414 branches covered (69.32%)

8342 of 10084 relevant lines covered (82.73%)

186.0 hits per line

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

81.08
/src/js/components/devices/widgets/devicequickactions.js
1
// Copyright 2021 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, { forwardRef, useState } from 'react';
15
import { useSelector } from 'react-redux';
16

17
import {
18
  AddCircle as AddCircleIcon,
19
  CheckCircle as CheckCircleIcon,
20
  HeightOutlined as HeightOutlinedIcon,
21
  HighlightOffOutlined as HighlightOffOutlinedIcon,
22
  RemoveCircleOutline as RemoveCircleOutlineIcon,
23
  Replay as ReplayIcon
24
} from '@mui/icons-material';
25
import { SpeedDial, SpeedDialAction, SpeedDialIcon } from '@mui/material';
26
import { speedDialActionClasses } from '@mui/material/SpeedDialAction';
27
import { makeStyles } from 'tss-react/mui';
28

29
import { mdiTrashCanOutline as TrashCan } from '@mdi/js';
30
import pluralize from 'pluralize';
31

32
import GatewayIcon from '../../../../assets/img/gateway.svg';
33
import { DEVICE_STATES, UNGROUPED_GROUP } from '../../../constants/deviceConstants';
34
import { stringToBoolean } from '../../../helpers';
35
import { getDeviceById, getFeatures, getMappedDevicesList, getTenantCapabilities, getUserCapabilities } from '../../../selectors';
36
import MaterialDesignIcon from '../../common/materialdesignicon';
37

38
const defaultActions = {
10✔
39
  accept: {
40
    icon: <CheckCircleIcon className="green" />,
41
    key: 'accept',
42
    title: pluralized => `Accept ${pluralized}`,
1✔
43
    action: ({ onAuthorizationChange, selection }) => onAuthorizationChange(selection, DEVICE_STATES.accepted),
×
44
    checkRelevance: ({ device, userCapabilities: { canWriteDevices } }) =>
45
      canWriteDevices && [DEVICE_STATES.pending, DEVICE_STATES.rejected].includes(device.status)
18✔
46
  },
47
  dismiss: {
48
    icon: <RemoveCircleOutlineIcon className="red" />,
49
    key: 'dismiss',
50
    title: pluralized => `Dismiss ${pluralized}`,
14✔
51
    action: ({ onDeviceDismiss, selection }) => onDeviceDismiss(selection),
×
52
    checkRelevance: ({ device, userCapabilities: { canWriteDevices } }) =>
53
      canWriteDevices && [DEVICE_STATES.accepted, DEVICE_STATES.pending, DEVICE_STATES.preauth, DEVICE_STATES.rejected, 'noauth'].includes(device.status)
30✔
54
  },
55
  reject: {
56
    icon: <HighlightOffOutlinedIcon className="red" />,
57
    key: 'reject',
58
    title: pluralized => `Reject ${pluralized}`,
14✔
59
    action: ({ onAuthorizationChange, selection }) => onAuthorizationChange(selection, DEVICE_STATES.rejected),
×
60
    checkRelevance: ({ device, userCapabilities: { canWriteDevices } }) =>
61
      canWriteDevices && [DEVICE_STATES.accepted, DEVICE_STATES.pending].includes(device.status)
30✔
62
  },
63
  addToGroup: {
64
    icon: <AddCircleIcon className="green" />,
65
    key: 'group-add',
66
    title: pluralized => `Add selected ${pluralized} to a group`,
13✔
67
    action: ({ onAddDevicesToGroup, selection }) => onAddDevicesToGroup(selection),
×
68
    checkRelevance: ({ selectedGroup, userCapabilities: { canWriteDevices } }) => canWriteDevices && !selectedGroup
30✔
69
  },
70
  moveToGroup: {
71
    icon: <HeightOutlinedIcon className="rotated ninety" />,
72
    key: 'group-change',
73
    title: pluralized => `Move selected ${pluralized} to another group`,
1✔
74
    action: ({ onAddDevicesToGroup, selection }) => onAddDevicesToGroup(selection),
×
75
    checkRelevance: ({ selectedGroup, userCapabilities: { canWriteDevices } }) => canWriteDevices && !!selectedGroup
18✔
76
  },
77
  removeFromGroup: {
78
    icon: <MaterialDesignIcon path={TrashCan} />,
79
    key: 'group-remove',
80
    title: pluralized => `Remove selected ${pluralized} from this group`,
1✔
81
    action: ({ onRemoveDevicesFromGroup, selection }) => onRemoveDevicesFromGroup(selection),
×
82
    checkRelevance: ({ selectedGroup, userCapabilities: { canWriteDevices } }) => canWriteDevices && selectedGroup && selectedGroup !== UNGROUPED_GROUP.id
18✔
83
  },
84
  promoteToGateway: {
85
    icon: <GatewayIcon style={{ width: 20 }} />,
86
    key: 'promote-to-gateway',
87
    title: () => 'Promote to gateway',
×
88
    action: ({ onPromoteGateway, selection }) => onPromoteGateway(selection),
×
89
    checkRelevance: ({ device, features, tenantCapabilities: { isEnterprise } }) =>
90
      features.isHosted && isEnterprise && !stringToBoolean(device.attributes?.mender_is_gateway) && device.status === DEVICE_STATES.accepted
18!
91
  },
92
  createDeployment: {
93
    icon: <ReplayIcon />,
94
    key: 'create-deployment',
95
    title: (pluralized, count) => `Create deployment for ${pluralize('this', count)} ${pluralized}`,
13✔
96
    action: ({ onCreateDeployment, selection }) => onCreateDeployment(selection),
×
97
    checkRelevance: ({ device, userCapabilities: { canDeploy, canReadReleases } }) =>
98
      canDeploy && canReadReleases && device && device.status === DEVICE_STATES.accepted
30✔
99
  }
100
};
101

102
const useStyles = makeStyles()(theme => ({
10✔
103
  container: {
104
    display: 'flex',
105
    position: 'fixed',
106
    bottom: theme.spacing(6.5),
107
    right: theme.spacing(6.5),
108
    zIndex: 10,
109
    minWidth: 400,
110
    alignItems: 'flex-end',
111
    justifyContent: 'flex-end',
112
    pointerEvents: 'none',
113
    [`.${speedDialActionClasses.staticTooltipLabel}`]: {
114
      minWidth: 'max-content'
115
    }
116
  },
117
  fab: { margin: theme.spacing(2) },
118
  label: {
119
    marginRight: theme.spacing(2),
120
    marginBottom: theme.spacing(4)
121
  }
122
}));
123

124
export const DeviceQuickActions = ({ actionCallbacks, deviceId, selectedGroup }, ref) => {
10✔
125
  const [showActions, setShowActions] = useState(false);
18✔
126
  const features = useSelector(getFeatures);
18✔
127
  const tenantCapabilities = useSelector(getTenantCapabilities);
18✔
128
  const userCapabilities = useSelector(getUserCapabilities);
18✔
129
  const { selection: selectedRows } = useSelector(state => state.devices.deviceList);
35✔
130
  const singleDevice = useSelector(state => getDeviceById(state, deviceId));
35✔
131
  const devices = useSelector(state => getMappedDevicesList(state, 'deviceList'));
35✔
132
  const { classes } = useStyles();
18✔
133

134
  const selectedDevices = deviceId ? [singleDevice] : selectedRows.map(row => devices[row]);
33✔
135
  const actions = Object.values(defaultActions).reduce((accu, action) => {
18✔
136
    if (selectedDevices.every(device => device && action.checkRelevance({ device, features, selectedGroup, tenantCapabilities, userCapabilities }))) {
208✔
137
      accu.push(action);
57✔
138
    }
139
    return accu;
144✔
140
  }, []);
141

142
  const pluralized = pluralize('devices', selectedDevices.length);
18✔
143
  return (
18✔
144
    <div className={classes.container} ref={ref}>
145
      <div className={classes.label}>{deviceId ? 'Device actions' : `${selectedDevices.length} ${pluralized} selected`}</div>
18✔
146
      <SpeedDial
147
        className={classes.fab}
148
        ariaLabel="device-actions"
149
        icon={<SpeedDialIcon />}
150
        onClose={() => setShowActions(false)}
×
151
        onOpen={setShowActions}
152
        open={Boolean(showActions)}
153
      >
154
        {actions.map(action => (
155
          <SpeedDialAction
57✔
156
            key={action.key}
157
            aria-label={action.key}
158
            icon={action.icon}
159
            tooltipTitle={action.title(pluralized, selectedDevices.length)}
160
            tooltipOpen
161
            onClick={() => action.action({ ...actionCallbacks, selection: selectedDevices })}
×
162
          />
163
        ))}
164
      </SpeedDial>
165
    </div>
166
  );
167
};
168

169
export default forwardRef(DeviceQuickActions);
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