|
|
@@ -15,29 +15,22 @@
|
|
|
// limitations under the License.
|
|
|
|
|
|
import React, { useMemo, useState, useCallback } from 'react';
|
|
|
-import { ColumnProps } from 'antd/lib/table';
|
|
|
import { Input, Tooltip } from 'antd';
|
|
|
|
|
|
import FolderIcon from '@cloudera/cuix-core/icons/react/ProjectIcon';
|
|
|
import FileIcon from '@cloudera/cuix-core/icons/react/DocumentationIcon';
|
|
|
-import SortAscending from '@cloudera/cuix-core/icons/react/SortAscendingIcon';
|
|
|
-import SortDescending from '@cloudera/cuix-core/icons/react/SortDescendingIcon';
|
|
|
-
|
|
|
-import Table from 'cuix/dist/components/Table';
|
|
|
|
|
|
import { i18nReact } from '../../../utils/i18nReact';
|
|
|
import useDebounce from '../../../utils/useDebounce';
|
|
|
|
|
|
import { LIST_DIRECTORY_API_URL } from '../api';
|
|
|
import {
|
|
|
- SortOrder,
|
|
|
ListDirectory,
|
|
|
FileStats,
|
|
|
BrowserViewType,
|
|
|
StorageDirectoryTableData,
|
|
|
FileSystem
|
|
|
} from '../types';
|
|
|
-import Pagination from '../../../reactComponents/Pagination/Pagination';
|
|
|
import formatBytes from '../../../utils/formatBytes';
|
|
|
|
|
|
import './StorageDirectoryPage.scss';
|
|
|
@@ -55,20 +48,20 @@ import FileUploadQueue from '../../../reactComponents/FileUploadQueue/FileUpload
|
|
|
import { useWindowSize } from '../../../utils/hooks/useWindowSize/useWindowSize';
|
|
|
import LoadingErrorWrapper from '../../../reactComponents/LoadingErrorWrapper/LoadingErrorWrapper';
|
|
|
import StorageDirectoryActions from './StorageDirectoryActions/StorageDirectoryActions';
|
|
|
+import PaginatedTable, {
|
|
|
+ SortOrder,
|
|
|
+ ColumnProps
|
|
|
+} from '../../../reactComponents/PaginatedTable/PaginatedTable';
|
|
|
|
|
|
interface StorageDirectoryPageProps {
|
|
|
fileStats: FileStats;
|
|
|
fileSystem: FileSystem;
|
|
|
onFilePathChange: (path: string) => void;
|
|
|
- className?: string;
|
|
|
- rowClassName?: string;
|
|
|
testId?: string;
|
|
|
reloadTrashPath: () => void;
|
|
|
}
|
|
|
|
|
|
const defaultProps = {
|
|
|
- className: 'hue-storage-browser__table',
|
|
|
- rowClassName: 'hue-storage-browser__table-row',
|
|
|
testId: 'hue-storage-browser__table'
|
|
|
};
|
|
|
|
|
|
@@ -76,11 +69,8 @@ const StorageDirectoryPage = ({
|
|
|
fileStats,
|
|
|
fileSystem,
|
|
|
onFilePathChange,
|
|
|
- className,
|
|
|
- rowClassName,
|
|
|
testId,
|
|
|
- reloadTrashPath,
|
|
|
- ...restProps
|
|
|
+ reloadTrashPath
|
|
|
}: StorageDirectoryPageProps): JSX.Element => {
|
|
|
const [loadingFiles, setLoadingFiles] = useState<boolean>(false);
|
|
|
const [selectedFiles, setSelectedFiles] = useState<StorageDirectoryTableData[]>([]);
|
|
|
@@ -89,8 +79,9 @@ const StorageDirectoryPage = ({
|
|
|
|
|
|
const [pageSize, setPageSize] = useState<number>(DEFAULT_PAGE_SIZE);
|
|
|
const [pageNumber, setPageNumber] = useState<number>(1);
|
|
|
- const [sortByColumn, setSortByColumn] = useState<string>('');
|
|
|
- const [sortOrder, setSortOrder] = useState<SortOrder>(SortOrder.NONE);
|
|
|
+ const [sortByColumn, setSortByColumn] =
|
|
|
+ useState<ColumnProps<StorageDirectoryTableData>['dataIndex']>();
|
|
|
+ const [sortOrder, setSortOrder] = useState<SortOrder>(null);
|
|
|
const [searchTerm, setSearchTerm] = useState<string>('');
|
|
|
|
|
|
const { t } = i18nReact.useTranslation();
|
|
|
@@ -105,17 +96,15 @@ const StorageDirectoryPage = ({
|
|
|
path: fileStats.path,
|
|
|
pagesize: pageSize.toString(),
|
|
|
pagenum: pageNumber.toString(),
|
|
|
- filter: searchTerm,
|
|
|
+ filter: searchTerm !== '' ? searchTerm : undefined,
|
|
|
sortby: sortByColumn,
|
|
|
- descending: sortOrder === SortOrder.DSC ? 'true' : 'false'
|
|
|
+ descending: sortOrder !== null ? sortOrder === 'descend' : undefined
|
|
|
},
|
|
|
skip:
|
|
|
fileStats.path === '' ||
|
|
|
fileStats.path === undefined ||
|
|
|
fileStats.type !== BrowserViewType.dir,
|
|
|
- onSuccess: () => {
|
|
|
- setSelectedFiles([]);
|
|
|
- },
|
|
|
+ onSuccess: () => setSelectedFiles([]),
|
|
|
pollInterval: polling ? DEFAULT_POLLING_TIME : undefined
|
|
|
});
|
|
|
|
|
|
@@ -137,67 +126,6 @@ const StorageDirectoryPage = ({
|
|
|
}));
|
|
|
}, [filesData]);
|
|
|
|
|
|
- const onColumnTitleClicked = (columnClicked: string) => {
|
|
|
- if (columnClicked === sortByColumn) {
|
|
|
- if (sortOrder === SortOrder.NONE) {
|
|
|
- setSortOrder(SortOrder.ASC);
|
|
|
- } else if (sortOrder === SortOrder.ASC) {
|
|
|
- setSortOrder(SortOrder.DSC);
|
|
|
- } else {
|
|
|
- setSortOrder(SortOrder.NONE);
|
|
|
- }
|
|
|
- } else {
|
|
|
- setSortByColumn(columnClicked);
|
|
|
- setSortOrder(SortOrder.ASC);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- const getColumns = (file: StorageDirectoryTableData) => {
|
|
|
- const columns: ColumnProps<StorageDirectoryTableData>[] = [];
|
|
|
- for (const key of Object.keys(file)) {
|
|
|
- const column: ColumnProps<StorageDirectoryTableData> = {
|
|
|
- dataIndex: key,
|
|
|
- title: (
|
|
|
- <div
|
|
|
- className="hue-storage-browser__table-column-header"
|
|
|
- onClick={() => onColumnTitleClicked(key)}
|
|
|
- >
|
|
|
- <div className="hue-storage-browser__table-column-title">
|
|
|
- {key === 'mtime' ? t('Last Updated') : t(key)}
|
|
|
- </div>
|
|
|
- {key === sortByColumn ? (
|
|
|
- sortOrder === SortOrder.DSC ? (
|
|
|
- <SortDescending />
|
|
|
- ) : sortOrder === SortOrder.ASC ? (
|
|
|
- <SortAscending />
|
|
|
- ) : null
|
|
|
- ) : null}
|
|
|
- </div>
|
|
|
- ),
|
|
|
- key: `${key}`
|
|
|
- };
|
|
|
- if (key === 'name') {
|
|
|
- column.width = '40%';
|
|
|
- column.render = (_, record: StorageDirectoryTableData) => (
|
|
|
- <Tooltip title={record.name} mouseEnterDelay={1.5}>
|
|
|
- <span className="hue-storage-browser__table-cell-icon">
|
|
|
- {record.type === 'dir' ? <FolderIcon /> : <FileIcon />}
|
|
|
- </span>
|
|
|
- <span className="hue-storage-browser__table-cell-name">{record.name}</span>
|
|
|
- </Tooltip>
|
|
|
- );
|
|
|
- } else if (key === 'mtime') {
|
|
|
- column.width = '20%';
|
|
|
- } else if (key === 'permission') {
|
|
|
- column.width = '12%';
|
|
|
- }
|
|
|
- columns.push(column);
|
|
|
- }
|
|
|
- return columns.filter(
|
|
|
- col => col.dataIndex !== 'type' && col.dataIndex !== 'path' && col.dataIndex !== 'replication'
|
|
|
- );
|
|
|
- };
|
|
|
-
|
|
|
const onRowClicked = (record: StorageDirectoryTableData) => {
|
|
|
return {
|
|
|
onClick: () => {
|
|
|
@@ -211,12 +139,6 @@ const StorageDirectoryPage = ({
|
|
|
};
|
|
|
};
|
|
|
|
|
|
- const rowSelection = {
|
|
|
- onChange: (_: React.Key[], selectedRows: StorageDirectoryTableData[]) => {
|
|
|
- setSelectedFiles(selectedRows);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
const handleSearch = useCallback(
|
|
|
useDebounce(searchTerm => {
|
|
|
setSearchTerm(encodeURIComponent(searchTerm));
|
|
|
@@ -241,10 +163,6 @@ const StorageDirectoryPage = ({
|
|
|
// 40px for table header, 50px for pagination
|
|
|
const tableBodyHeight = Math.max(rect.height - 90, 100);
|
|
|
|
|
|
- const locale = {
|
|
|
- emptyText: t('Folder is empty')
|
|
|
- };
|
|
|
-
|
|
|
const errorConfig = [
|
|
|
{
|
|
|
enabled: !!listDirectoryError,
|
|
|
@@ -254,6 +172,64 @@ const StorageDirectoryPage = ({
|
|
|
}
|
|
|
];
|
|
|
|
|
|
+ const columnsConfig: ColumnProps<StorageDirectoryTableData>[] = [
|
|
|
+ {
|
|
|
+ title: t('Name'),
|
|
|
+ dataIndex: 'name',
|
|
|
+ key: 'name',
|
|
|
+ sorter: true,
|
|
|
+ width: '40%',
|
|
|
+ render: (_, record) => (
|
|
|
+ <Tooltip title={record.name} mouseEnterDelay={1.5}>
|
|
|
+ <div className="hue-storage-browser-directory__table-container__name-column">
|
|
|
+ <div className="hue-storage-browser-directory__table-container__name-column__icon">
|
|
|
+ {record.type === BrowserViewType.dir ? (
|
|
|
+ <FolderIcon height={18} width={18} />
|
|
|
+ ) : (
|
|
|
+ <FileIcon height={18} width={18} />
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ <div className="hue-storage-browser-directory__table-container__name-column__label">
|
|
|
+ {record.name}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Tooltip>
|
|
|
+ )
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: t('Size'),
|
|
|
+ dataIndex: 'size',
|
|
|
+ key: 'size',
|
|
|
+ width: '10%',
|
|
|
+ sorter: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: t('User'),
|
|
|
+ dataIndex: 'user',
|
|
|
+ key: 'user',
|
|
|
+ width: '10%'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: t('Group'),
|
|
|
+ dataIndex: 'group',
|
|
|
+ key: 'group',
|
|
|
+ width: '10%'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: t('Permission'),
|
|
|
+ dataIndex: 'permission',
|
|
|
+ key: 'permission',
|
|
|
+ width: '10%'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: t('Last Updated'),
|
|
|
+ dataIndex: 'mtime',
|
|
|
+ key: 'mtime',
|
|
|
+ width: '20%',
|
|
|
+ sorter: true
|
|
|
+ }
|
|
|
+ ];
|
|
|
+
|
|
|
return (
|
|
|
<div className="hue-storage-browser-directory">
|
|
|
<div className="hue-storage-browser-directory__actions-bar">
|
|
|
@@ -261,9 +237,7 @@ const StorageDirectoryPage = ({
|
|
|
className="hue-storage-browser-directory__actions-bar__search"
|
|
|
placeholder={t('Search')}
|
|
|
allowClear={true}
|
|
|
- onChange={event => {
|
|
|
- handleSearch(event.target.value);
|
|
|
- }}
|
|
|
+ onChange={event => handleSearch(event.target.value)}
|
|
|
disabled={!tableData.length && !searchTerm.length}
|
|
|
/>
|
|
|
<div className="hue-storage-browser-directory__actions-bar__actions">
|
|
|
@@ -288,34 +262,26 @@ const StorageDirectoryPage = ({
|
|
|
loading={(loadingFiles || listDirectoryLoading) && !polling}
|
|
|
errors={errorConfig}
|
|
|
>
|
|
|
- <Table
|
|
|
- className={className}
|
|
|
- columns={getColumns(tableData[0] ?? {})}
|
|
|
- dataSource={tableData}
|
|
|
- onRow={onRowClicked}
|
|
|
- pagination={false}
|
|
|
- rowClassName={rowClassName}
|
|
|
+ <PaginatedTable<StorageDirectoryTableData>
|
|
|
+ data={tableData}
|
|
|
+ columns={columnsConfig}
|
|
|
rowKey={r => `${r.path}_${r.type}_${r.mtime}`}
|
|
|
- rowSelection={{
|
|
|
- hideSelectAll: !tableData.length,
|
|
|
- columnWidth: 36,
|
|
|
- type: 'checkbox',
|
|
|
- ...rowSelection
|
|
|
- }}
|
|
|
+ onRowClick={onRowClicked}
|
|
|
+ onRowSelect={setSelectedFiles}
|
|
|
+ sortByColumn={sortByColumn}
|
|
|
+ setSortByColumn={setSortByColumn}
|
|
|
+ sortOrder={sortOrder}
|
|
|
+ setSortOrder={setSortOrder}
|
|
|
+ locale={{ emptyText: t('Folder is empty') }}
|
|
|
scroll={{ y: tableBodyHeight }}
|
|
|
- data-testid={testId}
|
|
|
- locale={locale}
|
|
|
- {...restProps}
|
|
|
+ testId={testId}
|
|
|
+ pagination={{
|
|
|
+ pageSize,
|
|
|
+ setPageSize,
|
|
|
+ setPageNumber,
|
|
|
+ pageStats: filesData?.page
|
|
|
+ }}
|
|
|
/>
|
|
|
-
|
|
|
- {filesData?.page && filesData?.page?.totalPages > 0 && (
|
|
|
- <Pagination
|
|
|
- setPageSize={setPageSize}
|
|
|
- pageSize={pageSize}
|
|
|
- setPageNumber={setPageNumber}
|
|
|
- pageStats={filesData?.page}
|
|
|
- />
|
|
|
- )}
|
|
|
</LoadingErrorWrapper>
|
|
|
</DragAndDrop>
|
|
|
</div>
|