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

mendersoftware / gui / 897326496

pending completion
897326496

Pull #3752

gitlab-ci

mzedel
chore(e2e): made use of shared timeout & login checking values to remove code duplication

Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #3752: chore(e2e-tests): slightly simplified log in test + separated log out test

4395 of 6392 branches covered (68.76%)

8060 of 9780 relevant lines covered (82.41%)

126.17 hits per line

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

91.23
/src/js/components/devices/device-details/connection.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, { useEffect, useState } from 'react';
15
import { Link } from 'react-router-dom';
16

17
import { ImportExport as ImportExportIcon, InfoOutlined as InfoIcon, Launch as LaunchIcon } from '@mui/icons-material';
18
import { Button, Typography } from '@mui/material';
19
import { useTheme } from '@mui/material/styles';
20

21
import { mdiConsole as ConsoleIcon } from '@mdi/js';
22

23
import { BEGINNING_OF_TIME } from '../../../constants/appConstants';
24
import { DEVICE_CONNECT_STATES } from '../../../constants/deviceConstants';
25
import { AUDIT_LOGS_TYPES } from '../../../constants/organizationConstants';
26
import { formatAuditlogs } from '../../../utils/locationutils';
27
import MaterialDesignIcon from '../../common/materialdesignicon';
28
import MenderTooltip from '../../common/mendertooltip';
29
import Time from '../../common/time';
30
import Troubleshootdialog from '../dialogs/troubleshootdialog';
31
import DeviceDataCollapse from './devicedatacollapse';
32

33
const buttonStyle = { textTransform: 'none', textAlign: 'left' };
11✔
34
export const PortForwardLink = ({ docsVersion }) => (
11✔
35
  <MenderTooltip
3✔
36
    arrow
37
    title={
38
      <div style={{ whiteSpace: 'normal' }}>
39
        <h3>Port forwarding</h3>
40
        <p>Port forwarding allows you to troubleshoot or use services on or via the device, without opening any ports on the device itself.</p>
41
        <p>
42
          To enable port forwarding you will need to install and configure the necessary software on the device and your workstation. Follow the link to learn
43
          more.
44
        </p>
45
      </div>
46
    }
47
  >
48
    <a href={`https://docs.mender.io/${docsVersion}add-ons/port-forward`} className="flexbox centered margin-left" target="_blank" rel="noopener noreferrer">
49
      Enable port forwarding
50
      <LaunchIcon className="margin-left-small" fontSize="small" />
51
    </a>
52
  </MenderTooltip>
53
);
54

55
export const DeviceConnectionNote = ({ children, style = buttonStyle }) => {
11✔
56
  const theme = useTheme();
7✔
57
  return (
7✔
58
    <div className="flexbox muted">
59
      <InfoIcon fontSize="small" style={{ marginRight: theme.spacing() }} />
60
      <Typography variant="body1" style={style}>
61
        {children}
62
      </Typography>
63
    </div>
64
  );
65
};
66

67
export const DeviceConnectionMissingNote = ({ docsVersion }) => (
11✔
68
  <DeviceConnectionNote>
3✔
69
    The troubleshoot add-on does not seem to be enabled on this device.
70
    <br />
71
    Please{' '}
72
    <a target="_blank" rel="noopener noreferrer" href={`https://docs.mender.io/${docsVersion}add-ons/remote-terminal`}>
73
      see the documentation
74
    </a>{' '}
75
    for a description on how it works and how to enable it.
76
  </DeviceConnectionNote>
77
);
78

79
export const DeviceDisconnectedNote = ({ docsVersion, lastConnectionTs }) => (
11✔
80
  <DeviceConnectionNote>
3✔
81
    The troubleshoot add-on is not currently connected on this device, it was last connected on <Time value={lastConnectionTs} />.
82
    <br />
83
    Please{' '}
84
    <a target="_blank" rel="noopener noreferrer" href={`https://docs.mender.io/${docsVersion}add-ons/remote-terminal`}>
85
      see the documentation
86
    </a>{' '}
87
    for more information.
88
  </DeviceConnectionNote>
89
);
90

91
export const TroubleshootButton = ({ disabled, item, onClick }) => {
11✔
92
  const theme = useTheme();
4✔
93
  return (
4✔
94
    <Button onClick={() => onClick(item.key)} disabled={disabled} startIcon={item.icon} style={{ marginRight: theme.spacing(2) }}>
×
95
      <Typography variant="subtitle2" style={buttonStyle}>
96
        {item.title}
97
      </Typography>
98
    </Button>
99
  );
100
};
101

102
const troubleshootingTools = [
11✔
103
  {
104
    key: 'terminal',
105
    title: 'Launch a new Remote Terminal session',
106
    icon: <MaterialDesignIcon path={ConsoleIcon} />,
107
    needsWriteAccess: true,
108
    needsTroubleshoot: true
109
  },
110
  { key: 'transfer', title: 'Launch File Transfer', icon: <ImportExportIcon />, needsWriteAccess: false, needsTroubleshoot: false },
111
  { key: 'portForward', component: PortForwardLink, needsWriteAccess: false, needsTroubleshoot: true }
112
];
113

114
const deviceAuditlogType = AUDIT_LOGS_TYPES.find(type => type.value === 'device');
33✔
115

116
export const DeviceConnection = ({ className = '', device, docsVersion = '', hasAuditlogs, socketClosed, startTroubleshoot, userCapabilities }) => {
11✔
117
  const [availableTabs, setAvailableTabs] = useState(troubleshootingTools);
6✔
118

119
  const { canAuditlog, canTroubleshoot, canWriteDevices: hasWriteAccess } = userCapabilities;
6✔
120

121
  useEffect(() => {
6✔
122
    const allowedTabs = troubleshootingTools.reduce((accu, tab) => {
3✔
123
      if ((tab.needsWriteAccess && !hasWriteAccess) || (tab.needsTroubleshoot && !canTroubleshoot)) {
9!
124
        return accu;
×
125
      }
126
      accu.push(tab);
9✔
127
      return accu;
9✔
128
    }, []);
129
    setAvailableTabs(allowedTabs);
3✔
130
  }, [hasWriteAccess, canTroubleshoot]);
131

132
  const { connect_status = DEVICE_CONNECT_STATES.unknown, connect_updated_ts } = device;
6✔
133
  return (
6✔
134
    <DeviceDataCollapse
135
      header={
136
        <div className={`flexbox ${className}`}>
137
          {connect_status === DEVICE_CONNECT_STATES.unknown && <DeviceConnectionMissingNote docsVersion={docsVersion} />}
8✔
138
          {connect_status === DEVICE_CONNECT_STATES.disconnected && <DeviceDisconnectedNote docsVersion={docsVersion} lastConnectionTs={connect_updated_ts} />}
8✔
139
          {connect_status === DEVICE_CONNECT_STATES.connected &&
8✔
140
            availableTabs.map(item => {
141
              let Component = TroubleshootButton;
6✔
142
              if (item.component) {
6✔
143
                Component = item.component;
2✔
144
              }
145
              return <Component key={item.key} docsVersion={docsVersion} onClick={startTroubleshoot} disabled={!socketClosed} item={item} />;
6✔
146
            })}
147
          {canAuditlog && hasAuditlogs && connect_status !== DEVICE_CONNECT_STATES.unknown && (
16✔
148
            <Link
149
              className="flexbox center-aligned margin-left"
150
              to={`/auditlog?${formatAuditlogs({ pageState: { type: deviceAuditlogType, detail: device.id, startDate: BEGINNING_OF_TIME } }, {})}`}
151
            >
152
              List all log entries for this device
153
            </Link>
154
          )}
155
        </div>
156
      }
157
      isAddOn
158
      title="Troubleshoot"
159
    ></DeviceDataCollapse>
160
  );
161
};
162

163
export default DeviceConnection;
164

165
export const TroubleshootTab = ({
11✔
166
  classes,
167
  device,
168
  docsVersion,
169
  tenantCapabilities: { hasAuditlogs },
170
  socketClosed,
171
  launchTroubleshoot,
172
  userCapabilities,
173
  troubleshootType,
174
  setTroubleshootType,
175
  setSocketClosed
176
}) => (
177
  <>
×
178
    <DeviceConnection
179
      className={classes.deviceConnection}
180
      device={device}
181
      docsVersion={docsVersion}
182
      hasAuditlogs={hasAuditlogs}
183
      socketClosed={socketClosed}
184
      startTroubleshoot={launchTroubleshoot}
185
      userCapabilities={userCapabilities}
186
    />
187
    <Troubleshootdialog
188
      device={device}
189
      hasAuditlogs={hasAuditlogs}
190
      open={Boolean(troubleshootType)}
191
      onCancel={() => setTroubleshootType()}
×
192
      setSocketClosed={setSocketClosed}
193
      type={troubleshootType}
194
      userCapabilities={userCapabilities}
195
    />
196
  </>
197
);
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