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

mendersoftware / gui / 1081664682

22 Nov 2023 02:11PM UTC coverage: 82.798% (-17.2%) from 99.964%
1081664682

Pull #4214

gitlab-ci

tranchitella
fix: Fixed the infinite page redirects when the back button is pressed

Remove the location and navigate from the useLocationParams.setValue callback
dependencies as they change the set function that is presented in other
useEffect dependencies. This happens when the back button is clicked, which
leads to the location changing infinitely.

Changelog: Title
Ticket: MEN-6847
Ticket: MEN-6796

Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
Signed-off-by: Fabio Tranchitella <fabio.tranchitella@northern.tech>
Pull Request #4214: fix: Fixed the infinite page redirects when the back button is pressed

4319 of 6292 branches covered (0.0%)

8332 of 10063 relevant lines covered (82.8%)

191.0 hits per line

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

7.89
/src/js/components/devices/device-details/devicesystem.js
1
// Copyright 2022 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, useNavigate } from 'react-router-dom';
17

18
import { Button } from '@mui/material';
19
import { makeStyles } from 'tss-react/mui';
20

21
import { setSnackbar } from '../../../actions/appActions';
22
import { getSystemDevices } from '../../../actions/deviceActions';
23
import { BENEFITS, SORTING_OPTIONS } from '../../../constants/appConstants';
24
import { DEVICE_LIST_DEFAULTS } from '../../../constants/deviceConstants';
25
import { getDemoDeviceAddress, toggle } from '../../../helpers';
26
import { getCurrentSession, getDevicesById, getIdAttribute, getIsPreview, getOrganization } from '../../../selectors';
27
import { TwoColumnData } from '../../common/configurationobject';
28
import DocsLink from '../../common/docslink';
29
import EnterpriseNotification from '../../common/enterpriseNotification';
30
import { getHeaders } from '../authorized-devices';
31
import { routes } from '../base-devices';
32
import Devicelist from '../devicelist';
33
import ConnectToGatewayDialog from '../dialogs/connecttogatewaydialog';
34
import DeviceDataCollapse from './devicedatacollapse';
35

36
const useStyles = makeStyles()(theme => ({ container: { maxWidth: 600, marginTop: theme.spacing(), marginBottom: theme.spacing() } }));
8✔
37

38
export const DeviceSystem = ({ columnSelection, device, onConnectToGatewayClick, openSettingsDialog }) => {
8✔
39
  const [columnHeaders, setColumnHeaders] = useState([]);
×
40
  const [headerKeys, setHeaderKeys] = useState([]);
×
41
  const [page, setPage] = useState(DEVICE_LIST_DEFAULTS.page);
×
42
  const [perPage, setPerPage] = useState(DEVICE_LIST_DEFAULTS.perPage);
×
43
  const { classes } = useStyles();
×
44
  const navigate = useNavigate();
×
45
  const dispatch = useDispatch();
×
46
  const devicesById = useSelector(getDevicesById);
×
47
  const idAttribute = useSelector(getIdAttribute);
×
48

49
  const { systemDeviceIds = [], systemDeviceTotal = 0 } = device;
×
50
  const deviceIp = getDemoDeviceAddress([device]);
×
51

52
  const [sortOptions, setSortOptions] = useState([]);
×
53

54
  const onSortChange = attribute => {
×
55
    let changedOrder = SORTING_OPTIONS.asc;
×
56
    if (sortOptions.length && sortOptions[0].attribute == attribute.name) {
×
57
      changedOrder = sortOptions[0].order === SORTING_OPTIONS.desc ? SORTING_OPTIONS.asc : SORTING_OPTIONS.desc;
×
58
    }
59
    setSortOptions([{ attribute: attribute.name, scope: attribute.scope, order: changedOrder }]);
×
60
  };
61

62
  useEffect(() => {
×
63
    const columnHeaders = getHeaders(columnSelection, routes.allDevices.defaultHeaders, idAttribute, openSettingsDialog);
×
64
    setColumnHeaders(columnHeaders);
×
65
    setHeaderKeys(columnHeaders.map(({ attribute: { name, scope } }) => `${name}-${scope}`).join('-'));
×
66
    // eslint-disable-next-line react-hooks/exhaustive-deps
67
  }, [columnSelection, idAttribute.attribute, openSettingsDialog]);
68

69
  useEffect(() => {
×
70
    if (device.attributes) {
×
71
      dispatch(getSystemDevices(device.id, { page, perPage, sortOptions }));
×
72
    }
73
    // eslint-disable-next-line react-hooks/exhaustive-deps
74
  }, [dispatch, device.id, device.attributes?.mender_is_gateway, page, perPage, sortOptions]);
75

76
  const onDeviceClick = (device = {}) => navigate(`/devices/${device.status}?id=${device.id}&open=true&tab=identity`);
×
77

78
  return (
×
79
    <>
80
      <DeviceDataCollapse
81
        title={
82
          <div className="flexbox center-aligned">
83
            <h4>Mender Gateway</h4>
84
            <EnterpriseNotification className="margin-left-small" id={BENEFITS.gateway.id} />
85
          </div>
86
        }
87
      >
88
        <TwoColumnData config={{ 'Server IP': deviceIp }} compact setSnackbar={message => dispatch(setSnackbar(message))} />
×
89
      </DeviceDataCollapse>
90
      <DeviceDataCollapse className={classes.container} title="System for this gateway">
91
        {systemDeviceTotal ? (
×
92
          <Devicelist
93
            customColumnSizes={[]}
94
            columnHeaders={columnHeaders}
95
            devices={systemDeviceIds.map(id => devicesById[id])}
×
96
            deviceListState={{ page, perPage }}
97
            headerKeys={headerKeys}
98
            idAttribute={idAttribute}
99
            onChangeRowsPerPage={setPerPage}
100
            onExpandClick={onDeviceClick}
101
            onResizeColumns={false}
102
            onPageChange={setPage}
103
            onSelect={false}
104
            onSort={onSortChange}
105
            pageLoading={false}
106
            pageTotal={systemDeviceTotal}
107
          />
108
        ) : (
109
          <div className="dashboard-placeholder">
110
            <p>No devices have been connected to this gateway device yet.</p>
111
            <div>
112
              Visit the <DocsLink path="get-started/mender-gateway" title="full Mender Gateway documentation" /> to learn how to make the most of the gateway
113
              functionality.
114
            </div>
115
          </div>
116
        )}
117
      </DeviceDataCollapse>
118
      <div className="flexbox">
119
        <Button color="secondary" component={Link} to={`/deployments?deviceId=${device.id}&open=true`}>
120
          Create deployment for this system
121
        </Button>
122
        <Button onClick={onConnectToGatewayClick}>Connect devices</Button>
123
      </div>
124
    </>
125
  );
126
};
127

128
const DeviceSystemTab = ({ device, ...remainder }) => {
8✔
129
  const [open, setOpen] = useState(false);
×
130
  const isPreRelease = useSelector(getIsPreview);
×
131
  const { tenant_token: tenantToken } = useSelector(getOrganization);
×
132
  const { token } = useSelector(getCurrentSession);
×
133

134
  const gatewayIp = getDemoDeviceAddress([device]);
×
135
  const toggleDialog = () => setOpen(toggle);
×
136
  return (
×
137
    <>
138
      <DeviceSystem onConnectToGatewayClick={toggleDialog} {...{ device, ...remainder }} />
139
      {open && <ConnectToGatewayDialog gatewayIp={gatewayIp} isPreRelease={isPreRelease} onCancel={toggleDialog} tenantToken={tenantToken} token={token} />}
×
140
    </>
141
  );
142
};
143

144
export default DeviceSystemTab;
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