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

mendersoftware / gui / 951400782

pending completion
951400782

Pull #3900

gitlab-ci

web-flow
chore: bump @testing-library/jest-dom from 5.16.5 to 5.17.0

Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 5.16.5 to 5.17.0.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v5.16.5...v5.17.0)

---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #3900: chore: bump @testing-library/jest-dom from 5.16.5 to 5.17.0

4446 of 6414 branches covered (69.32%)

8342 of 10084 relevant lines covered (82.73%)

186.0 hits per line

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

50.77
/src/js/components/devices/troubleshoot/filetransfer.js
1
// Copyright 2021 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

16
import { FileCopy as CopyPasteIcon } from '@mui/icons-material';
17
import { Button, IconButton, Tab, Tabs, TextField, Tooltip } from '@mui/material';
18
import { makeStyles } from 'tss-react/mui';
19

20
import { canAccess } from '../../../constants/appConstants';
21
import FileUpload from '../../common/forms/fileupload';
22
import InfoText from '../../common/infotext';
23

24
const tabs = [
13✔
25
  { key: 'upload', canAccess: ({ userCapabilities: { canTroubleshoot, canWriteDevices } }) => canTroubleshoot && canWriteDevices },
1✔
26
  { key: 'download', canAccess }
27
];
28

29
const maxWidth = 400;
13✔
30

31
const useStyles = makeStyles()(theme => ({
13✔
32
  column: { maxWidth },
33
  inputWrapper: { display: 'grid', gridTemplateColumns: `${maxWidth}px max-content` },
34
  tab: { alignItems: 'flex-start' },
35
  fileDestination: { marginTop: theme.spacing(2) }
36
}));
37

38
export const FileTransfer = ({
13✔
39
  deviceId,
40
  downloadPath,
41
  file,
42
  onDownload,
43
  onUpload,
44
  setFile,
45
  setDownloadPath,
46
  setSnackbar,
47
  setUploadPath,
48
  uploadPath,
49
  userCapabilities
50
}) => {
51
  const { classes } = useStyles();
2✔
52
  const [currentTab, setCurrentTab] = useState(tabs[0].key);
2✔
53
  const [isValidDestination, setIsValidDestination] = useState(true);
2✔
54
  const [availableTabs, setAvailableTabs] = useState(tabs);
2✔
55

56
  useEffect(() => {
2✔
57
    let destination = currentTab === 'download' ? downloadPath : uploadPath;
1!
58
    const isValid = destination.length ? /^(?:\/|[a-z]+:\/\/)/.test(destination) : true;
1!
59
    setIsValidDestination(isValid);
1✔
60
  }, [currentTab, downloadPath, uploadPath]);
61

62
  useEffect(() => {
2✔
63
    const availableTabs = tabs.reduce((accu, item) => {
1✔
64
      if (item.canAccess({ userCapabilities })) {
2!
65
        accu.push(item);
2✔
66
      }
67
      return accu;
2✔
68
    }, []);
69
    setAvailableTabs(availableTabs);
1✔
70
    setCurrentTab(availableTabs[0].key);
1✔
71
  }, [JSON.stringify(userCapabilities)]);
72

73
  const onPasteDownloadClick = async () => {
2✔
74
    const path = await navigator.clipboard.readText();
×
75
    setDownloadPath(path);
×
76
  };
77

78
  const onPasteUploadClick = async () => {
2✔
79
    const path = await navigator.clipboard.readText();
×
80
    setUploadPath(path);
×
81
  };
82

83
  const onFileSelect = selectedFile => {
2✔
84
    let path;
85
    if (selectedFile) {
×
86
      path = `${uploadPath}/${selectedFile.name}`;
×
87
    } else {
88
      path = file && uploadPath.includes(file.name) ? uploadPath.substring(0, uploadPath.lastIndexOf('/')) : uploadPath;
×
89
    }
90
    setUploadPath(path);
×
91
    setFile(selectedFile);
×
92
  };
93

94
  return (
2✔
95
    <div className="tab-container with-sub-panels" style={{ minHeight: '95%' }}>
96
      <Tabs orientation="vertical" className="leftFixed" onChange={(e, item) => setCurrentTab(item)} value={currentTab}>
×
97
        {availableTabs.map(({ key }) => (
98
          <Tab className={`${classes.tab} capitalized`} key={key} label={key} value={key} />
4✔
99
        ))}
100
      </Tabs>
101
      <div className="rightFluid padding-right">
102
        {currentTab === 'upload' ? (
2!
103
          <>
104
            <InfoText className={classes.column}>Upload a file to the device</InfoText>
105
            <FileUpload
106
              enableContentReading={false}
107
              fileNameSelection={file?.name}
108
              onFileChange={() => undefined}
×
109
              onFileSelect={onFileSelect}
110
              placeholder={
111
                <>
112
                  Drag here or <a>browse</a> to upload a file
113
                </>
114
              }
115
              setSnackbar={setSnackbar}
116
              style={{ maxWidth }}
117
            />
118
            <div className={classes.inputWrapper}>
119
              <TextField
120
                autoFocus={true}
121
                error={!isValidDestination}
122
                fullWidth
123
                helperText={!isValidDestination && <div className="warning">Destination has to be an absolute path</div>}
2!
124
                inputProps={{ style: { marginTop: 16 } }}
125
                InputLabelProps={{ shrink: true }}
126
                label="Destination directory on the device where the file will be transferred"
127
                onChange={e => setUploadPath(e.target.value)}
×
128
                placeholder="Example: /opt/installed-by-single-file"
129
                value={uploadPath}
130
              />
131
              <Tooltip title="Paste" placement="top">
132
                <IconButton style={{ alignSelf: 'flex-end' }} onClick={onPasteUploadClick} size="large">
133
                  <CopyPasteIcon />
134
                </IconButton>
135
              </Tooltip>
136
            </div>
137
            <div className={`flexbox margin-top ${classes.column}`} style={{ justifyContent: 'flex-end' }}>
138
              <Button
139
                variant="contained"
140
                color="primary"
141
                disabled={!(file && uploadPath && isValidDestination)}
2!
142
                onClick={() => onUpload(deviceId, uploadPath, file)}
×
143
              >
144
                Upload
145
              </Button>
146
            </div>
147
          </>
148
        ) : (
149
          <>
150
            <InfoText>Download a file from the device</InfoText>
151
            <div className={classes.inputWrapper}>
152
              <TextField
153
                autoFocus={true}
154
                className={classes.column}
155
                error={!isValidDestination}
156
                fullWidth
157
                helperText={!isValidDestination && <div className="warning">Destination has to be an absolute path</div>}
×
158
                inputProps={{ className: classes.fileDestination }}
159
                InputLabelProps={{ shrink: true }}
160
                label="Path to the file on the device"
161
                onChange={e => setDownloadPath(e.target.value)}
×
162
                placeholder="Example: /home/mender/"
163
                value={downloadPath}
164
              />
165
              <Tooltip title="Paste" placement="top">
166
                <IconButton style={{ alignSelf: 'flex-end' }} onClick={onPasteDownloadClick} size="large">
167
                  <CopyPasteIcon />
168
                </IconButton>
169
              </Tooltip>
170
            </div>
171
            <div className={`flexbox margin-top ${classes.column}`} style={{ justifyContent: 'flex-end' }}>
172
              <Button
173
                variant="contained"
174
                color="primary"
175
                disabled={!(downloadPath && isValidDestination)}
×
176
                onClick={() => onDownload(downloadPath)}
×
177
                style={{ alignSelf: 'flex-end' }}
178
              >
179
                Download
180
              </Button>
181
            </div>
182
          </>
183
        )}
184
      </div>
185
    </div>
186
  );
187
};
188

189
export default FileTransfer;
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