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

mendersoftware / gui / 901187442

pending completion
901187442

Pull #3795

gitlab-ci

mzedel
feat: increased chances of adopting our intended navigation patterns instead of unsupported browser navigation

Ticket: None
Changelog: None
Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #3795: feat: increased chances of adopting our intended navigation patterns instead of unsupported browser navigation

4389 of 6365 branches covered (68.96%)

5 of 5 new or added lines in 1 file covered. (100.0%)

1729 existing lines in 165 files now uncovered.

8274 of 10019 relevant lines covered (82.58%)

144.86 hits per line

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

96.0
/src/js/components/dashboard/deployments.js
1
// Copyright 2015 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, useRef, useState } from 'react';
15
import { useDispatch, useSelector } from 'react-redux';
16
import { Link } from 'react-router-dom';
17

18
import { setSnackbar } from '../../actions/appActions';
19
import { getDeploymentsByStatus } from '../../actions/deploymentActions';
20
import { DEPLOYMENT_ROUTES, DEPLOYMENT_STATES, deploymentDisplayStates } from '../../constants/deploymentConstants';
21
import { onboardingSteps } from '../../constants/onboardingConstants';
22
import { DEPLOYMENT_CUTOFF, getIdAttribute, getOnboardingState, getRecentDeployments, getUserCapabilities } from '../../selectors';
23
import { getOnboardingComponentFor } from '../../utils/onboardingmanager';
24
import useWindowSize from '../../utils/resizehook';
25
import { clearAllRetryTimers, setRetryTimer } from '../../utils/retrytimer';
26
import Loader from '../common/loader';
27
import { BaseDeploymentsWidget, CompletedDeployments } from './widgets/deployments';
28
import RedirectionWidget from './widgets/redirectionwidget';
29

30
const refreshDeploymentsLength = 30000;
5✔
31

32
// we need to exclude the scheduled state here as the os version is not able to process these and would prevent the dashboard from loading
33
const stateMap = {
5✔
34
  [DEPLOYMENT_STATES.pending]: BaseDeploymentsWidget,
35
  [DEPLOYMENT_STATES.inprogress]: BaseDeploymentsWidget,
36
  [DEPLOYMENT_STATES.finished]: CompletedDeployments
37
};
38

39
export const Deployments = ({ className = '', clickHandle }) => {
5✔
40
  const dispatch = useDispatch();
471✔
41
  const setSnackbarDispatched = message => dispatch(setSnackbar(message));
471✔
42
  const { canDeploy } = useSelector(getUserCapabilities);
471✔
43
  const { total: deploymentsCount, ...deployments } = useSelector(getRecentDeployments);
471✔
44
  const onboardingState = useSelector(getOnboardingState);
471✔
45
  const devicesById = useSelector(state => state.devices.byId);
901✔
46
  const idAttribute = useSelector(getIdAttribute);
471✔
47
  const [loading, setLoading] = useState(!deploymentsCount);
471✔
48
  // eslint-disable-next-line no-unused-vars
49
  const size = useWindowSize();
471✔
50
  const deploymentsRef = useRef();
471✔
51
  const timer = useRef();
471✔
52

53
  useEffect(() => {
471✔
54
    clearAllRetryTimers(setSnackbarDispatched);
10✔
55
    clearInterval(timer.current);
10✔
56
    timer.current = setInterval(getDeployments, refreshDeploymentsLength);
10✔
57
    getDeployments();
10✔
58
    return () => {
10✔
59
      clearInterval(timer.current);
10✔
60
      clearAllRetryTimers(setSnackbarDispatched);
10✔
61
    };
62
  }, []);
63

64
  const getDeployments = () =>
471✔
65
    Promise.all(Object.keys(stateMap).map(status => dispatch(getDeploymentsByStatus(status, 1, DEPLOYMENT_CUTOFF))))
213✔
UNCOV
66
      .catch(err => setRetryTimer(err, 'deployments', `Couldn't load deployments.`, refreshDeploymentsLength, setSnackbarDispatched))
×
67
      .finally(() => setLoading(false));
70✔
68

69
  let onboardingComponent;
70
  if (deploymentsRef.current) {
471✔
71
    const anchor = {
423✔
72
      top: deploymentsRef.current.offsetTop + deploymentsRef.current.offsetHeight,
73
      left: deploymentsRef.current.offsetLeft + deploymentsRef.current.offsetWidth / 2
74
    };
75
    onboardingComponent = getOnboardingComponentFor(onboardingSteps.DEPLOYMENTS_PAST_COMPLETED, onboardingState, { anchor });
423✔
76
  }
77
  return (
471✔
78
    <div className={`${className} deployments`}>
79
      {loading ? (
471✔
80
        <Loader show={loading} fade={true} />
81
      ) : (
82
        <div className="dashboard flexbox column" ref={deploymentsRef} style={{ gridTemplateColumns: '1fr', rowGap: 10 }}>
83
          <h4 className={`${deploymentsCount ? 'margin-bottom-none' : 'margin-top-none'} margin-left-small`}>
435✔
84
            {deploymentsCount ? 'Recent deployments' : 'Deployments'}
435✔
85
          </h4>
86
          {deploymentsCount ? (
435✔
87
            <>
88
              {Object.entries(stateMap).reduce((accu, [key, Component]) => {
89
                if (!deployments[key]) {
1,269✔
90
                  return accu;
9✔
91
                }
92
                accu.push(
1,260✔
93
                  <React.Fragment key={key}>
94
                    <h5 className="margin-bottom-none">{deploymentDisplayStates[key]}</h5>
95
                    <Component deployments={deployments[key]} devicesById={devicesById} idAttribute={idAttribute} state={key} onClick={clickHandle} />
96
                  </React.Fragment>
97
                );
98
                return accu;
1,260✔
99
              }, [])}
100
              <Link className="margin-top" to="/deployments">
101
                See all deployments
102
              </Link>
103
            </>
104
          ) : (
105
            canDeploy && (
14✔
106
              <RedirectionWidget
107
                content="Create a new deployment to update a group of devices"
UNCOV
108
                onClick={() => clickHandle({ route: `${DEPLOYMENT_ROUTES.active.route}?open=true` })}
×
109
              />
110
            )
111
          )}
112
        </div>
113
      )}
114
      {onboardingComponent}
115
    </div>
116
  );
117
};
118

119
export default Deployments;
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