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

mendersoftware / gui / 1113439055

19 Dec 2023 09:01PM UTC coverage: 82.752% (-17.2%) from 99.964%
1113439055

Pull #4258

gitlab-ci

mender-test-bot
chore: Types update

Signed-off-by: Mender Test Bot <mender@northern.tech>
Pull Request #4258: chore: Types update

4326 of 6319 branches covered (0.0%)

8348 of 10088 relevant lines covered (82.75%)

189.39 hits per line

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

71.43
/src/js/components/common/dialogs/physicaldeviceonboarding.js
1
// Copyright 2019 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, { useEffect, useState } from 'react';
15
import { useDispatch, useSelector } from 'react-redux';
16
import { Link } from 'react-router-dom';
17

18
import { InfoOutlined as InfoIcon } from '@mui/icons-material';
19
import { Autocomplete, TextField } from '@mui/material';
20
import { createFilterOptions } from '@mui/material/useAutocomplete';
21

22
import { advanceOnboarding, setOnboardingApproach, setOnboardingDeviceType } from '../../../actions/onboardingActions';
23
import { EXTERNAL_PROVIDER } from '../../../constants/deviceConstants';
24
import { onboardingSteps } from '../../../constants/onboardingConstants';
25
import { getDebConfigurationCode, versionCompare } from '../../../helpers';
26
import {
27
  getCurrentSession,
28
  getFeatures,
29
  getFullVersionInformation,
30
  getIsEnterprise,
31
  getIsPreview,
32
  getOnboardingState,
33
  getOrganization
34
} from '../../../selectors';
35
import { HELPTOOLTIPS, MenderHelpTooltip } from '../../helptips/helptooltips';
36
import CopyCode from '../copy-code';
37
import DocsLink from '../docslink';
38
import { MenderTooltipClickable } from '../mendertooltip';
39

40
const filter = createFilterOptions();
3✔
41

42
const types = [
3✔
43
  { title: 'Raspberry Pi 3', value: 'raspberrypi3' },
44
  { title: 'Raspberry Pi 4', value: 'raspberrypi4' }
45
];
46

47
export const ConvertedImageNote = () => (
3✔
48
  <p>
2✔
49
    We prepared an image, ready for Mender, for you to start with. You can find it in the{' '}
50
    <DocsLink path="get-started/preparation/prepare-a-raspberry-pi-device" title="Prepare a Raspberry Pi device" /> documentation, which also contains
51
    instructions for initial device setup. Once you&apos;re done flashing you can go ahead and proceed to the next step.
52
  </p>
53
);
54

55
const IntegrationsLink = () => (
3✔
56
  <Link to="/settings/integrations" target="_blank">
×
57
    Integration settings
58
  </Link>
59
);
60

61
export const ExternalProviderTip = ({ hasExternalIntegration, integrationProvider }) => (
3✔
62
  <MenderTooltipClickable
6✔
63
    className="clickable flexbox muted"
64
    placement="bottom"
65
    style={{ alignItems: 'end', marginBottom: 3 }}
66
    title={
67
      <div style={{ maxWidth: 350 }}>
68
        {hasExternalIntegration ? (
6✔
69
          <p>
70
            Devices added here will be automatically integrated with the <i>{EXTERNAL_PROVIDER[integrationProvider].title}</i> you set in the{' '}
71
            <IntegrationsLink />.
72
          </p>
73
        ) : (
74
          <p>
75
            To connect your devices with <i>{EXTERNAL_PROVIDER[integrationProvider].title}</i>, go to <IntegrationsLink /> and set up the integration.
76
          </p>
77
        )}
78
      </div>
79
    }
80
  >
81
    <InfoIcon />
82
  </MenderTooltipClickable>
83
);
84

85
export const DeviceTypeSelectionStep = ({
3✔
86
  hasConvertedImage,
87
  hasExternalIntegration,
88
  integrationProvider,
89
  onboardingState,
90
  onSelect,
91
  selection = '',
×
92
  version
93
}) => {
94
  const shouldShowOnboardingTip = !onboardingState.complete && onboardingState.showTips;
5✔
95
  const hasExternalIntegrationSupport = versionCompare(version, '3.2') > -1;
5✔
96
  return (
5✔
97
    <>
98
      <h4>Enter your device type</h4>
99
      <p>Setting this attribute on the device ensures that the device will only receive updates for compatible software releases.</p>
100

101
      <div style={{ display: 'grid', gridTemplateColumns: 'max-content 50px 150px', placeItems: 'end center' }}>
102
        <Autocomplete
103
          id="device-type-selection"
104
          autoSelect
105
          autoHighlight
106
          filterSelectedOptions
107
          freeSolo
108
          getOptionLabel={option => {
109
            // Value selected with enter, right from the input
110
            if (typeof option === 'string') {
9!
111
              return option;
9✔
112
            }
113
            if (option.key === 'custom' && option.value === selection) {
×
114
              return option.value;
×
115
            }
116
            return option.title;
×
117
          }}
118
          handleHomeEndKeys
119
          includeInputInList
120
          filterOptions={(options, params) => {
121
            const filtered = filter(options, params);
×
122
            if (filtered.length !== 1 && params.inputValue !== '') {
×
123
              filtered.push({
×
124
                value: params.inputValue,
125
                key: 'custom',
126
                title: `Use "${params.inputValue}"`
127
              });
128
            }
129
            return filtered;
×
130
          }}
131
          options={types}
132
          onChange={onSelect}
133
          renderInput={params => (
134
            <TextField {...params} label="Device type" placeholder="Choose a device type" InputProps={{ ...params.InputProps }} style={{ marginTop: 0 }} />
6✔
135
          )}
136
          style={{ maxWidth: 300 }}
137
          value={selection}
138
        />
139
        {hasExternalIntegrationSupport && <ExternalProviderTip hasExternalIntegration={hasExternalIntegration} integrationProvider={integrationProvider} />}
10✔
140
        {shouldShowOnboardingTip ? <MenderHelpTooltip id={HELPTOOLTIPS.deviceTypeTip.id} placement="bottom" /> : <div />}
5✔
141
      </div>
142
      {hasConvertedImage && <ConvertedImageNote />}
6✔
143
    </>
144
  );
145
};
146

147
export const InstallationStep = ({ advanceOnboarding, selection, onboardingState, ...remainingProps }) => {
3✔
148
  const codeToCopy = getDebConfigurationCode({ ...remainingProps, deviceType: selection, isOnboarding: !onboardingState.complete });
1✔
149
  return (
1✔
150
    <>
151
      <h4>Log into your device and install the Mender client</h4>
152
      <p>
153
        Copy & paste and run this command <b>on your device</b>:
154
      </p>
155
      <CopyCode code={codeToCopy} onCopy={() => advanceOnboarding(onboardingSteps.DASHBOARD_ONBOARDING_START)} withDescription={true} />
×
156
      <p>This downloads the Mender client on the device, sets the configuration and starts the client.</p>
157
      <p>
158
        Once the client has started, your device will attempt to connect to the server. It will then appear in your Pending devices tab and you can continue.
159
      </p>
160
    </>
161
  );
162
};
163

164
const steps = {
3✔
165
  1: DeviceTypeSelectionStep,
166
  2: InstallationStep
167
};
168

169
const integrationProvider = EXTERNAL_PROVIDER['iot-hub'].provider;
3✔
170

171
export const PhysicalDeviceOnboarding = ({ progress }) => {
3✔
172
  const [selection, setSelection] = useState('');
4✔
173
  const hasExternalIntegration = useSelector(state => {
4✔
174
    const { credentials = {} } = state.organization.externalDeviceIntegrations.find(integration => integration.provider === integrationProvider) ?? {};
8✔
175
    const { [EXTERNAL_PROVIDER['iot-hub'].credentialsAttribute]: azureConnectionString = '' } = credentials;
8✔
176
    return !!azureConnectionString;
8✔
177
  });
178
  const ipAddress = useSelector(state => state.app.hostAddress);
8✔
179
  const isEnterprise = useSelector(getIsEnterprise);
4✔
180
  const { isDemoMode, isHosted } = useSelector(getFeatures);
4✔
181
  const isPreRelease = useSelector(getIsPreview);
4✔
182
  const onboardingState = useSelector(getOnboardingState);
4✔
183
  const { tenant_token: tenantToken } = useSelector(getOrganization);
4✔
184
  const { Integration: version } = useSelector(getFullVersionInformation);
4✔
185
  const { token } = useSelector(getCurrentSession);
4✔
186
  const dispatch = useDispatch();
4✔
187

188
  useEffect(() => {
4✔
189
    dispatch(setOnboardingApproach('physical'));
2✔
190
  }, [dispatch]);
191

192
  const onSelect = (e, deviceType, reason) => {
4✔
193
    if (reason === 'selectOption') {
×
194
      dispatch(setOnboardingDeviceType(deviceType.value));
×
195
      setSelection(deviceType.value);
×
196
    } else if (reason === 'clear') {
×
197
      dispatch(setOnboardingDeviceType(''));
×
198
      setSelection('');
×
199
    }
200
  };
201

202
  const hasConvertedImage = !!selection && selection.length && (selection.startsWith('raspberrypi3') || selection.startsWith('raspberrypi4'));
4!
203

204
  const ComponentToShow = steps[progress];
4✔
205
  return (
4✔
206
    <ComponentToShow
207
      advanceOnboarding={step => dispatch(advanceOnboarding(step))}
×
208
      hasExternalIntegration={hasExternalIntegration}
209
      hasConvertedImage={hasConvertedImage}
210
      integrationProvider={integrationProvider}
211
      ipAddress={ipAddress}
212
      isEnterprise={isEnterprise}
213
      isHosted={isHosted}
214
      isDemoMode={isDemoMode}
215
      isPreRelease={isPreRelease}
216
      onboardingState={onboardingState}
217
      onSelect={onSelect}
218
      selection={selection}
219
      tenantToken={tenantToken}
220
      token={token}
221
      version={version}
222
    />
223
  );
224
};
225

226
export default PhysicalDeviceOnboarding;
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