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

mendersoftware / gui / 988636826

01 Sep 2023 04:04AM UTC coverage: 82.384% (-17.6%) from 99.964%
988636826

Pull #3969

gitlab-ci

web-flow
chore: Bump autoprefixer from 10.4.14 to 10.4.15

Bumps [autoprefixer](https://github.com/postcss/autoprefixer) from 10.4.14 to 10.4.15.
- [Release notes](https://github.com/postcss/autoprefixer/releases)
- [Changelog](https://github.com/postcss/autoprefixer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/autoprefixer/compare/10.4.14...10.4.15)

---
updated-dependencies:
- dependency-name: autoprefixer
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #3969: chore: Bump autoprefixer from 10.4.14 to 10.4.15

4346 of 6321 branches covered (0.0%)

8259 of 10025 relevant lines covered (82.38%)

192.73 hits per line

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

92.86
/src/js/components/releases/releases.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, useMemo, useRef, useState } from 'react';
15
import { useDispatch, useSelector } from 'react-redux';
16

17
import { CloudUpload } from '@mui/icons-material';
18
import { Button, Tab, Tabs } from '@mui/material';
19
import { makeStyles } from 'tss-react/mui';
20

21
import pluralize from 'pluralize';
22

23
import { getReleases, selectRelease, setReleasesListState } from '../../actions/releaseActions';
24
import { BENEFITS, SORTING_OPTIONS, TIMEOUTS } from '../../constants/appConstants';
25
import { getFeatures, getIsEnterprise, getReleasesList, getUserCapabilities } from '../../selectors';
26
import { useDebounce } from '../../utils/debouncehook';
27
import { useLocationParams } from '../../utils/liststatehook';
28
import ChipSelect from '../common/chipselect';
29
import EnterpriseNotification, { DefaultUpgradeNotification } from '../common/enterpriseNotification';
30
import Search from '../common/search';
31
import { HELPTOOLTIPS, MenderHelpTooltip } from '../helptips/helptooltips';
32
import AddArtifactDialog from './dialogs/addartifact';
33
import ReleaseDetails from './releasedetails';
34
import ReleasesList from './releaseslist';
35

36
const refreshArtifactsLength = 60000;
4✔
37

38
const DeltaProgress = () => {
4✔
39
  const isEnterprise = useSelector(getIsEnterprise);
×
40
  return (
×
41
    <div className="dashboard-placeholder" style={{ display: 'grid', placeContent: 'center' }}>
42
      {isEnterprise ? 'There is no automatic delta artifacts generation running.' : <DefaultUpgradeNotification />}
×
43
    </div>
44
  );
45
};
46

47
const DeltaTitle = () => (
4✔
48
  <div className="flexbox center-aligned">
27✔
49
    <div>Delta Artifacts generation</div>
50
    <EnterpriseNotification className="margin-left-small" id={BENEFITS.deltaGeneration.id} />
51
  </div>
52
);
53

54
const tabs = [
4✔
55
  { key: 'releases', Title: () => 'Releases', component: ReleasesList },
27✔
56
  { key: 'delta', Title: DeltaTitle, component: DeltaProgress }
57
];
58

59
const useStyles = makeStyles()(theme => ({
4✔
60
  filters: { maxWidth: 400, alignItems: 'end', columnGap: 50 },
61
  searchNote: { minHeight: '1.8rem' },
62
  tabContainer: { alignSelf: 'flex-start' },
63
  uploadButton: { minWidth: 164, marginRight: theme.spacing(2) }
64
}));
65

66
const Header = ({ canUpload, existingTags = [], features, hasReleases, releasesListState, setReleasesListState, onUploadClick }) => {
4!
67
  const { hasReleaseTags } = features;
27✔
68
  const { selectedTags = [], searchTerm, searchTotal, tab = tabs[0].key, total } = releasesListState;
27✔
69
  const { classes } = useStyles();
27✔
70

71
  const searchUpdated = useCallback(searchTerm => setReleasesListState({ searchTerm }), [setReleasesListState]);
27✔
72

73
  const onTabChanged = (e, tab) => setReleasesListState({ tab });
27✔
74

75
  const onTagSelectionChanged = ({ selection }) => setReleasesListState({ selectedTags: selection });
27✔
76

77
  return (
27✔
78
    <div>
79
      <div className="flexbox space-between center-aligned">
80
        <Tabs className={classes.tabContainer} value={tab} onChange={onTabChanged} textColor="primary">
81
          {tabs.map(({ key, Title }) => (
82
            <Tab key={key} label={<Title />} value={key} />
54✔
83
          ))}
84
        </Tabs>
85
        {canUpload && (
54✔
86
          <div className="flexbox center-aligned">
87
            <Button color="secondary" className={classes.uploadButton} onClick={onUploadClick} startIcon={<CloudUpload fontSize="small" />} variant="contained">
88
              Upload
89
            </Button>
90
            <MenderHelpTooltip id={HELPTOOLTIPS.artifactUpload.id} style={{ marginTop: 8 }} />
91
          </div>
92
        )}
93
      </div>
94
      {hasReleases && tab === tabs[0].key && (
81✔
95
        <div className={`two-columns ${classes.filters}`}>
96
          <Search onSearch={searchUpdated} searchTerm={searchTerm} placeholder="Search releases by name" />
97
          {hasReleaseTags && (
27!
98
            <ChipSelect
99
              id="release-tag-selection"
100
              label="Filter by tag"
101
              onChange={onTagSelectionChanged}
102
              placeholder="Filter by tag"
103
              selection={selectedTags}
104
              options={existingTags}
105
            />
106
          )}
107
        </div>
108
      )}
109
      <p className={`muted ${classes.searchNote}`}>{searchTerm && searchTotal !== total ? `Filtered from ${total} ${pluralize('Release', total)}` : ''}</p>
55✔
110
    </div>
111
  );
112
};
113

114
export const Releases = () => {
4✔
115
  const features = useSelector(getFeatures);
28✔
116
  const hasReleases = useSelector(
27✔
117
    state => !!(Object.keys(state.releases.byId).length || state.releases.releasesList.total || state.releases.releasesList.searchTotal)
51!
118
  );
119
  const releases = useSelector(getReleasesList);
27✔
120
  const releasesListState = useSelector(state => state.releases.releasesList);
51✔
121
  const releaseTags = useSelector(state => state.releases.releaseTags);
51✔
122
  const selectedRelease = useSelector(state => state.releases.byId[state.releases.selectedRelease]) ?? {};
51✔
123
  const userCapabilities = useSelector(getUserCapabilities);
27✔
124
  const { canUploadReleases } = userCapabilities;
27✔
125
  const dispatch = useDispatch();
27✔
126

127
  const [selectedFile, setSelectedFile] = useState();
27✔
128
  const [showAddArtifactDialog, setShowAddArtifactDialog] = useState(false);
27✔
129
  const artifactTimer = useRef();
27✔
130
  const [locationParams, setLocationParams] = useLocationParams('releases', { defaults: { direction: SORTING_OPTIONS.desc, key: 'modified' } });
27✔
131
  const { searchTerm, sort = {}, page, perPage, tab = tabs[0].key, selectedTags } = releasesListState;
27!
132
  const debouncedSearchTerm = useDebounce(searchTerm, TIMEOUTS.debounceDefault);
27✔
133

134
  useEffect(() => {
27✔
135
    if (!artifactTimer.current) {
14✔
136
      return;
4✔
137
    }
138
    setLocationParams({ pageState: { ...releasesListState, selectedRelease: selectedRelease.Name } });
10✔
139
    // eslint-disable-next-line react-hooks/exhaustive-deps
140
  }, [debouncedSearchTerm, JSON.stringify(sort), page, perPage, selectedRelease.Name, setLocationParams, tab, JSON.stringify(selectedTags)]);
141

142
  useEffect(() => {
27✔
143
    const { selectedRelease, tags, ...remainder } = locationParams;
9✔
144
    if (selectedRelease) {
9✔
145
      dispatch(selectRelease(selectedRelease));
2✔
146
    }
147
    dispatch(setReleasesListState({ ...remainder, selectedTags: tags }));
9✔
148
    clearInterval(artifactTimer.current);
9✔
149
    artifactTimer.current = setInterval(() => dispatch(getReleases()), refreshArtifactsLength);
9✔
150
    return () => {
9✔
151
      clearInterval(artifactTimer.current);
9✔
152
    };
153
    // eslint-disable-next-line react-hooks/exhaustive-deps
154
  }, [dispatch, JSON.stringify(locationParams)]);
155

156
  const onUploadClick = () => setShowAddArtifactDialog(true);
27✔
157

158
  const onFileUploadClick = selectedFile => {
27✔
159
    setSelectedFile(selectedFile);
×
160
    setShowAddArtifactDialog(true);
×
161
  };
162

163
  const onHideAddArtifactDialog = () => setShowAddArtifactDialog(false);
27✔
164

165
  const onSetReleasesListState = useCallback(state => dispatch(setReleasesListState(state)), [dispatch]);
27✔
166

167
  const ContentComponent = useMemo(() => tabs.find(({ key }) => key === tab).component, [tab]);
27✔
168
  return (
27✔
169
    <div className="margin">
170
      <div>
171
        <Header
172
          canUpload={canUploadReleases}
173
          existingTags={releaseTags}
174
          features={features}
175
          hasReleases={hasReleases}
176
          onUploadClick={onUploadClick}
177
          releasesListState={releasesListState}
178
          setReleasesListState={onSetReleasesListState}
179
        />
180
        <ContentComponent onFileUploadClick={onFileUploadClick} />
181
      </div>
182
      <ReleaseDetails />
183
      {showAddArtifactDialog && (
27!
184
        <AddArtifactDialog releases={releases} onCancel={onHideAddArtifactDialog} onUploadStarted={onHideAddArtifactDialog} selectedFile={selectedFile} />
185
      )}
186
    </div>
187
  );
188
};
189

190
export default Releases;
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