• 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

79.05
/src/js/components/devices/base-devices.js
1
// Copyright 2020 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 from 'react';
15
import { Link } from 'react-router-dom';
16

17
import pluralize from 'pluralize';
18

19
import preauthImage from '../../../assets/img/preauthorize.png';
20
import { DEVICE_STATES } from '../../constants/deviceConstants';
21
import { rootfsImageVersion } from '../../constants/releaseConstants';
22
import Time, { ApproximateRelativeDate } from '../common/time';
23
import DeviceStatus from './device-status';
24

25
const propertyNameMap = {
187✔
26
  inventory: 'attributes',
27
  identity: 'identity_data',
28
  system: 'system',
29
  monitor: 'monitor',
30
  tags: 'tags'
31
};
32

33
export const defaultTextRender = ({ column, device }) => {
187✔
34
  const propertyName = propertyNameMap[column.attribute.scope] ?? column.attribute.scope;
4!
35
  const accessorTarget = device[propertyName] ?? device;
4!
36
  const attributeValue = accessorTarget[column.attribute.name] || accessorTarget[column.attribute.alternative] || device[column.attribute.name];
4✔
37
  return typeof attributeValue === 'object' ? JSON.stringify(attributeValue) : attributeValue;
4!
38
};
39

40
export const getDeviceIdentityText = ({ device = {}, idAttribute }) => {
187!
41
  const { id = '', identity_data = {}, tags = {} } = device;
53!
42
  // eslint-disable-next-line no-unused-vars
43
  const { status, ...remainingIds } = identity_data;
53✔
44
  const nonIdKey = Object.keys(remainingIds)[0];
53✔
45
  if (!idAttribute || idAttribute === 'id' || idAttribute === 'Device ID') {
53✔
46
    return id;
51✔
47
  } else if (idAttribute === 'name') {
2!
48
    return tags[idAttribute] ?? `${id.substring(0, 6)}...`;
×
49
  }
50
  return identity_data[idAttribute] ?? identity_data[nonIdKey] ?? id;
2!
51
};
52

53
const AttributeRenderer = ({ content, textContent }) => (
187✔
54
  <div title={textContent}>
35✔
55
    <div className="text-overflow">{content}</div>
56
  </div>
57
);
58

59
export const DefaultAttributeRenderer = ({ column, device, idAttribute }) => (
187✔
60
  <AttributeRenderer content={column.textRender({ device, column, idAttribute })} textContent={column.textRender({ device, column, idAttribute })} />
1✔
61
);
62

63
export const getDeviceSoftwareText = (attributes = {}) => attributes[rootfsImageVersion] || attributes.artifact_name || '-';
187!
64
export const DeviceSoftware = ({ device }) => (
187✔
65
  <AttributeRenderer content={getDeviceSoftwareText(device.attributes)} textContent={getDeviceSoftwareText(device.attributes)} />
17✔
66
);
67

68
export const getDeviceTypeText = (attributes = {}) => (attributes.device_type?.length ? attributes.device_type.join(',') : '-');
187!
69
export const DeviceTypes = ({ device }) => (
187✔
70
  <AttributeRenderer content={getDeviceTypeText(device.attributes)} textContent={getDeviceTypeText(device.attributes)} />
17✔
71
);
72

73
export const RelativeDeviceTime = ({ device }) => (
187✔
74
  <div>
17✔
75
    <ApproximateRelativeDate updateTime={device.updated_ts} />
76
  </div>
77
);
78

79
export const DeviceCreationTime = ({ device }) =>
187✔
80
  device.created_ts ? (
1!
81
    <div>
82
      <Time value={device.created_ts} />
83
    </div>
84
  ) : (
85
    '-'
86
  );
87

88
export const DeviceStatusRenderer = ({ device }) => (
187✔
89
  <div>
17✔
90
    <DeviceStatus device={device} />
91
  </div>
92
);
93

94
export const AcceptedEmptyState = ({ allCount }) => (
187✔
95
  <div className="dashboard-placeholder">
2✔
96
    <p>No devices found</p>
97
    {!allCount && (
3✔
98
      <>
99
        <p>No devices have been authorized to connect to the Mender server yet.</p>
100
        <p>
101
          Visit the <Link to="/help/get-started">Help section</Link> to learn how to connect devices to the Mender server.
102
        </p>
103
      </>
104
    )}
105
  </div>
106
);
107

108
export const PreauthorizedEmptyState = ({ canManageDevices, limitMaxed, onClick }) => (
187✔
109
  <div className="dashboard-placeholder">
1✔
110
    <p>There are no preauthorized devices.</p>
111
    {canManageDevices && (
1!
112
      <p>
113
        {limitMaxed ? 'Preauthorize devices' : <a onClick={onClick}>Preauthorize devices</a>} so that when they come online, they will connect to the server
×
114
        immediately
115
      </p>
116
    )}
117
    <img src={preauthImage} alt="preauthorize" />
118
  </div>
119
);
120

121
export const PendingEmptyState = ({ filters, highlightHelp }) => (
187✔
122
  <div className="dashboard-placeholder">
1✔
123
    <p>
124
      {filters.length
1!
125
        ? `There are no pending devices matching the selected ${pluralize('filters', filters.length)}`
126
        : 'There are no devices pending authorization'}
127
    </p>
128
    {highlightHelp ? (
1!
129
      <p>
130
        Visit the <Link to="/help/get-started">Help section</Link> to learn how to connect devices to the Mender server.
131
      </p>
132
    ) : null}
133
  </div>
134
);
135

136
export const RejectedEmptyState = ({ filters }) => (
187✔
137
  <div className="dashboard-placeholder">
1✔
138
    <p>{filters.length ? `There are no rejected devices matching the selected ${pluralize('filters', filters.length)}` : 'There are no rejected devices'}</p>
1!
139
  </div>
140
);
141

142
export const defaultHeaders = {
187✔
143
  currentSoftware: {
144
    title: 'Current software',
145
    attribute: { name: rootfsImageVersion, scope: 'inventory', alternative: 'artifact_name' },
146
    component: DeviceSoftware,
147
    sortable: true,
148
    textRender: getDeviceSoftwareText
149
  },
150
  deviceCreationTime: {
151
    title: 'First request',
152
    attribute: { name: 'created_ts', scope: 'system' },
153
    component: DeviceCreationTime,
154
    sortable: true
155
  },
156
  deviceId: {
157
    title: 'Device ID',
158
    attribute: { name: 'id', scope: 'identity' },
159
    sortable: true,
160
    textRender: ({ device }) => device.id
×
161
  },
162
  deviceStatus: {
163
    title: 'Status',
164
    attribute: { name: 'status', scope: 'identity' },
165
    component: DeviceStatusRenderer,
166
    sortable: true,
167
    textRender: defaultTextRender
168
  },
169
  deviceType: {
170
    title: 'Device type',
171
    attribute: { name: 'device_type', scope: 'inventory' },
172
    component: DeviceTypes,
173
    sortable: true,
174
    textRender: getDeviceTypeText
175
  },
176
  lastCheckIn: {
177
    title: 'Latest activity',
178
    attribute: { name: 'updated_ts', scope: 'system' },
179
    component: RelativeDeviceTime,
180
    sortable: true
181
  }
182
};
183

184
const baseDevicesRoute = '/devices';
187✔
185

186
const acceptedDevicesRoute = {
187✔
187
  key: DEVICE_STATES.accepted,
188
  groupRestricted: false,
189
  route: `${baseDevicesRoute}/${DEVICE_STATES.accepted}`,
190
  title: () => DEVICE_STATES.accepted,
23✔
191
  emptyState: AcceptedEmptyState,
192
  defaultHeaders: [defaultHeaders.deviceType, defaultHeaders.currentSoftware, defaultHeaders.lastCheckIn]
193
};
194

195
export const routes = {
187✔
196
  allDevices: {
197
    ...acceptedDevicesRoute,
198
    route: baseDevicesRoute,
199
    key: 'any',
200
    title: () => 'any'
23✔
201
  },
202
  devices: acceptedDevicesRoute,
203
  [DEVICE_STATES.accepted]: acceptedDevicesRoute,
204
  [DEVICE_STATES.pending]: {
205
    key: DEVICE_STATES.pending,
206
    groupRestricted: true,
207
    route: `${baseDevicesRoute}/${DEVICE_STATES.pending}`,
208
    title: count => `${DEVICE_STATES.pending}${count ? ` (${count})` : ''}`,
23!
209
    emptyState: PendingEmptyState,
210
    defaultHeaders: [defaultHeaders.deviceCreationTime, defaultHeaders.lastCheckIn]
211
  },
212
  [DEVICE_STATES.preauth]: {
213
    key: DEVICE_STATES.preauth,
214
    groupRestricted: true,
215
    route: `${baseDevicesRoute}/${DEVICE_STATES.preauth}`,
216
    title: () => DEVICE_STATES.preauth,
23✔
217
    emptyState: PreauthorizedEmptyState,
218
    defaultHeaders: [
219
      {
220
        ...defaultHeaders.deviceCreationTime,
221
        title: 'Date added'
222
      }
223
    ]
224
  },
225
  [DEVICE_STATES.rejected]: {
226
    key: DEVICE_STATES.rejected,
227
    groupRestricted: true,
228
    route: `${baseDevicesRoute}/${DEVICE_STATES.rejected}`,
229
    title: () => DEVICE_STATES.rejected,
23✔
230
    emptyState: RejectedEmptyState,
231
    defaultHeaders: [defaultHeaders.deviceCreationTime, defaultHeaders.lastCheckIn]
232
  }
233
};
234

235
export const sortingAlternatives = Object.values(routes)
187✔
236
  .reduce((accu, item) => [...accu, ...item.defaultHeaders], [])
1,122✔
237
  .reduce((accu, item) => {
238
    if (item.attribute.alternative) {
2,618✔
239
      accu[item.attribute.name] = item.attribute.alternative;
561✔
240
      accu[item.attribute.alternative] = item.attribute.name;
561✔
241
    }
242
    return accu;
2,618✔
243
  }, {});
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