• 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

90.0
/src/js/components/deployments/inprogressdeployments.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, { useCallback, useEffect, useRef, useState } from 'react';
15
import { connect } from 'react-redux';
16

17
import { Refresh as RefreshIcon } from '@mui/icons-material';
18
import { makeStyles } from 'tss-react/mui';
19

20
import { setSnackbar } from '../../actions/appActions';
21
import { getDeploymentsByStatus, setDeploymentsState } from '../../actions/deploymentActions';
22
import { DEPLOYMENT_STATES } from '../../constants/deploymentConstants';
23
import { onboardingSteps } from '../../constants/onboardingConstants';
24
import { tryMapDeployments } from '../../helpers';
25
import { getIdAttribute, getOnboardingState, getUserCapabilities } from '../../selectors';
26
import { getOnboardingComponentFor } from '../../utils/onboardingmanager';
27
import useWindowSize from '../../utils/resizehook';
28
import { clearAllRetryTimers, clearRetryTimer, setRetryTimer } from '../../utils/retrytimer';
29
import LinedHeader from '../common/lined-header';
30
import Loader from '../common/loader';
31
import { defaultRefreshDeploymentsLength as refreshDeploymentsLength } from './deployments';
32
import DeploymentsList from './deploymentslist';
33

34
export const minimalRefreshDeploymentsLength = 2000;
7✔
35

36
const useStyles = makeStyles()(theme => ({
7✔
37
  deploymentsPending: {
38
    borderColor: 'rgba(0, 0, 0, 0.06)',
39
    backgroundColor: theme.palette.background.light,
40
    color: theme.palette.text.primary,
41
    ['.dashboard-header span']: {
42
      backgroundColor: theme.palette.background.light,
43
      color: theme.palette.text.primary
44
    },
45
    ['.MuiButtonBase-root']: {
46
      color: theme.palette.text.primary
47
    }
48
  }
49
}));
50

51
export const Progress = props => {
7✔
52
  const {
53
    abort,
54
    canDeploy,
55
    createClick,
56
    getDeploymentsByStatus,
57
    onboardingState,
58
    pastDeploymentsCount,
59
    pending,
60
    pendingCount,
61
    progress,
62
    progressCount,
63
    selectionState,
64
    setDeploymentsState,
65
    setSnackbar
66
  } = props;
235✔
67
  const { page: progressPage, perPage: progressPerPage } = selectionState.inprogress;
234✔
68
  const { page: pendingPage, perPage: pendingPerPage } = selectionState.pending;
234✔
69

70
  const [currentRefreshDeploymentLength, setCurrentRefreshDeploymentLength] = useState(refreshDeploymentsLength);
234✔
71
  const [doneLoading, setDoneLoading] = useState(!!(progressCount || pendingCount));
234✔
72
  // eslint-disable-next-line no-unused-vars
73
  const size = useWindowSize();
234✔
74

75
  const inprogressRef = useRef();
234✔
76
  const dynamicTimer = useRef();
234✔
77

78
  const { classes } = useStyles();
234✔
79

80
  useEffect(() => {
234✔
81
    return () => {
7✔
82
      clearAllRetryTimers(setSnackbar);
7✔
83
    };
84
  }, []);
85

86
  useEffect(() => {
234✔
87
    clearTimeout(dynamicTimer.current);
12✔
88
    setupDeploymentsRefresh(minimalRefreshDeploymentsLength);
12✔
89
    return () => {
12✔
90
      clearTimeout(dynamicTimer.current);
12✔
91
    };
92
  }, [pendingCount]);
93

94
  useEffect(() => {
234✔
95
    clearTimeout(dynamicTimer.current);
7✔
96
    setupDeploymentsRefresh();
7✔
97
    return () => {
7✔
98
      clearInterval(dynamicTimer.current);
7✔
99
    };
100
  }, [progressPage, progressPerPage, pendingPage, pendingPerPage]);
101

102
  const setupDeploymentsRefresh = (refreshLength = currentRefreshDeploymentLength) => {
234✔
103
    let tasks = [refreshDeployments(DEPLOYMENT_STATES.inprogress), refreshDeployments(DEPLOYMENT_STATES.pending)];
19✔
104
    if (!onboardingState.complete && !pastDeploymentsCount) {
19✔
105
      // retrieve past deployments outside of the regular refresh cycle to not change the selection state for past deployments
106
      getDeploymentsByStatus(DEPLOYMENT_STATES.finished, 1, 1, undefined, undefined, undefined, undefined, false);
12✔
107
    }
108
    return Promise.all(tasks)
19✔
109
      .then(() => {
110
        const currentRefreshDeploymentLength = Math.min(refreshDeploymentsLength, refreshLength * 2);
17✔
111
        setCurrentRefreshDeploymentLength(currentRefreshDeploymentLength);
17✔
112
        clearTimeout(dynamicTimer.current);
17✔
113
        dynamicTimer.current = setTimeout(setupDeploymentsRefresh, currentRefreshDeploymentLength);
17✔
114
      })
115
      .finally(() => setDoneLoading(true));
17✔
116
  };
117

118
  // deploymentStatus = <inprogress|pending>
119
  const refreshDeployments = useCallback(
234✔
120
    deploymentStatus => {
121
      const { page, perPage } = selectionState[deploymentStatus];
38✔
122
      return getDeploymentsByStatus(deploymentStatus, page, perPage)
38✔
123
        .then(deploymentsAction => {
124
          clearRetryTimer(deploymentStatus, setSnackbar);
34✔
125
          const { total, deploymentIds } = deploymentsAction[deploymentsAction.length - 1];
34✔
126
          if (total && !deploymentIds.length) {
34!
127
            return refreshDeployments(deploymentStatus);
×
128
          }
129
        })
130
        .catch(err => setRetryTimer(err, 'deployments', `Couldn't load deployments.`, refreshDeploymentsLength, setSnackbar))
×
131
        .finally(() => setDoneLoading(true));
34✔
132
    },
133
    [pendingPage, pendingPerPage, progressPage, progressPerPage]
134
  );
135

136
  const abortDeployment = id =>
234✔
137
    abort(id).then(() => Promise.all([refreshDeployments(DEPLOYMENT_STATES.inprogress), refreshDeployments(DEPLOYMENT_STATES.pending)]));
×
138

139
  let onboardingComponent = null;
234✔
140
  if (!onboardingState.complete && inprogressRef.current) {
234✔
141
    const anchor = {
203✔
142
      left: inprogressRef.current.offsetLeft + (inprogressRef.current.offsetWidth / 100) * 90,
143
      top: inprogressRef.current.offsetTop + inprogressRef.current.offsetHeight
144
    };
145
    onboardingComponent = getOnboardingComponentFor(onboardingSteps.DEPLOYMENTS_INPROGRESS, onboardingState, { anchor });
203✔
146
  }
147

148
  return doneLoading ? (
234✔
149
    <div className="fadeIn">
150
      {!!progress.length && (
422✔
151
        <div className="margin-left">
152
          <LinedHeader className="margin-top-large  margin-right" heading="In progress now" />
153
          <DeploymentsList
154
            {...props}
155
            abort={abortDeployment}
156
            count={progressCount}
157
            items={progress}
158
            listClass="margin-right-small"
159
            page={progressPage}
160
            pageSize={progressPerPage}
161
            rootRef={inprogressRef}
162
            onChangeRowsPerPage={perPage => setDeploymentsState({ [DEPLOYMENT_STATES.inprogress]: { page: 1, perPage } })}
×
163
            onChangePage={page => setDeploymentsState({ [DEPLOYMENT_STATES.inprogress]: { page } })}
×
164
            type={DEPLOYMENT_STATES.inprogress}
165
          />
166
        </div>
167
      )}
168
      {!!onboardingComponent && onboardingComponent}
214!
169
      {!!pending.length && (
419✔
170
        <div className={`deployments-pending margin-top margin-bottom-large ${classes.deploymentsPending}`}>
171
          <LinedHeader className="margin-small margin-top" heading="Pending" />
172
          <DeploymentsList
173
            {...props}
174
            abort={abortDeployment}
175
            componentClass="margin-left-small"
176
            count={pendingCount}
177
            items={pending}
178
            page={pendingPage}
179
            pageSize={pendingPerPage}
180
            onChangeRowsPerPage={perPage => setDeploymentsState({ [DEPLOYMENT_STATES.pending]: { page: 1, perPage } })}
×
181
            onChangePage={page => setDeploymentsState({ [DEPLOYMENT_STATES.pending]: { page } })}
×
182
            type={DEPLOYMENT_STATES.pending}
183
          />
184
        </div>
185
      )}
186
      {!(progressCount || pendingCount) && (
440✔
187
        <div className="dashboard-placeholder">
188
          <p>Pending and ongoing deployments will appear here. </p>
189
          {canDeploy && (
12✔
190
            <p>
191
              <a onClick={createClick}>Create a deployment</a> to get started
192
            </p>
193
          )}
194
          <RefreshIcon className="flip-horizontal" style={{ fill: '#e3e3e3', width: 111, height: 111 }} />
195
        </div>
196
      )}
197
    </div>
198
  ) : (
199
    <Loader show={doneLoading} />
200
  );
201
};
202

203
const actionCreators = { getDeploymentsByStatus, setDeploymentsState, setSnackbar };
7✔
204

205
const mapStateToProps = state => {
7✔
206
  const progress = state.deployments.selectionState.inprogress.selection.reduce(tryMapDeployments, { state, deployments: [] }).deployments;
158✔
207
  const pending = state.deployments.selectionState.pending.selection.reduce(tryMapDeployments, { state, deployments: [] }).deployments;
158✔
208
  const { canConfigure, canDeploy } = getUserCapabilities(state);
158✔
209
  return {
158✔
210
    canConfigure,
211
    canDeploy,
212
    devices: state.devices.byId,
213
    idAttribute: getIdAttribute(state).attribute,
214
    onboardingState: getOnboardingState(state),
215
    pastDeploymentsCount: state.deployments.byStatus.finished.total,
216
    pending,
217
    pendingCount: state.deployments.byStatus.pending.total,
218
    progress,
219
    progressCount: state.deployments.byStatus.inprogress.total,
220
    selectionState: state.deployments.selectionState
221
  };
222
};
223

224
export default connect(mapStateToProps, actionCreators)(Progress);
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