Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ui-storagebrowser] view file content as text #3823

Merged
merged 41 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
f7e1cf8
[ui-core]: feat: add useFetch hook for API calls
ramprasadagarwal Aug 14, 2024
dc0984e
add the license information
ramprasadagarwal Aug 14, 2024
95cb886
fix lint
ramprasadagarwal Aug 14, 2024
fdd2c13
lint fix
ramprasadagarwal Aug 14, 2024
bbdbd4a
add library
ramprasadagarwal Aug 14, 2024
b97d332
pin the library version
ramprasadagarwal Aug 14, 2024
7a5c9d5
revert extra changes
ramprasadagarwal Aug 15, 2024
d5b5a2d
Merge branch 'master' of github.com:cloudera/hue into feat/useFetch-hook
ramprasadagarwal Aug 15, 2024
662fb1b
revert package-lock json
ramprasadagarwal Aug 15, 2024
74a99e4
Merge branch 'master' into feat/useFetch-hook
ramprasadagarwal Aug 16, 2024
a7ade51
fix: rename hook
ramprasadagarwal Aug 16, 2024
1702fef
Merge branch 'master' of github.com:cloudera/hue into feat/useFetch-hook
ramprasadagarwal Aug 16, 2024
a164444
Merge branch 'feat/useFetch-hook' of github.com:cloudera/hue into fea…
ramprasadagarwal Aug 16, 2024
3a4160a
fix the function name
ramprasadagarwal Aug 16, 2024
9dd4482
[ui-storagebrowser] chore: move useHuePubSub to hooks folder
ramprasadagarwal Aug 16, 2024
187dcaf
[ui-core] enhance formatBytes util function
ramprasadagarwal Aug 16, 2024
8441dfa
[ui-storagebrowser] replace api calls with useLoadData hook
ramprasadagarwal Aug 16, 2024
631955a
[ui-storagebrowser] add mising data-event props in PathBrowser component
ramprasadagarwal Aug 17, 2024
8c5f8c1
[ui-storagebrowser] view file content as text
ramprasadagarwal Aug 19, 2024
8a5a6b5
remove the duplicate interface
ramprasadagarwal Aug 20, 2024
a8dc4f6
make height auto scale
ramprasadagarwal Aug 20, 2024
69caab4
[api] Add /get_trash_path public API (#3817)
Harshg999 Aug 20, 2024
537ad3c
[ui-core]: feat: add useLoadData hook for API calls (#3819)
ramprasadagarwal Aug 20, 2024
56d9708
Merge branch 'master' of github.com:cloudera/hue into feat/view-file
ramprasadagarwal Aug 20, 2024
4d8b2b4
Merge branch 'master' of github.com:cloudera/hue into feat/view-file
ramprasadagarwal Sep 5, 2024
2cf2794
revert the tooltip for filename with the added delay
ramprasadagarwal Sep 5, 2024
d9b94a1
remove the mock for i18nreact from test file
ramprasadagarwal Sep 5, 2024
2fd2f0b
consistent naming for tabContent
ramprasadagarwal Sep 5, 2024
098b934
remove the unneccesary type declaration
ramprasadagarwal Sep 5, 2024
fa48ad0
fix failing test
ramprasadagarwal Sep 5, 2024
320e3a1
fix style-lint
ramprasadagarwal Sep 5, 2024
bcdb13a
mock the date object for timezone
ramprasadagarwal Sep 7, 2024
fb3f614
fix the linting
ramprasadagarwal Sep 7, 2024
3f89756
mock formatTimestamp funtion to resolve timzeone issue
ramprasadagarwal Sep 7, 2024
9fc13a8
Merge branch 'master' of github.com:cloudera/hue into feat/view-file
ramprasadagarwal Sep 16, 2024
d37e36d
fix the css classnames with respect to BEM rules
ramprasadagarwal Sep 16, 2024
27aef4c
fix the testid naming convention
ramprasadagarwal Sep 16, 2024
a10eac1
fix the layout issue
ramprasadagarwal Sep 16, 2024
0902a30
add nullish coalescing for table data
ramprasadagarwal Sep 17, 2024
4f6555b
Merge branch 'master' into feat/view-file
ramprasadagarwal Sep 17, 2024
56dee74
Merge branch 'master' into feat/view-file
ramprasadagarwal Sep 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,22 @@
}

.hue-storage-browser__tab {
display: flex;
flex: 1;
background-color: vars.$fluidx-gray-100;
padding: 0 16px;
height: 100%;

.ant-tabs-content-holder {
display: flex;
flex: 1;
overflow: auto;

.ant-tabs-content,
.ant-tabs-tabpane-active {
display: flex;
flex-direction: column;
flex: 1;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,26 @@
@use 'mixins';

.antd.cuix {
.ant-spin-nested-loading,
ramprasadagarwal marked this conversation as resolved.
Show resolved Hide resolved
.ant-spin-container {
display: flex;
flex-direction: column;
flex: 1;
}

.hue-storage-browser-tabContent {
ramprasadagarwal marked this conversation as resolved.
Show resolved Hide resolved
margin: vars.$fluidx-spacing-s 0;
display: flex;
flex: 1;
flex-direction: column;
margin: vars.$fluidx-spacing-s;
}

.hue-storage-browser__title-bar {
display: flex;
margin: 0 vars.$fluidx-spacing-s;
gap: vars.$fluidx-spacing-xs;
}

.hue-storage-browser__icon {
margin-right: vars.$fluidx-spacing-xs;
flex: 0 0 auto;
height: vars.$fluidx-heading-h3-line-height;
}
Expand All @@ -41,13 +50,12 @@

.hue-storage-browser__path-browser-panel {
display: flex;
margin: vars.$fluidx-spacing-xs 0;
align-items: center;
gap: vars.$fluidx-spacing-xs;
}

.hue-storage-browser__filePath {
flex: 0 0 auto;
font-weight: 600;
margin: 0 vars.$fluidx-spacing-xs 0 vars.$fluidx-spacing-s;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,16 @@ import BucketIcon from '@cloudera/cuix-core/icons/react/BucketIcon';
import PathBrowser from '../../../../reactComponents/FileChooser/PathBrowser/PathBrowser';
import StorageBrowserTable from '../StorageBrowserTable/StorageBrowserTable';
import { VIEWFILES_API_URl } from '../../../../reactComponents/FileChooser/api';
import { PathAndFileData, SortOrder } from '../../../../reactComponents/FileChooser/types';
import {
BrowserViewType,
PathAndFileData,
SortOrder
} from '../../../../reactComponents/FileChooser/types';
import { DEFAULT_PAGE_SIZE } from '../../../../utils/constants/storageBrowser';
import useLoadData from '../../../../utils/hooks/useLoadData';

import './StorageBrowserTabContent.scss';
import StorageFilePage from '../../StorageFilePage/StorageFilePage';

interface StorageBrowserTabContentProps {
user_home_dir: string;
Expand Down Expand Up @@ -73,7 +78,7 @@ const StorageBrowserTabContent = ({
<div className="hue-storage-browser__title-bar" data-testid={`${testId}-title-bar`}>
<BucketIcon className="hue-storage-browser__icon" data-testid={`${testId}-icon`} />
<h3 className="hue-storage-browser__folder-name" data-testid={`${testId}-folder-namer`}>
{filesData?.breadcrumbs[filesData?.breadcrumbs?.length - 1].label}
{filesData?.path?.split('/').pop()}
</h3>
</div>
<div
Expand All @@ -88,20 +93,24 @@ const StorageBrowserTabContent = ({
showIcon={false}
/>
</div>
<StorageBrowserTable
filesData={filesData}
pageSize={pageSize}
onFilepathChange={setFilePath}
onPageSizeChange={setPageSize}
onPageNumberChange={setPageNumber}
onSortByColumnChange={setSortByColumn}
onSortOrderChange={setSortOrder}
onSearch={setSearchTerm}
sortByColumn={sortByColumn}
sortOrder={sortOrder}
refetchData={reloadData}
filePath={filePath}
/>
{filesData?.type === BrowserViewType.file ? (
<StorageFilePage fileData={filesData} />
) : (
<StorageBrowserTable
filesData={filesData}
pageSize={pageSize}
onFilepathChange={setFilePath}
onPageSizeChange={setPageSize}
onPageNumberChange={setPageNumber}
onSortByColumnChange={setSortByColumn}
onSortOrderChange={setSortOrder}
onSearch={setSearchTerm}
sortByColumn={sortByColumn}
sortOrder={sortOrder}
refetchData={reloadData}
filePath={filePath}
/>
)}
</div>
</Spin>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ $icon-margin: 5px;
.antd.cuix {
.hue-storage-browser__actions-bar {
display: flex;
margin: vars.$fluidx-spacing-s;
margin: vars.$fluidx-spacing-s 0;
justify-content: space-between;
}

Expand All @@ -46,8 +46,6 @@ $icon-margin: 5px;
}

.hue-storage-browser__table {
margin: 0 vars.$fluidx-spacing-s;

.ant-table-placeholder {
height: $table-placeholder-height;
text-align: center;
Expand All @@ -65,6 +63,10 @@ $icon-margin: 5px;
}

.hue-storage-browser__table-row {
:hover {
cursor: pointer;
}

td.ant-table-cell {
height: $cell-height;
@include mixins.nowrap-ellipsis;
Expand All @@ -87,4 +89,4 @@ $icon-margin: 5px;
.hue-storage-browser__actions-dropdown {
width: $action-dropdown-width;
@include mixins.hue-svg-icon__d3-conflict;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import React, { useEffect, useMemo, useState, useCallback } from 'react';
import React, { useMemo, useState, useCallback, useEffect } from 'react';
import { ColumnProps } from 'antd/lib/table';
import { Dropdown, Input, Spin } from 'antd';
import { MenuItemGroupType } from 'antd/lib/menu/hooks/useItems';
import Tooltip from 'antd/es/tooltip';

import FolderIcon from '@cloudera/cuix-core/icons/react/ProjectIcon';
import SortAscending from '@cloudera/cuix-core/icons/react/SortAscendingIcon';
Expand All @@ -39,14 +38,15 @@ import { mkdir, touch } from '../../../../reactComponents/FileChooser/api';
import {
StorageBrowserTableData,
SortOrder,
PathAndFileData,
BrowserViewType
PathAndFileData
} from '../../../../reactComponents/FileChooser/types';
import Pagination from '../../../../reactComponents/Pagination/Pagination';
import StorageBrowserActions from '../StorageBrowserActions/StorageBrowserActions';
import InputModal from '../../InputModal/InputModal';
import formatBytes from '../../../../utils/formatBytes';

import './StorageBrowserTable.scss';
import { formatTimestamp } from '../../../../utils/dateTimeUtils';

interface StorageBrowserTableProps {
className?: string;
Expand Down Expand Up @@ -91,29 +91,28 @@ const StorageBrowserTable = ({
...restProps
}: StorageBrowserTableProps): JSX.Element => {
const [loadingFiles, setLoadingFiles] = useState<boolean>(false);
const [tableHeight, setTableHeight] = useState<number>();
const [tableHeight, setTableHeight] = useState<number>(100);
ramprasadagarwal marked this conversation as resolved.
Show resolved Hide resolved
const [selectedFiles, setSelectedFiles] = useState<StorageBrowserTableData[]>([]);
const [showNewFolderModal, setShowNewFolderModal] = useState<boolean>(false);
const [showNewFileModal, setShowNewFileModal] = useState<boolean>(false);
const [viewType, setViewType] = useState<BrowserViewType>(BrowserViewType.dir);

const { t } = i18nReact.useTranslation();

const tableData: StorageBrowserTableData[] = useMemo(() => {
return (
filesData?.files
?.filter(file => !['.', '..'].includes(file.name)) // removes ..(previous folder) and .(current folder)
.map(file => ({
name: file.name,
size: file.humansize,
user: file.stats.user,
group: file.stats.group,
permission: file.rwx,
mtime: file.mtime,
type: file.type,
path: file.path
})) ?? []
);
if (!filesData?.files) {
return [];
}

return filesData?.files?.map(file => ({
ramprasadagarwal marked this conversation as resolved.
Show resolved Hide resolved
name: file.name,
size: formatBytes(file.stats?.size),
user: file.stats.user,
group: file.stats.group,
permission: file.rwx,
mtime: file.stats?.mtime ? formatTimestamp(new Date(Number(file.stats.mtime) * 1000)) : '-',
type: file.type,
path: file.path
}));
}, [filesData]);

const newActionsMenuItems: MenuItemGroupType[] = [
Expand Down Expand Up @@ -171,7 +170,7 @@ const StorageBrowserTable = ({

const getColumns = (file: StorageBrowserTableData) => {
const columns: ColumnProps<StorageBrowserTableData>[] = [];
for (const [key] of Object.entries(file)) {
for (const key of Object.keys(file)) {
ramprasadagarwal marked this conversation as resolved.
Show resolved Hide resolved
const column: ColumnProps<StorageBrowserTableData> = {
dataIndex: key,
title: (
Expand All @@ -195,14 +194,15 @@ const StorageBrowserTable = ({
};
if (key === 'name') {
column.width = '40%';
//TODO: Apply tooltip only for truncated values
column.render = (_, record: StorageBrowserTableData) => (
<Tooltip title={record.name}>
<>
ramprasadagarwal marked this conversation as resolved.
Show resolved Hide resolved
<span className="hue-storage-browser__table-cell-icon">
{record.type === 'dir' ? <FolderIcon /> : <FileOutlined />}
</span>
<span className="hue-storage-browser__table-cell-name">{record.name}</span>
</Tooltip>
<span className="hue-storage-browser__table-cell-name" title={record.name}>
ramprasadagarwal marked this conversation as resolved.
Show resolved Hide resolved
{record.name}
</span>
</>
);
} else if (key === 'mtime') {
column.width = '20%';
Expand Down Expand Up @@ -302,14 +302,6 @@ const StorageBrowserTable = ({
};
}, []);

useEffect(() => {
if (filesData?.type === 'file') {
setViewType(BrowserViewType.file);
} else {
setViewType(BrowserViewType.dir);
}
}, [filesData]);

const locale = {
emptyText: t('Folder is empty')
};
Expand All @@ -326,56 +318,45 @@ const StorageBrowserTable = ({
}}
/>
<div className="hue-storage-browser__actions-bar-right">
{viewType === BrowserViewType.dir && (
<>
<StorageBrowserActions
selectedFiles={selectedFiles}
setLoadingFiles={setLoadingFiles}
onSuccessfulAction={refetchData}
/>
<Dropdown
overlayClassName="hue-storage-browser__actions-dropdown"
menu={{
items: newActionsMenuItems,
className: 'hue-storage-browser__action-menu'
}}
trigger={['hover', 'click']}
>
<PrimaryButton data-event={''}>
{t('New')}
<DropDownIcon />
</PrimaryButton>
</Dropdown>
</>
)}
<StorageBrowserActions
selectedFiles={selectedFiles}
setLoadingFiles={setLoadingFiles}
onSuccessfulAction={refetchData}
/>
<Dropdown
overlayClassName="hue-storage-browser__actions-dropdown"
menu={{
items: newActionsMenuItems,
className: 'hue-storage-browser__action-menu'
}}
trigger={['hover', 'click']}
>
<PrimaryButton data-event={''}>
ramprasadagarwal marked this conversation as resolved.
Show resolved Hide resolved
{t('New')}
<DropDownIcon />
</PrimaryButton>
</Dropdown>
</div>
</div>

<Spin spinning={loadingFiles}>
{viewType === BrowserViewType.dir && (
<Table
className={className}
columns={getColumns(tableData[0] ?? [])}
dataSource={tableData}
onRow={onRowClicked}
pagination={false}
rowClassName={rowClassName}
rowKey={(record, index) => record.path + '' + index}
rowSelection={{
type: 'checkbox',
...rowSelection
}}
scroll={{ y: tableHeight }}
data-testid={`${testId}`}
locale={locale}
{...restProps}
/>
)}

{viewType === BrowserViewType.file && (
// TODO: code for file view
<div> File view</div>
)}
<Table
className={className}
columns={getColumns(tableData[0] ?? {})}
dataSource={tableData.slice(2) ?? []}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that this is old code, but perhaps we can fix it anyway. The nullish coalescing operator only returns the right hand if tableData is null or undefined. But we can't slice a null or undefined value, it will throw an error.

Suggested change
dataSource={tableData.slice(2) ?? []}
dataSource={tableData?.slice(2) ?? []}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tableData will be an array always, either and empty one or non-empty one, although having nullish coalescing operator doesn't harm.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, well then the unnecessary nullish coalescing operator only adds confusion (at least for me) and should probably be removed :-)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, reverting it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So given what we know about nullish coalescing and that tableData will always be an array, I think we should just write
dataSource={tableData?.slice(2)}

since slicing an empty array will return an empty array.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense, noted and changed.

onRow={onRowClicked}
pagination={false}
rowClassName={rowClassName}
rowKey={(record, index) => record.path + '' + index}
rowSelection={{
type: 'checkbox',
...rowSelection
}}
scroll={{ y: tableHeight }}
data-testid={`${testId}`}
locale={locale}
{...restProps}
/>

{filesData?.page && (
<Pagination
Expand Down
Loading
Loading