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

mendersoftware / gui / 1057188406

01 Nov 2023 04:24AM UTC coverage: 82.824% (-17.1%) from 99.964%
1057188406

Pull #4134

gitlab-ci

web-flow
chore: Bump uuid from 9.0.0 to 9.0.1

Bumps [uuid](https://github.com/uuidjs/uuid) from 9.0.0 to 9.0.1.
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v9.0.0...v9.0.1)

---
updated-dependencies:
- dependency-name: uuid
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #4134: chore: Bump uuid from 9.0.0 to 9.0.1

4349 of 6284 branches covered (0.0%)

8313 of 10037 relevant lines covered (82.82%)

200.97 hits per line

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

71.67
/src/js/components/deployments/scheduleddeployments.js
1
// Copyright 2020 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 { Calendar, momentLocalizer } from 'react-big-calendar';
16
import 'react-big-calendar/lib/css/react-big-calendar.css';
17
import { useDispatch, useSelector } from 'react-redux';
18

19
import { CalendarToday as CalendarTodayIcon, List as ListIcon, Refresh as RefreshIcon } from '@mui/icons-material';
20
import { Button } from '@mui/material';
21
import { makeStyles } from 'tss-react/mui';
22

23
import moment from 'moment';
24

25
import { setSnackbar } from '../../actions/appActions';
26
import { getDeploymentsByStatus, setDeploymentsState } from '../../actions/deploymentActions';
27
import { DEPLOYMENT_STATES } from '../../constants/deploymentConstants';
28
import {
29
  getDeploymentsByStatus as getDeploymentsByStatusSelector,
30
  getDeploymentsSelectionState,
31
  getDevicesById,
32
  getIdAttribute,
33
  getMappedDeploymentSelection,
34
  getTenantCapabilities,
35
  getUserCapabilities
36
} from '../../selectors';
37
import { clearAllRetryTimers, clearRetryTimer, setRetryTimer } from '../../utils/retrytimer';
38
import { DefaultUpgradeNotification } from '../common/enterpriseNotification';
39
import { DeploymentDeviceCount, DeploymentEndTime, DeploymentPhases, DeploymentStartTime } from './deploymentitem';
40
import { defaultRefreshDeploymentsLength as refreshDeploymentsLength } from './deployments';
41
import DeploymentsList, { defaultHeaders } from './deploymentslist';
42

43
const useStyles = makeStyles()(theme => ({
7✔
44
  inactive: { color: theme.palette.text.disabled },
45
  refreshIcon: { fill: theme.palette.grey[400], width: 111, height: 111 },
46
  tabSelect: { textTransform: 'none' }
47
}));
48

49
const localizer = momentLocalizer(moment);
7✔
50

51
const headers = [
7✔
52
  ...defaultHeaders.slice(0, 2),
53
  { title: 'Start time', renderer: DeploymentStartTime, props: { direction: 'up' } },
54
  { title: `End time`, renderer: DeploymentEndTime },
55
  { title: '# devices', class: 'align-right column-defined', renderer: DeploymentDeviceCount },
56
  { title: 'Phases', renderer: DeploymentPhases }
57
];
58

59
const tabs = {
7✔
60
  list: {
61
    icon: <ListIcon />,
62
    index: 'list',
63
    title: 'List view'
64
  },
65
  calendar: {
66
    icon: <CalendarTodayIcon />,
67
    index: 'calendar',
68
    title: 'Calendar'
69
  }
70
};
71

72
const type = DEPLOYMENT_STATES.scheduled;
7✔
73

74
export const Scheduled = ({ abort, createClick, openReport, ...remainder }) => {
7✔
75
  const [calendarEvents, setCalendarEvents] = useState([]);
3✔
76
  const [tabIndex, setTabIndex] = useState(tabs.list.index);
3✔
77
  const timer = useRef();
3✔
78
  const { canConfigure, canDeploy } = useSelector(getUserCapabilities);
3✔
79
  const {
80
    scheduled: { total: count }
81
  } = useSelector(getDeploymentsByStatusSelector);
3✔
82
  const { attribute: idAttribute } = useSelector(getIdAttribute);
3✔
83
  const devices = useSelector(getDevicesById);
3✔
84
  // TODO: isEnterprise is misleading here, but is passed down to the DeploymentListItem, this should be renamed
85
  const { canDelta: isEnterprise } = useSelector(getTenantCapabilities);
3✔
86
  const { scheduled: scheduledState } = useSelector(getDeploymentsSelectionState);
3✔
87
  const items = useSelector(state => getMappedDeploymentSelection(state, type));
8✔
88
  const dispatch = useDispatch();
3✔
89
  const dispatchedSetSnackbar = useCallback((...args) => dispatch(setSnackbar(...args)), [dispatch]);
3✔
90
  const { classes } = useStyles();
3✔
91

92
  const { page, perPage } = scheduledState;
3✔
93

94
  const refreshDeployments = useCallback(() => {
3✔
95
    return dispatch(getDeploymentsByStatus(DEPLOYMENT_STATES.scheduled, page, perPage))
2✔
96
      .then(deploymentsAction => {
97
        clearRetryTimer(type, dispatchedSetSnackbar);
1✔
98
        const { total, deploymentIds } = deploymentsAction[deploymentsAction.length - 1];
1✔
99
        if (total && !deploymentIds.length) {
1!
100
          return refreshDeployments();
×
101
        }
102
      })
103
      .catch(err => setRetryTimer(err, 'deployments', `Couldn't load deployments.`, refreshDeploymentsLength, dispatchedSetSnackbar));
×
104
  }, [dispatch, dispatchedSetSnackbar, page, perPage]);
105

106
  useEffect(() => {
3✔
107
    if (!isEnterprise) {
2!
108
      return;
×
109
    }
110
    refreshDeployments();
2✔
111
    return () => {
2✔
112
      clearAllRetryTimers(dispatchedSetSnackbar);
2✔
113
    };
114
  }, [dispatchedSetSnackbar, isEnterprise, refreshDeployments]);
115

116
  useEffect(() => {
3✔
117
    if (!isEnterprise) {
2!
118
      return;
×
119
    }
120
    clearInterval(timer.current);
2✔
121
    timer.current = setInterval(refreshDeployments, refreshDeploymentsLength);
2✔
122
    return () => {
2✔
123
      clearInterval(timer.current);
2✔
124
    };
125
  }, [isEnterprise, page, perPage, refreshDeployments]);
126

127
  useEffect(() => {
3✔
128
    if (tabIndex !== tabs.calendar.index) {
2!
129
      return;
2✔
130
    }
131
    const calendarEvents = items.map(deployment => {
×
132
      const start = new Date(deployment.start_ts || deployment.phases ? deployment.phases[0].start_ts : deployment.created);
×
133
      let endDate = start;
×
134
      if (deployment.phases && deployment.phases.length && deployment.phases[deployment.phases.length - 1].end_ts) {
×
135
        endDate = new Date(deployment.phases[deployment.phases.length - 1].end_ts);
×
136
      } else if (deployment.filter_id || deployment.filter) {
×
137
        // calendar doesn't support never ending events so we arbitrarly set one year
138
        endDate = moment(start).add(1, 'year');
×
139
      }
140
      return {
×
141
        allDay: !(deployment.filter_id || deployment.filter),
×
142
        id: deployment.id,
143
        title: `${deployment.name} ${deployment.artifact_name}`,
144
        start,
145
        end: endDate
146
      };
147
    });
148
    setCalendarEvents(calendarEvents);
×
149
    // eslint-disable-next-line react-hooks/exhaustive-deps
150
  }, [JSON.stringify(items), tabIndex]);
151

152
  const abortDeployment = id => abort(id).then(refreshDeployments);
3✔
153

154
  const props = {
3✔
155
    ...remainder,
156
    canDeploy,
157
    canConfigure,
158
    count,
159
    devices,
160
    idAttribute,
161
    isEnterprise,
162
    items,
163
    openReport,
164
    page
165
  };
166
  return (
3✔
167
    <div className="fadeIn margin-left">
168
      {items.length ? (
3✔
169
        <>
170
          <div className="margin-large margin-left-small">
171
            {Object.entries(tabs).map(([currentIndex, tab]) => (
172
              <Button
4✔
173
                className={`${classes.tabSelect} ${currentIndex !== tabIndex ? classes.inactive : ''}`}
4✔
174
                color="primary"
175
                key={currentIndex}
176
                startIcon={tab.icon}
177
                onClick={() => setTabIndex(currentIndex)}
×
178
              >
179
                {tab.title}
180
              </Button>
181
            ))}
182
          </div>
183
          {tabIndex === tabs.list.index && (
4✔
184
            <DeploymentsList
185
              {...props}
186
              abort={abortDeployment}
187
              headers={headers}
188
              type={type}
189
              onChangeRowsPerPage={perPage => dispatch(setDeploymentsState({ [DEPLOYMENT_STATES.scheduled]: { page: 1, perPage } }))}
×
190
              onChangePage={page => dispatch(setDeploymentsState({ [DEPLOYMENT_STATES.scheduled]: { page } }))}
×
191
            />
192
          )}
193
          {tabIndex === tabs.calendar.index && (
2!
194
            <Calendar
195
              localizer={localizer}
196
              className="margin-left margin-bottom"
197
              events={calendarEvents}
198
              startAccessor="start"
199
              endAccessor="end"
200
              style={{ height: 700 }}
201
              onSelectEvent={calendarEvent => openReport(type, calendarEvent.id)}
×
202
            />
203
          )}
204
        </>
205
      ) : (
206
        <div className="dashboard-placeholder margin-top">
207
          {isEnterprise ? (
1!
208
            <>
209
              <p>Scheduled deployments will appear here. </p>
210
              {canDeploy && (
2✔
211
                <p>
212
                  <a onClick={createClick}>Create a deployment</a> to get started
213
                </p>
214
              )}
215
            </>
216
          ) : (
217
            <div className="flexbox centered">
218
              <DefaultUpgradeNotification />
219
            </div>
220
          )}
221
          <RefreshIcon className={`flip-horizontal ${classes.refreshIcon}`} />
222
        </div>
223
      )}
224
    </div>
225
  );
226
};
227

228
export default Scheduled;
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