Skip to content

Commit 73c5e6d

Browse files
Merge branch 'master' into Overview
2 parents db25ed4 + 382177d commit 73c5e6d

File tree

17 files changed

+679
-467
lines changed

17 files changed

+679
-467
lines changed

desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/StorageDirectoryPage.tsx

+4-8
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,10 @@ import formatBytes from '../../../utils/formatBytes';
3636
import './StorageDirectoryPage.scss';
3737
import { formatTimestamp } from '../../../utils/dateTimeUtils';
3838
import useLoadData from '../../../utils/hooks/useLoadData/useLoadData';
39-
import {
40-
DEFAULT_PAGE_SIZE,
41-
DEFAULT_POLLING_TIME,
42-
FileUploadStatus
43-
} from '../../../utils/constants/storageBrowser';
39+
import { DEFAULT_PAGE_SIZE, DEFAULT_POLLING_TIME } from '../../../utils/constants/storageBrowser';
4440
import DragAndDrop from '../../../reactComponents/DragAndDrop/DragAndDrop';
4541
import UUID from '../../../utils/string/UUID';
46-
import { UploadItem } from '../../../utils/hooks/useFileUpload/util';
42+
import { RegularFile, FileStatus } from '../../../utils/hooks/useFileUpload/types';
4743
import FileUploadQueue from '../../../reactComponents/FileUploadQueue/FileUploadQueue';
4844
import { useWindowSize } from '../../../utils/hooks/useWindowSize/useWindowSize';
4945
import LoadingErrorWrapper from '../../../reactComponents/LoadingErrorWrapper/LoadingErrorWrapper';
@@ -74,7 +70,7 @@ const StorageDirectoryPage = ({
7470
}: StorageDirectoryPageProps): JSX.Element => {
7571
const [loadingFiles, setLoadingFiles] = useState<boolean>(false);
7672
const [selectedFiles, setSelectedFiles] = useState<StorageDirectoryTableData[]>([]);
77-
const [filesToUpload, setFilesToUpload] = useState<UploadItem[]>([]);
73+
const [filesToUpload, setFilesToUpload] = useState<RegularFile[]>([]);
7874
const [polling, setPolling] = useState<boolean>(false);
7975

8076
const [pageSize, setPageSize] = useState<number>(DEFAULT_PAGE_SIZE);
@@ -152,7 +148,7 @@ const StorageDirectoryPage = ({
152148
file,
153149
filePath: fileStats.path,
154150
uuid: UUID(),
155-
status: FileUploadStatus.Pending
151+
status: FileStatus.Pending
156152
};
157153
});
158154
setPolling(true);

desktop/core/src/desktop/js/reactComponents/FileUploadQueue/FileUploadQueue.scss

+1-32
Original file line numberDiff line numberDiff line change
@@ -44,37 +44,6 @@
4444
overflow: auto;
4545
padding: 16px;
4646
gap: 16px;
47-
48-
&__row {
49-
display: flex;
50-
align-items: center;
51-
padding: 8px;
52-
font-size: 14px;
53-
gap: 8px;
54-
border: solid 1px vars.$fluidx-gray-300;
55-
56-
&__status {
57-
display: flex;
58-
width: 20px;
59-
}
60-
61-
&__name {
62-
display: flex;
63-
flex: 1;
64-
text-overflow: ellipsis;
65-
}
66-
67-
&__size {
68-
display: flex;
69-
text-align: right;
70-
color: vars.$fluidx-gray-700;
71-
}
72-
73-
&__close {
74-
display: flex;
75-
}
76-
}
7747
}
78-
7948
}
80-
}
49+
}

desktop/core/src/desktop/js/reactComponents/FileUploadQueue/FileUploadQueue.test.tsx

+5-31
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,22 @@
1515
// limitations under the License.
1616

1717
import React from 'react';
18-
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
18+
import { render, screen, fireEvent } from '@testing-library/react';
1919
import '@testing-library/jest-dom';
2020
import FileUploadQueue from './FileUploadQueue';
21-
import { FileUploadStatus } from '../../utils/constants/storageBrowser';
22-
import { UploadItem } from '../../utils/hooks/useFileUpload/util';
21+
import { FileStatus, RegularFile } from '../../utils/hooks/useFileUpload/types';
2322

24-
const mockFilesQueue: UploadItem[] = [
23+
const mockFilesQueue: RegularFile[] = [
2524
{
2625
uuid: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx1',
2726
filePath: '/path/to/file1.txt',
28-
status: FileUploadStatus.Pending,
27+
status: FileStatus.Pending,
2928
file: new File([], 'file1.txt')
3029
},
3130
{
3231
uuid: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx2',
3332
filePath: '/path/to/file2.txt',
34-
status: FileUploadStatus.Pending,
33+
status: FileStatus.Pending,
3534
file: new File([], 'file2.txt')
3635
}
3736
];
@@ -55,19 +54,6 @@ describe('FileUploadQueue', () => {
5554
expect(getByText('file2.txt')).toBeInTheDocument();
5655
});
5756

58-
it('should call onCancel when cancel button is clicked', async () => {
59-
const { getAllByTestId } = render(
60-
<FileUploadQueue filesQueue={mockFilesQueue} onClose={() => {}} onComplete={() => {}} />
61-
);
62-
63-
const cancelButton = getAllByTestId('upload-queue__list__row__close-icon')[0];
64-
fireEvent.click(cancelButton);
65-
66-
await waitFor(() => {
67-
expect(mockOnCancel).toHaveBeenCalled();
68-
});
69-
});
70-
7157
it('should toggle the visibility of the queue when the header is clicked', () => {
7258
const { getByTestId } = render(
7359
<FileUploadQueue filesQueue={mockFilesQueue} onClose={() => {}} onComplete={() => {}} />
@@ -85,16 +71,4 @@ describe('FileUploadQueue', () => {
8571
expect(screen.getByText('file1.txt')).toBeInTheDocument();
8672
expect(screen.getByText('file2.txt')).toBeInTheDocument();
8773
});
88-
89-
it('should render cancel button for files in Pending state', () => {
90-
const { getAllByTestId } = render(
91-
<FileUploadQueue filesQueue={mockFilesQueue} onClose={() => {}} onComplete={() => {}} />
92-
);
93-
94-
const cancelButtons = getAllByTestId('upload-queue__list__row__close-icon');
95-
expect(cancelButtons).toHaveLength(mockFilesQueue.length);
96-
97-
expect(cancelButtons[0]).toBeInTheDocument();
98-
expect(cancelButtons[1]).toBeInTheDocument();
99-
});
10074
});

desktop/core/src/desktop/js/reactComponents/FileUploadQueue/FileUploadQueue.tsx

+20-58
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,29 @@
1515
// limitations under the License.
1616

1717
import React, { useState } from 'react';
18-
import './FileUploadQueue.scss';
19-
import { Tooltip } from 'antd';
2018
import CloseIcon from '../../components/icons/CloseIcon';
2119
import { i18nReact } from '../../utils/i18nReact';
22-
import formatBytes from '../../utils/formatBytes';
23-
import StatusPendingIcon from '@cloudera/cuix-core/icons/react/StatusPendingIcon';
24-
import StatusInProgressIcon from '@cloudera/cuix-core/icons/react/StatusInProgressIcon';
25-
import StatusSuccessIcon from '@cloudera/cuix-core/icons/react/StatusSuccessIcon';
26-
import StatusStoppedIcon from '@cloudera/cuix-core/icons/react/StatusStoppedIcon';
27-
import StatusErrorIcon from '@cloudera/cuix-core/icons/react/StatusErrorIcon';
28-
import { UploadItem } from '../../utils/hooks/useFileUpload/util';
20+
import { RegularFile, FileStatus } from '../../utils/hooks/useFileUpload/types';
2921
import useFileUpload from '../../utils/hooks/useFileUpload/useFileUpload';
30-
import {
31-
DEFAULT_ENABLE_CHUNK_UPLOAD,
32-
FileUploadStatus
33-
} from '../../utils/constants/storageBrowser';
22+
import { DEFAULT_ENABLE_CHUNK_UPLOAD } from '../../utils/constants/storageBrowser';
3423
import { getLastKnownConfig } from '../../config/hueConfig';
24+
import FileUploadRow from './FileUploadRow/FileUploadRow';
25+
26+
import './FileUploadQueue.scss';
3527

3628
interface FileUploadQueueProps {
37-
filesQueue: UploadItem[];
29+
filesQueue: RegularFile[];
3830
onClose: () => void;
3931
onComplete: () => void;
4032
}
4133

4234
const sortOrder = [
43-
FileUploadStatus.Uploading,
44-
FileUploadStatus.Failed,
45-
FileUploadStatus.Pending,
46-
FileUploadStatus.Canceled,
47-
FileUploadStatus.Uploaded
48-
].reduce((acc: Record<string, number>, status: FileUploadStatus, index: number) => {
35+
FileStatus.Uploading,
36+
FileStatus.Failed,
37+
FileStatus.Pending,
38+
FileStatus.Cancelled,
39+
FileStatus.Uploaded
40+
].reduce((acc: Record<string, number>, status: FileStatus, index: number) => {
4941
acc[status] = index + 1;
5042
return acc;
5143
}, {});
@@ -64,21 +56,11 @@ const FileUploadQueue: React.FC<FileUploadQueueProps> = ({ filesQueue, onClose,
6456
onComplete
6557
});
6658

67-
const uploadedCount = uploadQueue.filter(
68-
item => item.status === FileUploadStatus.Uploaded
69-
).length;
59+
const uploadedCount = uploadQueue.filter(item => item.status === FileStatus.Uploaded).length;
7060
const pendingCount = uploadQueue.filter(
71-
item => item.status === FileUploadStatus.Pending || item.status === FileUploadStatus.Uploading
61+
item => item.status === FileStatus.Pending || item.status === FileStatus.Uploading
7262
).length;
7363

74-
const statusIcon = {
75-
[FileUploadStatus.Pending]: <StatusPendingIcon />,
76-
[FileUploadStatus.Uploading]: <StatusInProgressIcon />,
77-
[FileUploadStatus.Uploaded]: <StatusSuccessIcon />,
78-
[FileUploadStatus.Canceled]: <StatusStoppedIcon />,
79-
[FileUploadStatus.Failed]: <StatusErrorIcon />
80-
};
81-
8264
return (
8365
<div className="upload-queue cuix antd">
8466
<div
@@ -99,32 +81,12 @@ const FileUploadQueue: React.FC<FileUploadQueueProps> = ({ filesQueue, onClose,
9981
<div className="upload-queue__list">
10082
{uploadQueue
10183
.sort((a, b) => sortOrder[a.status] - sortOrder[b.status])
102-
.map((row: UploadItem) => (
103-
<div key={`${row.filePath}__${row.file.name}`} className="upload-queue__list__row">
104-
<Tooltip
105-
title={row.status}
106-
mouseEnterDelay={1.5}
107-
className="upload-queue__list__row__status"
108-
>
109-
{statusIcon[row.status]}
110-
</Tooltip>
111-
<div className="upload-queue__list__row__name">{row.file.name}</div>
112-
<div className="upload-queue__list__row__size">{formatBytes(row.file.size)}</div>
113-
{row.status === FileUploadStatus.Pending && (
114-
<Tooltip
115-
title={t('Cancel')}
116-
mouseEnterDelay={1.5}
117-
className="upload-queue__list__row__close"
118-
>
119-
<CloseIcon
120-
data-testid="upload-queue__list__row__close-icon"
121-
onClick={() => onCancel(row)}
122-
height={16}
123-
width={16}
124-
/>
125-
</Tooltip>
126-
)}
127-
</div>
84+
.map((row: RegularFile) => (
85+
<FileUploadRow
86+
key={`${row.filePath}__${row.file.name}`}
87+
data={row}
88+
onCancel={() => onCancel(row)}
89+
/>
12890
))}
12991
</div>
13092
)}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Licensed to Cloudera, Inc. under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. Cloudera, Inc. licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
@use 'variables' as vars;
18+
19+
.antd.cuix {
20+
.hue-upload-queue-row {
21+
display: flex;
22+
flex-direction: column;
23+
border: solid 1px vars.$fluidx-gray-300;
24+
25+
&__container {
26+
display: flex;
27+
align-items: center;
28+
font-size: 14px;
29+
padding: 8px;
30+
gap: 8px;
31+
}
32+
33+
&__status {
34+
display: flex;
35+
width: 20px;
36+
}
37+
38+
&__name {
39+
display: flex;
40+
flex: 1;
41+
text-overflow: ellipsis;
42+
}
43+
44+
&__size {
45+
display: flex;
46+
text-align: right;
47+
color: vars.$fluidx-gray-700;
48+
}
49+
50+
&__close-icon {
51+
cursor: pointer;
52+
height: 16px;
53+
width: 16px;
54+
}
55+
56+
&__progressbar {
57+
height: 2px;
58+
background-color: vars.$fluidx-blue-500;
59+
}
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Licensed to Cloudera, Inc. under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. Cloudera, Inc. licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
import React from 'react';
18+
import { render, fireEvent, waitFor } from '@testing-library/react';
19+
import '@testing-library/jest-dom';
20+
import { RegularFile, FileStatus } from '../../../utils/hooks/useFileUpload/types';
21+
import FileUploadRow from './FileUploadRow';
22+
23+
const mockUploadRow: RegularFile = {
24+
uuid: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx1',
25+
filePath: '/path/to/file1.txt',
26+
status: FileStatus.Pending,
27+
file: new File(['mock test file'], 'file1.txt'),
28+
progress: 0
29+
};
30+
const mockOnCancel = jest.fn();
31+
32+
describe('FileUploadRow', () => {
33+
it('should render the row with name', () => {
34+
const { getByText } = render(<FileUploadRow data={mockUploadRow} onCancel={mockOnCancel} />);
35+
36+
expect(getByText('file1.txt')).toBeInTheDocument();
37+
expect(getByText('14 Bytes')).toBeInTheDocument();
38+
});
39+
40+
it('should call onCancel when cancel button is clicked', async () => {
41+
const { getByTestId } = render(<FileUploadRow data={mockUploadRow} onCancel={mockOnCancel} />);
42+
43+
const cancelButton = getByTestId('hue-upload-queue-row__close-icon');
44+
fireEvent.click(cancelButton);
45+
46+
await waitFor(() => {
47+
expect(mockOnCancel).toHaveBeenCalled();
48+
});
49+
});
50+
51+
it('should hide cancel button for files is not in Pending state', () => {
52+
const mockData = { ...mockUploadRow, status: FileStatus.Failed };
53+
const { queryByTestId } = render(<FileUploadRow data={mockData} onCancel={mockOnCancel} />);
54+
55+
const cancelButtons = queryByTestId('hue-upload-queue-row__close-icon');
56+
expect(cancelButtons).not.toBeInTheDocument();
57+
});
58+
59+
it('should show progress bar when file is in uploading state', () => {
60+
const mockData = { ...mockUploadRow, status: FileStatus.Uploading, progress: 10 };
61+
const { getByRole } = render(<FileUploadRow data={mockData} onCancel={mockOnCancel} />);
62+
const progressBar = getByRole('hue-upload-queue-row__progressbar');
63+
expect(progressBar).toBeInTheDocument();
64+
expect(progressBar).toHaveStyle('width: 10%');
65+
});
66+
});

0 commit comments

Comments
 (0)