瀏覽代碼

[ui-core] refactor storage browser to extend file preview feature (#3779)

* [ui-core]: refactor storage browser table component

* fix: handle empty folder edge case

* fix: lint
Ram Prasad Agarwal 1 年之前
父節點
當前提交
6d08458ed6

+ 10 - 28
desktop/core/src/desktop/js/apps/storageBrowser/StorageBrowserPage/StorageBrowserTabContents/StorageBrowserTabContent.tsx

@@ -14,7 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, useCallback } from 'react';
 import { Spin } from 'antd';
 
 import { i18nReact } from '../../../../utils/i18nReact';
@@ -23,12 +23,7 @@ import BucketIcon from '@cloudera/cuix-core/icons/react/BucketIcon';
 import PathBrowser from '../../../../reactComponents/FileChooser/PathBrowser/PathBrowser';
 import StorageBrowserTable from '../StorageBrowserTable/StorageBrowserTable';
 import { fetchFiles } from '../../../../reactComponents/FileChooser/api';
-import {
-  PathAndFileData,
-  StorageBrowserTableData,
-  PageStats,
-  SortOrder
-} from '../../../../reactComponents/FileChooser/types';
+import { PathAndFileData, SortOrder } from '../../../../reactComponents/FileChooser/types';
 
 import './StorageBrowserTabContent.scss';
 
@@ -47,9 +42,7 @@ const StorageBrowserTabContent = ({
 }: StorageBrowserTabContentProps): JSX.Element => {
   const [filePath, setFilePath] = useState<string>(user_home_dir);
   const [filesData, setFilesData] = useState<PathAndFileData>();
-  const [files, setFiles] = useState<StorageBrowserTableData[]>();
   const [loadingFiles, setLoadingFiles] = useState(true);
-  const [pageStats, setPageStats] = useState<PageStats>();
   const [pageSize, setPageSize] = useState<number>(0);
   const [pageNumber, setPageNumber] = useState<number>(1);
   const [sortByColumn, setSortByColumn] = useState<string>('');
@@ -57,27 +50,13 @@ const StorageBrowserTabContent = ({
   //TODO: Add filter functionality
   const [filterData] = useState<string>('');
 
-  const [refreshKey, setRefreshKey] = useState<number>(0);
-
   const { t } = i18nReact.useTranslation();
 
-  useEffect(() => {
+  const getFiles = useCallback(async () => {
     setLoadingFiles(true);
     fetchFiles(filePath, pageSize, pageNumber, filterData, sortByColumn, sortOrder)
       .then(responseFilesData => {
         setFilesData(responseFilesData);
-        const tableData: StorageBrowserTableData[] = responseFilesData.files.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
-        }));
-        setFiles(tableData);
-        setPageStats(responseFilesData.page);
         setPageSize(responseFilesData.pagesize);
       })
       .catch(error => {
@@ -87,7 +66,11 @@ const StorageBrowserTabContent = ({
       .finally(() => {
         setLoadingFiles(false);
       });
-  }, [filePath, pageSize, pageNumber, sortByColumn, sortOrder, refreshKey]);
+  }, [filePath, pageSize, pageNumber, filterData, sortByColumn, sortOrder]);
+
+  useEffect(() => {
+    getFiles();
+  }, [filePath, pageSize, pageNumber, sortByColumn, sortOrder]);
 
   return (
     <Spin spinning={loadingFiles}>
@@ -111,8 +94,7 @@ const StorageBrowserTabContent = ({
           />
         </div>
         <StorageBrowserTable
-          dataSource={files}
-          pageStats={pageStats}
+          filesData={filesData}
           pageSize={pageSize}
           onFilepathChange={setFilePath}
           onPageSizeChange={setPageSize}
@@ -121,7 +103,7 @@ const StorageBrowserTabContent = ({
           onSortOrderChange={setSortOrder}
           sortByColumn={sortByColumn}
           sortOrder={sortOrder}
-          setRefreshKey={setRefreshKey}
+          refetchData={getFiles}
           setLoadingFiles={setLoadingFiles}
           filePath={filePath}
         />

+ 95 - 70
desktop/core/src/desktop/js/apps/storageBrowser/StorageBrowserPage/StorageBrowserTable/StorageBrowserTable.tsx

@@ -14,7 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useMemo, useState } from 'react';
 import { ColumnProps } from 'antd/lib/table';
 import { Dropdown, Input } from 'antd';
 import { MenuItemGroupType } from 'antd/lib/menu/hooks/useItems';
@@ -35,18 +35,20 @@ import { i18nReact } from '../../../../utils/i18nReact';
 import huePubSub from '../../../../utils/huePubSub';
 import { mkdir, touch } from '../../../../reactComponents/FileChooser/api';
 import {
-  PageStats,
   StorageBrowserTableData,
-  SortOrder
+  SortOrder,
+  PathAndFileData,
+  BrowserViewType
 } from '../../../../reactComponents/FileChooser/types';
 import Pagination from '../../../../reactComponents/Pagination/Pagination';
 import StorageBrowserActions from '../StorageBrowserActions/StorageBrowserActions';
 import InputModal from '../../InputModal/InputModal';
 
 import './StorageBrowserTable.scss';
+
 interface StorageBrowserTableProps {
   className?: string;
-  dataSource?: StorageBrowserTableData[];
+  filesData?: PathAndFileData;
   filePath: string;
   onFilepathChange: (path: string) => void;
   onPageNumberChange: (pageNumber: number) => void;
@@ -54,11 +56,10 @@ interface StorageBrowserTableProps {
   onSortByColumnChange: (sortByColumn: string) => void;
   onSortOrderChange: (sortOrder: SortOrder) => void;
   pageSize: number;
-  pageStats?: PageStats;
   sortByColumn: string;
   sortOrder: SortOrder;
   rowClassName?: string;
-  setRefreshKey: (value: number) => void;
+  refetchData: () => void;
   setLoadingFiles: (value: boolean) => void;
   testId?: string;
 }
@@ -71,7 +72,7 @@ const defaultProps = {
 
 const StorageBrowserTable = ({
   className,
-  dataSource,
+  filesData,
   filePath,
   onFilepathChange,
   onPageNumberChange,
@@ -81,9 +82,8 @@ const StorageBrowserTable = ({
   sortByColumn,
   sortOrder,
   pageSize,
-  pageStats,
   rowClassName,
-  setRefreshKey,
+  refetchData,
   setLoadingFiles,
   testId,
   ...restProps
@@ -92,9 +92,27 @@ const StorageBrowserTable = ({
   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
+        })) ?? []
+    );
+  }, [filesData]);
+
   const newActionsMenuItems: MenuItemGroupType[] = [
     {
       key: 'create',
@@ -194,11 +212,10 @@ const StorageBrowserTable = ({
   const onRowClicked = (record: StorageBrowserTableData) => {
     return {
       onClick: () => {
+        onFilepathChange(record.path);
         if (record.type === 'dir') {
-          onFilepathChange(record.path);
           onPageNumberChange(1);
         }
-        //TODO: handle onclick file
       }
     };
   };
@@ -220,15 +237,11 @@ const StorageBrowserTable = ({
     onPageNumberChange(nextPageNumber === 0 ? numPages : nextPageNumber);
   };
 
-  const reloadData = () => {
-    setRefreshKey(oldKey => oldKey + 1);
-  };
-
   const handleCreateNewFolder = (folderName: string) => {
     setLoadingFiles(true);
     mkdir(folderName, filePath)
       .then(() => {
-        reloadData();
+        refetchData();
       })
       .catch(error => {
         huePubSub.publish('hue.error', error);
@@ -243,7 +256,7 @@ const StorageBrowserTable = ({
     setLoadingFiles(true);
     touch(fileName, filePath)
       .then(() => {
-        reloadData();
+        refetchData();
       })
       .catch(error => {
         huePubSub.publish('hue.error', error);
@@ -277,46 +290,53 @@ const StorageBrowserTable = ({
     };
   }, []);
 
-  //function removes ..(previous folder) and .(current folder) from table data
-  const removeDots = (dataSource: StorageBrowserTableData[]) => {
-    return dataSource.length > 2 ? dataSource.slice(2) : [];
-  };
+  useEffect(() => {
+    if (filesData?.type === 'file') {
+      setViewType(BrowserViewType.file);
+    } else {
+      setViewType(BrowserViewType.dir);
+    }
+  }, [filesData]);
 
   const locale = {
     emptyText: t('Folder is empty')
   };
 
-  if (dataSource && pageStats) {
-    return (
-      <>
-        <div className="hue-storage-browser__actions-bar">
-          <Input className="hue-storage-browser__search" placeholder={t('Search')} />
-          <div className="hue-storage-browser__actions-bar-right">
-            <StorageBrowserActions
-              selectedFiles={selectedFiles}
-              setLoadingFiles={setLoadingFiles}
-              onSuccessfulAction={reloadData}
-            />
-            <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>
-          </div>
+  return (
+    <>
+      <div className="hue-storage-browser__actions-bar">
+        <Input className="hue-storage-browser__search" placeholder={t('Search')} />
+        <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>
+            </>
+          )}
         </div>
+      </div>
 
+      {viewType === BrowserViewType.dir && (
         <Table
           className={className}
-          columns={getColumns(dataSource[0])}
-          dataSource={removeDots(dataSource)}
+          columns={getColumns(tableData[0] ?? [])}
+          dataSource={tableData}
           onRow={onRowClicked}
           pagination={false}
           rowClassName={rowClassName}
@@ -330,37 +350,42 @@ const StorageBrowserTable = ({
           locale={locale}
           {...restProps}
         />
+      )}
 
+      {viewType === BrowserViewType.file && (
+        // TODO: code for file view
+        <div> File view</div>
+      )}
+
+      {filesData?.page && (
         <Pagination
           onNextPageButtonClicked={onNextPageButtonClicked}
           onPageNumberChange={onPageNumberChange}
           onPageSizeChange={onPageSizeChange}
           onPreviousPageButtonClicked={onPreviousPageButtonClicked}
           pageSize={pageSize}
-          pageStats={pageStats}
+          pageStats={filesData?.page}
         />
+      )}
 
-        <InputModal
-          title={t('Create New Folder')}
-          inputLabel={t('Enter Folder name here')}
-          submitText={t('Create')}
-          showModal={showNewFolderModal}
-          onSubmit={handleCreateNewFolder}
-          onClose={() => setShowNewFolderModal(false)}
-        />
-        <InputModal
-          title={t('Create New File')}
-          inputLabel={t('Enter File name here')}
-          submitText={t('Create')}
-          showModal={showNewFileModal}
-          onSubmit={handleCreateNewFile}
-          onClose={() => setShowNewFileModal(false)}
-        />
-      </>
-    );
-  } else {
-    return <div />;
-  }
+      <InputModal
+        title={t('Create New Folder')}
+        inputLabel={t('Enter Folder name here')}
+        submitText={t('Create')}
+        showModal={showNewFolderModal}
+        onSubmit={handleCreateNewFolder}
+        onClose={() => setShowNewFolderModal(false)}
+      />
+      <InputModal
+        title={t('Create New File')}
+        inputLabel={t('Enter File name here')}
+        submitText={t('Create')}
+        showModal={showNewFileModal}
+        onSubmit={handleCreateNewFile}
+        onClose={() => setShowNewFileModal(false)}
+      />
+    </>
+  );
 };
 
 StorageBrowserTable.defaultProps = defaultProps;

+ 6 - 0
desktop/core/src/desktop/js/reactComponents/FileChooser/types.ts

@@ -78,6 +78,7 @@ export interface PathAndFileData {
   files: File[];
   page: PageStats;
   pagesize: number;
+  type?: string;
 }
 
 export interface ContentSummary {
@@ -99,3 +100,8 @@ export enum SortOrder {
   DSC = 'descending',
   NONE = 'none'
 }
+
+export enum BrowserViewType {
+  dir = 'dir',
+  file = 'file'
+}