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

mendersoftware / mender-server / 10423

11 Nov 2025 04:53PM UTC coverage: 74.435% (-0.1%) from 74.562%
10423

push

gitlab-ci

web-flow
Merge pull request #1071 from mendersoftware/dependabot/npm_and_yarn/frontend/main/development-dependencies-92732187be

3868 of 5393 branches covered (71.72%)

Branch coverage included in aggregate %.

5 of 5 new or added lines in 2 files covered. (100.0%)

176 existing lines in 95 files now uncovered.

64605 of 86597 relevant lines covered (74.6%)

7.74 hits per line

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

98.01
/frontend/src/js/components/helptips/HelpTooltips.tsx
1
// Copyright 2017 Northern.tech AS
2✔
2
//
2✔
3
//    Licensed under the Apache License, Version 2.0 (the "License");
2✔
4
//    you may not use this file except in compliance with the License.
2✔
5
//    You may obtain a copy of the License at
2✔
6
//
2✔
7
//        http://www.apache.org/licenses/LICENSE-2.0
2✔
8
//
2✔
9
//    Unless required by applicable law or agreed to in writing, software
2✔
10
//    distributed under the License is distributed on an "AS IS" BASIS,
2✔
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2✔
12
//    See the License for the specific language governing permissions and
2✔
13
//    limitations under the License.
2✔
14
import type { ComponentType, FC } from 'react';
2✔
15
import { useDispatch, useSelector } from 'react-redux';
2✔
16

2✔
17
import ConfigurationObject from '@northern.tech/common-ui/ConfigurationObject';
2✔
18
import DocsLink from '@northern.tech/common-ui/DocsLink';
2✔
19
import { SupportLink } from '@northern.tech/common-ui/SupportLink';
2✔
20
import storeActions from '@northern.tech/store/actions';
2✔
21
import { Device } from '@northern.tech/store/api/types';
2✔
22
import { READ_STATES } from '@northern.tech/store/constants';
2✔
23
import { getFeatures } from '@northern.tech/store/selectors';
2✔
24

2✔
25
const { setSnackbar } = storeActions;
64✔
26

2✔
27
const AuthExplainButton = () => (
64✔
28
  <>
3✔
29
    <h3>Device authorization status</h3>
2✔
30
    <p>
2✔
31
      Each device sends an authentication request containing its identity attributes and its current public key. You can accept, reject or dismiss these
2✔
32
      requests to determine the authorization status of the device.
2✔
33
    </p>
2✔
34
    <p>
2✔
35
      In cases such as key rotation, each device may have more than one identity/key combination listed. See the documentation for more on{' '}
2✔
36
      <DocsLink path="overview/device-authentication" title="Device authentication" />.
2✔
37
    </p>
2✔
38
  </>
2✔
39
);
2✔
40

2✔
41
const AuthButton = () => (
64✔
42
  <>
3✔
43
    <h3>Authorize devices</h3>
2✔
44
    <p>
2✔
45
      Expand this section to view the authentication options for this device. You can decide whether to accept it, reject it, or just dismiss this device for
2✔
46
      now.
2✔
47
    </p>
2✔
48
    <p>
2✔
49
      See the documentation for more on <DocsLink path="overview/device-authentication" title="Device authentication" />.
2✔
50
    </p>
2✔
51
  </>
2✔
52
);
2✔
53

2✔
54
const AddGroup = () => (
64✔
55
  <>
3✔
56
    <h3>Device groups</h3>
2✔
57
    <p>
2✔
58
      It is possible to create groups of devices. Once you have created a group and added one or more devices to it, you can deploy an update to that specific
2✔
59
      group only.
2✔
60
    </p>
2✔
61
  </>
2✔
62
);
2✔
63

2✔
64
const ExpandArtifact = () => (
64✔
65
  <>
3✔
66
    <h3>Device type compatibility</h3>
2✔
67
    <p>
2✔
68
      Mender Artifacts have <b>Device types compatible</b> as part of their metadata. All devices report which device type they are, as part of their inventory
2✔
69
      information. During a deployment, Mender makes sure that a device will only download and install an Artifact it is compatible with.
2✔
70
    </p>
2✔
71
    <p>You can click on each Artifact in the Release to expand the row and view more information about it.</p>
2✔
72
    <p>
2✔
73
      For more information on how to specify the device type compatibility and other artifact metadata,{' '}
2✔
74
      <DocsLink path="artifact-creation/create-an-artifact" title="see the documentation" />.
2✔
75
    </p>
2✔
76
  </>
2✔
77
);
2✔
78

2✔
79
const DeviceSupportTip = () => (
64✔
80
  <p>
3✔
81
    The steps in the guide should work on most operating systems in the Debian family (e.g. Debian, Ubuntu, Raspberry Pi OS) and devices based on ARMv6 or newer
2✔
82
    (e.g. Raspberry Pi 2/3/4, Beaglebone). Visit <DocsLink path="overview/device-support" title="our documentation" /> for more information about device
2✔
83
    support.
2✔
84
  </p>
2✔
85
);
2✔
86

2✔
87
const ConfigureTimezoneTip = () => (
64✔
88
  <>
3✔
89
    To see the effects of applying a configuration to your device you can set one of the below values to modify the timezone of your device. While all values
2✔
90
    from <i>timedatectl list-timezones</i> will work, to easily see the impact of the changed value you can use one of the following values:
2✔
91
    <ul>
2✔
92
      <li>Europe/Oslo</li>
2✔
93
      <li>America/Los_Angeles</li>
2✔
94
      <li>Asia/Tokyo</li>
2✔
95
    </ul>
2✔
96
    Once the configuration has been applied you can see the effect by opening the Remote Terminal to the device and executing the <i>date</i> command.
2✔
97
  </>
2✔
98
);
2✔
99

2✔
100
const ConfigureRaspberryLedTip = () => {
64✔
101
  const dispatch = useDispatch();
3✔
102
  return (
3✔
103
    <>
2✔
104
      To see the effects of applying a configuration to your device you can set one of the below values to modify the behaviour of your Raspberry Pi green
2✔
105
      status LED
2✔
106
      <ConfigurationObject
2✔
107
        className="margin-top-small margin-bottom-small"
2✔
108
        config={{
2✔
109
          mmc0: 'The default, which blinks the led on storage activity',
2✔
110
          on: 'Turn on the light permanently',
2✔
111
          off: 'Turn off the light permanently',
2✔
112
          heartbeat: 'Enable heartbeat blinking'
2✔
113
        }}
2✔
114
        compact
2✔
UNCOV
115
        setSnackbar={(...args) => dispatch(setSnackbar(...args))}
2✔
116
      />
2✔
117
      There are other possible values, but we won&apos;t advertise them here. See
2✔
118
      <a href="http://www.d3noob.org/2020/07/controlling-activity-led-on-raspberry-pi.html" target="_blank" rel="noopener noreferrer">
2✔
119
        this blog post
2✔
120
      </a>{' '}
2✔
121
      or{' '}
2✔
122
      <a href="https://www.raspberrypi.org/forums/viewtopic.php?t=273194#p1658930" target="_blank" rel="noopener noreferrer">
2✔
123
        in the Raspberry Pi forums
2✔
124
      </a>{' '}
2✔
125
      for more information.
2✔
126
    </>
2✔
127
  );
2✔
128
};
2✔
129

2✔
130
const ConfigureAddOnTip = () => (
64✔
131
  <p>
3✔
132
    Mender deploys the configuration attributes using the same mechanisms as software updates. The configuration is stored as a JSON file at
2✔
133
    <code>/var/lib/mender-configure/device-config.json</code> on the device and then all the scripts in{' '}
2✔
134
    <code>/usr/lib/mender-configure/apply-device-config.d/</code> are executed to apply the configuration attributes. To add a new configuration attribute, you
2✔
135
    simply need to input it in the UI and add a script to that directory that applies it accordingly.
2✔
136
  </p>
2✔
137
);
2✔
138

2✔
139
const NameTagTip = () => (
64✔
140
  <>
3✔
141
    The <i>Name</i> tag will be available as a device indentifier too.
2✔
142
  </>
2✔
143
);
2✔
144

2✔
145
const NameFilterTip = () => <>Filtering by name is limited to devices with a previously defined name.</>;
64✔
146

2✔
147
const DeviceTypeTip = () => (
64✔
148
  <>
3✔
149
    <p>
2✔
150
      If you don&apos;t see your exact device on the list, choose <i>Generic ARMv6 or newer</i> to continue the tutorial for now.
2✔
151
    </p>
2✔
152
    <p>
2✔
153
      (Note: if your device is <i>not</i> based on ARMv6 or newer, the tutorial won&apos;t work - instead, go back and use the virtual device)
2✔
154
    </p>
2✔
155
  </>
2✔
156
);
2✔
157

2✔
158
const TwoFactorNote = ({ className }: { className?: string }) => (
64✔
159
  <div className={className}>
3✔
160
    Two Factor Authentication is enabled for your account. If you haven&apos;t set up a 3rd party authentication app with a verification code, please contact an
2✔
161
    administrator.
2✔
162
  </div>
2✔
163
);
2✔
164

2✔
165
const AuditlogExplanation = () => <>The audit log shows the history of changes made to your Devices, Artifacts, Deployments, and user management.</>;
64✔
166

2✔
167
const DashboardWidget = () => (
64✔
168
  <>Add dashboard widgets to visualize the software distribution or geographical location of all your devices, or a group of your devices.</>
3✔
169
);
2✔
170

2✔
171
const ScheduleDeployment = () => (
64✔
172
  <>
3✔
173
    This time is relative to the server only – each device&apos;s time zone will not be taken into account. Devices across different time zones will receive the
2✔
174
    update at the same time.
2✔
175
  </>
2✔
176
);
2✔
177

2✔
178
const GroupDeployment = () => (
64✔
179
  <>The deployment will skip any devices in the group that are already on the target Release version, or that have an incompatible device type.</>
3✔
180
);
2✔
181

2✔
182
const ForceDeployment = () => (
64✔
183
  <>
3✔
184
    <h3>Force update</h3>
2✔
185
    <p>This will make the Mender client install the update even if the selected release is already installed.</p>
2✔
186
  </>
2✔
187
);
2✔
188

2✔
189
const ArtifactUpload = () => <>Upload an Artifact to an existing or new Release</>;
64✔
190

2✔
191
const PhasedPausedDeployments = () => (
64✔
192
  <>
3✔
193
    This feature is not available on <b>phased deployments</b>. If you&apos;d like to set pause states between update steps, go back and adjust the rollout
2✔
194
    schedule to a <b>single phase</b>.
2✔
195
  </>
2✔
196
);
2✔
197

2✔
198
const ResetHistory = () => <>Greyed out items will not be considered during deployment roll out</>;
64✔
199

2✔
200
const MenderArtifactUpload = () => (
64✔
201
  <>
3✔
202
    If there is no Release matching this Artifact’s name, a new Release will be created for this Artifact.
2✔
203
    <br />
2✔
204
    <br />
2✔
205
    If there is already a Release matching this Artifact’s name, the Artifact will be grouped in that Release.
2✔
206
  </>
2✔
207
);
2✔
208

2✔
209
const SingleFileUpload = () => <>This will generate a single file application update Artifact, which requires some additional metadata to be entered.</>;
64✔
210

2✔
211
const Webhooks = () => (
64✔
212
  <>Use webhooks to send data about device lifecycle events to third-party systems. Currently you can only have one integration set up at a time.</>
3✔
213
);
2✔
214

2✔
215
const WebhookEvents = () => (
64✔
216
  <>
3✔
217
    You can select which type(s) of events the webhook will receive. Device authentication includes when devices are provisioned, decommissioned, or
2✔
218
    authentication status changes.
2✔
219
  </>
2✔
220
);
2✔
221

2✔
222
const WebhookSecret = () => (
64✔
223
  <>
3✔
224
    The secret is used for signing the requests sent to your webhook, to verify their authenticity. It is optional, but highly recommended for security. The
2✔
225
    secret must be a hexidecimal string (including only characters from A-F and 0-9).
2✔
226
  </>
2✔
227
);
2✔
228

2✔
229
const SsoMetadata = () => <>Submit the metadata document from your Identity Provider</>;
64✔
230

2✔
231
const ReleaseName = () => (
64✔
232
  <>
3✔
233
    If a Release with this name already exists, this new Artifact may be grouped into a Release with other Artifacts of the same name - so long as they are
2✔
234
    compatible with different device types
2✔
235
  </>
2✔
236
);
2✔
237

2✔
238
const TenantAdmin = () => (
64✔
239
  <>
3✔
240
    Set the user who will have the admin role when this tenant is created. This can be a user who already has a Mender account, or a brand new user. The tenant
2✔
241
    admin will be able to change which user(s) have this role once they begin using the tenant.
2✔
242
  </>
2✔
243
);
2✔
244

2✔
245
const SubTenantDeviceLimit = () => (
64✔
246
  <>
3✔
247
    Set the maximum number of accepted devices this tenant can have connected to the server at any time. You can adjust this later. Each tenants’ amount of
2✔
248
    accepted devices will count towards your total device limit.
2✔
249
  </>
2✔
250
);
2✔
251

2✔
252
const SubTenantDeltaArtifactGeneration = () => <>This option will enable the server-side generation of Delta Artifacts for the created tenant when turned on</>;
64✔
253

2✔
254
const SubTenantSSO = () => (
64✔
255
  <>
3✔
256
    The created tenant will inherit the same Single Sign-On configuration as this Service Provider tenant. The created tenant’s admin user will not be able to
2✔
257
    change the SSO settings later.
2✔
258
  </>
2✔
259
);
2✔
260

2✔
261
const AttributeLimit = () => {
64✔
262
  const { isHosted } = useSelector(getFeatures);
3✔
263
  return isHosted ? (
3!
264
    <>
2✔
265
      Expand to see the list of attributes currently in use. Please <SupportLink variant="ourTeam" /> if your use case requires a different set of attributes.
2✔
266
    </>
2✔
267
  ) : (
2✔
268
    <>Expand to see the list of attributes currently in use.</>
2✔
269
  );
2✔
270
};
2✔
271
const TenantInitialAdmin = () => (
64✔
272
  <>
3✔
273
    The user that was assigned as admin for this tenant when it was created. There is a chance the admin user will have changed or this user no longer exists in
2✔
274
    this tenant.
2✔
275
  </>
2✔
276
);
2✔
277

2✔
278
const PlanUpgradeEmail = () => (
64✔
279
  <>
3✔
280
    This email address will receive all payment receipts and notifications about pricing and device limits. It does not necessarily have to belong to a user in
2✔
281
    your Mender account
2✔
282
  </>
2✔
283
);
2✔
284

2✔
285
export type HelpTooltipComponent = {
2✔
286
  Component?: FC;
2✔
287
  id: string;
2✔
288
  isRelevant?: (props: { device?: Device }) => boolean;
2✔
289
  readState?: keyof typeof READ_STATES;
2✔
290
  SpecialComponent?: ComponentType<{ className?: string; device?: Device }>;
2✔
291
};
2✔
292

2✔
293
export const HELPTOOLTIPS: Record<string, HelpTooltipComponent> = {
64✔
294
  addGroup: { id: 'addGroup', Component: AddGroup },
2✔
295
  artifactUpload: { id: 'artifactUpload', Component: ArtifactUpload },
2✔
296
  attributeLimit: { id: 'attributeLimit', Component: AttributeLimit },
2✔
297
  auditlogExplanation: { id: 'auditlogExplanation', Component: AuditlogExplanation },
2✔
298
  authButton: { id: 'authButton', Component: AuthButton },
2✔
299
  authExplainButton: { id: 'authExplainButton', Component: AuthExplainButton },
2✔
300
  configureAddOnTip: { id: 'configureAddOnTip', Component: ConfigureAddOnTip },
2✔
301
  configureRaspberryLedTip: {
2✔
302
    id: 'configureRaspberryLedTip',
2✔
303
    Component: ConfigureRaspberryLedTip,
2✔
304
    isRelevant: ({ device = {} }) => {
2!
305
      const { attributes = {} } = device;
2!
306
      const { device_type = [] } = attributes;
2!
307
      return ['raspberry', 'rpi'].some(type => device_type.some(deviceType => deviceType.startsWith(type)));
2✔
308
    }
2✔
309
  },
2✔
310
  configureTimezoneTip: {
2✔
311
    id: 'configureTimezoneTip',
2✔
312
    Component: ConfigureTimezoneTip,
2✔
313
    isRelevant: ({ device = {} }) => {
2!
314
      const { attributes = {} } = device;
2!
315
      const { device_type = [] } = attributes;
2!
316
      return ['generic-x86_64', 'raspberry', 'rpi', 'qemux86-64'].some(type => device_type.some(deviceType => deviceType.startsWith(type)));
2✔
317
    }
2✔
318
  },
2✔
319
  dashboardWidget: { id: 'dashboardWidget', Component: DashboardWidget },
2✔
320
  deviceSupportTip: { id: 'deviceSupportTip', Component: DeviceSupportTip },
2✔
321
  deviceTypeTip: { id: 'deviceTypeTip', Component: DeviceTypeTip },
2✔
322
  expandArtifact: { id: 'expandArtifact', Component: ExpandArtifact },
2✔
323
  forceDeployment: { id: 'forceDeployment', Component: ForceDeployment },
2✔
324
  groupDeployment: { id: 'groupDeployment', Component: GroupDeployment },
2✔
325
  menderArtifactUpload: { id: 'menderArtifactUpload', Component: MenderArtifactUpload },
2✔
326
  nameFilterTip: { id: 'nameFilterTip', Component: NameFilterTip },
2✔
327
  nameTagTip: { id: 'nameTagTip', Component: NameTagTip },
2✔
328
  phasedPausedDeployments: { id: 'phasedPausedDeployments', Component: PhasedPausedDeployments },
2✔
329
  planUpgradeEmail: { id: 'planUpgradeEmail', Component: PlanUpgradeEmail },
2✔
330
  releaseName: { id: 'releaseName', Component: ReleaseName },
2✔
331
  resetHistory: { id: 'resetHistory', Component: ResetHistory },
2✔
332
  ssoMetadata: { id: 'ssoMetadata', Component: SsoMetadata },
2✔
333
  scheduleDeployment: { id: 'scheduleDeployment', Component: ScheduleDeployment },
2✔
334
  singleFileUpload: { id: 'singleFileUpload', Component: SingleFileUpload },
2✔
335
  subTenantDeltaArtifactGeneration: { id: 'subTenantDeltaArtifactGeneration', Component: SubTenantDeltaArtifactGeneration },
2✔
336
  subTenantDeviceLimit: { id: 'subTenantDeviceLimit', Component: SubTenantDeviceLimit },
2✔
337
  subTenantSSO: { id: 'subTenantSSO', Component: SubTenantSSO },
2✔
338
  tenantAdmin: { id: 'tenantAdmin', Component: TenantAdmin },
2✔
339
  tenantInitialAdmin: { id: 'tenantInitialAdmin', Component: TenantInitialAdmin },
2✔
340
  twoFactorNote: { id: 'twoFactorNote', SpecialComponent: TwoFactorNote },
2✔
341
  webhookEvents: { id: 'webhookEvents', Component: WebhookEvents },
2✔
342
  webhooks: { id: 'webhooks', Component: Webhooks },
2✔
343
  webhookSecret: { id: 'webhookSecret', Component: WebhookSecret }
2✔
344
};
2✔
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