浏览代码

[ui-storageBrowser] Add home, refresh, edit and copy path functionalities (#3996)

* [ui-storageBrowser] Add home, refresh, edit path and copy path functionalities
Nidhi Bhat G 8 月之前
父节点
当前提交
cc9aa66ff3

+ 2 - 6
desktop/core/src/desktop/js/apps/storageBrowser/FileChooserModal/FileChooserModal.scss

@@ -29,12 +29,7 @@ $icon-margin: 5px;
   .hue-filechooser-modal__path-browser-panel {
     display: flex;
     align-items: center;
-    gap: vars.$fluidx-spacing-xs;
-  }
-
-  .hue-filechooser-modal__destPath {
-    flex: 0 0 auto;
-    font-weight: 600;
+    gap: 2px;
   }
 
   .hue-filechooser-modal__search {
@@ -65,6 +60,7 @@ $icon-margin: 5px;
   .hue-filechooser-modal__table-cell-icon {
     color: vars.$fluidx-blue-700;
     margin-right: 6px;
+    vertical-align: middle;
   }
 
   .hue-filechooser-modal__table-row {

+ 0 - 1
desktop/core/src/desktop/js/apps/storageBrowser/FileChooserModal/FileChooserModal.test.tsx

@@ -65,7 +65,6 @@ describe('FileChooserModal', () => {
     );
     await waitFor(() => {
       expect(screen.getByText('Select File')).toBeInTheDocument();
-      expect(screen.getByText('Destination Path:')).toBeInTheDocument();
       expect(screen.getByText('Cancel')).toBeInTheDocument();
       expect(screen.getByText('Submit')).toBeInTheDocument();
     });

+ 0 - 1
desktop/core/src/desktop/js/apps/storageBrowser/FileChooserModal/FileChooserModal.tsx

@@ -146,7 +146,6 @@ const FileChooserModal = ({
     >
       <div className="hue-filechooser-modal__body">
         <div className="hue-filechooser-modal__path-browser-panel">
-          <span className="hue-filechooser-modal__destPath">{t('Destination Path:')}</span>
           <PathBrowser
             filePath={destPath}
             onFilepathChange={setDestPath}

+ 23 - 6
desktop/core/src/desktop/js/apps/storageBrowser/StorageBrowserTab/StorageBrowserTab.scss

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 @use 'variables' as vars;
+@use 'mixins';
 
 .antd.cuix {
   .hue-storage-browser-tab-content {
@@ -24,8 +25,24 @@
   }
 
   .hue-storage-browser__title-bar {
+    display: flex;
+    justify-content: space-between;
+  }
+
+  .hue-storage-browser__title {
     display: flex;
     gap: vars.$fluidx-spacing-xs;
+    max-width: 60%;
+    margin-right: vars.$fluidx-spacing-xl
+  }
+
+  .hue-storage-browser__home-bar-btns {
+    padding: vars.$fluidx-spacing-xxs;
+  }
+
+  .hue-storage-browser__home-bar-right {
+    display: flex;
+    gap: vars.$fluidx-spacing-s;
   }
 
   .hue-storage-browser__icon {
@@ -38,16 +55,16 @@
     font-size: vars.$fluidx-heading-h3-size;
     line-height: vars.$fluidx-heading-h3-line-height;
     font-weight: vars.$fluidx-heading-h3-weight;
+    width: 100%;
+    @include mixins.nowrap-ellipsis;
+
+    display: inline;
   }
 
   .hue-storage-browser__path-browser-panel {
     display: flex;
     align-items: center;
-    gap: vars.$fluidx-spacing-xs;
-  }
-
-  .hue-storage-browser__filePath {
-    flex: 0 0 auto;
-    font-weight: 600;
+    gap: 2px;
+    margin-left: vars.$fluidx-spacing-xxs;
   }
 }

+ 33 - 7
desktop/core/src/desktop/js/apps/storageBrowser/StorageBrowserTab/StorageBrowserTab.tsx

@@ -24,12 +24,15 @@ import StorageDirectoryPage from '../StorageDirectoryPage/StorageDirectoryPage';
 import { FILE_STATS_API_URL } from '../api';
 import { BrowserViewType, FileStats, FileSystem } from '../types';
 import useLoadData from '../../../utils/hooks/useLoadData/useLoadData';
+import { BorderlessButton } from 'cuix/dist/components/Button';
 
 import './StorageBrowserTab.scss';
 import StorageFilePage from '../StorageFilePage/StorageFilePage';
 import changeURL from '../../../utils/url/changeURL';
 import LoadingErrorWrapper from '../../../reactComponents/LoadingErrorWrapper/LoadingErrorWrapper';
 import { getFileSystemAndPath } from '../../../reactComponents/PathBrowser/PathBrowser.util';
+import RefreshIcon from '@cloudera/cuix-core/icons/react/RefreshIcon';
+import HomeIcon from '@cloudera/cuix-core/icons/react/HomeIcon';
 
 interface StorageBrowserTabProps {
   fileSystem: FileSystem;
@@ -49,10 +52,10 @@ const StorageBrowserTab = ({ fileSystem, testId }: StorageBrowserTabProps): JSX.
     urlFileSystem === fileSystem.file_system ? urlFilePath : fileSystem.user_home_directory;
 
   const [filePath, setFilePath] = useState<string>(initialFilePath);
-  const fileName = filePath.split('/').pop() ?? '';
+  const fileName =
+    filePath.split('/').pop() !== '' ? (filePath.split('/').pop() ?? '') : filePath.split('://')[0];
 
   const { t } = i18nReact.useTranslation();
-
   const {
     data: fileStats,
     loading,
@@ -96,16 +99,39 @@ const StorageBrowserTab = ({ fileSystem, testId }: StorageBrowserTabProps): JSX.
     <LoadingErrorWrapper loading={loading} errors={errorConfig}>
       <div className="hue-storage-browser-tab-content" data-testid={testId}>
         <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`}>
-            {fileName}
-          </h3>
+          <div className="hue-storage-browser__title">
+            <BucketIcon className="hue-storage-browser__icon" data-testid={`${testId}-icon`} />
+            <h3 className="hue-storage-browser__folder-name" data-testid={`${testId}-folder-namer`}>
+              {fileName}
+            </h3>
+          </div>
+          <div className="hue-storage-browser__home-bar-right">
+            <BorderlessButton
+              onClick={() => {
+                setFilePath(fileSystem.user_home_directory);
+              }}
+              className="hue-storage-browser__home-bar-btns"
+              data-event={''}
+              title={'home'}
+              icon={<HomeIcon />}
+            >
+              {t('Home')}
+            </BorderlessButton>
+            <BorderlessButton
+              onClick={() => reloadData()}
+              className="hue-storage-browser__home-bar-btns"
+              data-event={''}
+              title={'Refresh'}
+              icon={<RefreshIcon />}
+            >
+              {t('Refresh')}
+            </BorderlessButton>
+          </div>
         </div>
         <div
           className="hue-storage-browser__path-browser-panel"
           data-testid={`${testId}-path-browser-panel`}
         >
-          <span className="hue-storage-browser__filePath">{t('File Path:')}</span>
           <PathBrowser
             filePath={filePath}
             onFilepathChange={setFilePath}

+ 2 - 1
desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/StorageDirectoryPage.scss

@@ -24,7 +24,7 @@ $icon-margin: 5px;
 .antd.cuix {
   .hue-storage-browser__actions-bar {
     display: flex;
-    margin: vars.$fluidx-spacing-s 0;
+    margin: vars.$fluidx-spacing-s 0 vars.$fluidx-spacing-s vars.$fluidx-spacing-xxs;
     justify-content: space-between;
   }
 
@@ -60,6 +60,7 @@ $icon-margin: 5px;
   .hue-storage-browser__table-cell-icon {
     color: vars.$fluidx-blue-700;
     margin-right: 6px;
+    vertical-align: middle;
   }
 
   .hue-storage-browser__table-row {

+ 0 - 4
desktop/core/src/desktop/js/reactComponents/PathBrowser/Breadcrumb/Breadcrumb.scss

@@ -17,9 +17,5 @@
 .antd.cuix {
   .hue-path-browser__breadcrumb {
     display: contents;
-
-    .hue-path-browser__overflowing-label {
-      min-width: var(--min-width);
-    }
   }
 }

+ 1 - 6
desktop/core/src/desktop/js/reactComponents/PathBrowser/Breadcrumb/Breadcrumb.tsx

@@ -30,13 +30,8 @@ const Breadcrumb = ({ label, url, onFilepathChange }: BreadcrumbProps): JSX.Elem
     onFilepathChange(url);
   };
 
-  const minWidth = '' + (label.length < 10 ? label.length : 10) + 'ch';
-
   return (
-    <div
-      className="hue-path-browser__breadcrumb"
-      style={{ '--min-width': `${minWidth}` } as React.CSSProperties}
-    >
+    <div className="hue-path-browser__breadcrumb">
       <OverflowingItem onClick={handleFilepathChange} label={label} />
     </div>
   );

+ 3 - 1
desktop/core/src/desktop/js/reactComponents/PathBrowser/OverflowingItem.scss

@@ -23,12 +23,14 @@
     flex: 0 1 auto;
     background-color: transparent;
     border: none;
+    max-width: 30%;
 
     >span {
       @include mixins.nowrap-ellipsis;
 
-      max-width: 150ch;
       display: inline !important;
+      font-size: vars.$font-size-lg;
+      line-height: 32px;
     }
   }
 }

+ 4 - 17
desktop/core/src/desktop/js/reactComponents/PathBrowser/PathBrowser.scss

@@ -22,8 +22,7 @@ $icon-height: 24px;
 
 .antd.cuix {
   .hue-path-browser {
-    display: flex;
-    width: 100%;
+    display: contents;
 
     .hue-path-browser__file-system-icon {
       object-fit: cover;
@@ -31,24 +30,11 @@ $icon-height: 24px;
       height: $icon-height;
       margin: 0 vars.$fluidx-spacing-xs;
     }
-
-    .hue-path-browser__toggle-breadcrumb-input-btn:empty {
-      pointer-events: auto;
-      width: 60px;
-      visibility: visible;
-      background-color: transparent;
-      padding: 0;
-
-      &:hover {
-        cursor: text;
-      }
-    }
   }
 
   .hue-path-browser__breadcrumbs {
-    display: flex;
-    gap: vars.$fluidx-spacing-xs;
-    max-width: 60%;
+    display: contents;
+    font-size: vars.$font-size-lg;
 
     &:hover {
       cursor: pointer;
@@ -74,6 +60,7 @@ $icon-height: 24px;
     justify-content: center;
     align-items: center;
     flex: 0 0 auto;
+    color: vars.$fluidx-gray-700;
   }
 
   .hue-path-browser__input {

+ 25 - 5
desktop/core/src/desktop/js/reactComponents/PathBrowser/PathBrowser.test.tsx

@@ -53,10 +53,13 @@ describe('Pathbrowser', () => {
           showIcon
         />
       );
-      screen.getAllByTestId('pathbroswer-breadcrumb-seperator').forEach(element => {
-        expect(element).toBeVisible();
-        expect(element).toHaveTextContent('%');
-      });
+      screen
+        .getAllByTestId('pathbroswer-breadcrumb-seperator')
+        .slice(1)
+        .forEach(element => {
+          expect(element).toBeVisible();
+          expect(element).toHaveTextContent('%');
+        });
     });
 
     it('should render breadcrumbs without dropdown button if there are less than or equal to 3 breadcrumbs', () => {
@@ -153,8 +156,25 @@ describe('Pathbrowser', () => {
           showIcon
         />
       );
-      const input = screen.queryByDisplayValue('abfs://test/test1');
+      const input = screen.queryByDisplayValue(mockFilePath);
       expect(input).toBeNull();
     });
+
+    it('should show input when edit path button is clicked', async () => {
+      render(
+        <PathBrowser
+          onFilepathChange={onFilepathChangeMock}
+          filePath={mockFilePath}
+          seperator={'/'}
+          showIcon
+        />
+      );
+      let input = screen.queryByDisplayValue(mockFilePath);
+      expect(input).toBeNull();
+      const editPathButton = screen.getByTestId('hue-path-browser__edit-path-btn');
+      await userEvent.click(editPathButton);
+      input = screen.getByDisplayValue(mockFilePath);
+      expect(input).not.toBeNull();
+    });
   });
 });

+ 19 - 11
desktop/core/src/desktop/js/reactComponents/PathBrowser/PathBrowser.tsx

@@ -22,6 +22,8 @@ import { MenuItemType } from 'antd/lib/menu/hooks/useItems';
 import HdfsIcon from '../../components/icons/HdfsIcon';
 import S3Icon from '../../components/icons/S3Icon';
 import AdlsIcon from '../../components/icons/AdlsIcon';
+import EditIcon from '@cloudera/cuix-core/icons/react/EditIcon';
+import CopyPathIcon from '@cloudera/cuix-core/icons/react/CopyClipboardIcon';
 
 import Breadcrumb from './Breadcrumb/Breadcrumb';
 import './PathBrowser.scss';
@@ -56,6 +58,7 @@ const PathBrowser = ({
 
   const { fileSystem, path } = getFileSystemAndPath(filePath);
   const breadcrumbs = getBreadcrumbs(fileSystem, path);
+  const URISchemeSeparator = fileSystem === 'hdfs' ? seperator : '://';
 
   const useOutsideAlerter = (ref: RefObject<HTMLDivElement>) => {
     useEffect(() => {
@@ -133,7 +136,7 @@ const PathBrowser = ({
                       className="hue-path-browser__breadcrumb-seperator"
                       data-testid={`${testId}-breadcrumb-seperator`}
                     >
-                      {seperator}
+                      {index === 0 ? URISchemeSeparator : seperator}
                     </div>
                   )}
                 </React.Fragment>
@@ -151,7 +154,7 @@ const PathBrowser = ({
                 className="hue-path-browser__breadcrumb-seperator"
                 data-testid={`${testId}-breadcrumb-seperator`}
               >
-                {seperator}
+                {URISchemeSeparator}
               </div>
               <Dropdown
                 overlayClassName="hue-path-browser__dropdown cuix antd"
@@ -199,15 +202,20 @@ const PathBrowser = ({
           )}
         </div>
         <BorderlessButton
-          data-event=""
-          className="hue-path-browser__toggle-breadcrumb-input-btn"
-          aria-label="hue-path-browser__toggle-breadcrumb-input-btn"
-          title="Edit path"
-          onClick={() => {
-            setIsEditMode(true);
-          }}
-          data-testid={`${testId}-toggle-input-btn`}
-        ></BorderlessButton>
+          onClick={() => setIsEditMode(true)}
+          className="hue-path-browser__edit-path-btn"
+          data-testid="hue-path-browser__edit-path-btn"
+          data-event={''}
+          title={'Edit Path'}
+          icon={<EditIcon />}
+        />
+        <BorderlessButton
+          onClick={() => navigator.clipboard.writeText(filePath)}
+          className="hue-path-browser__copy-path-btn"
+          data-event={''}
+          title={'Copy Path'}
+          icon={<CopyPathIcon />}
+        />
       </div>
     );
   }

+ 3 - 6
desktop/core/src/desktop/js/reactComponents/PathBrowser/PathBrowser.util.ts

@@ -45,9 +45,7 @@ export const getFileSystemAndPath = (
 };
 
 export const getBreadcrumbs = (fileSystem: string, path: string): BreadcrumbData[] => {
-  const urlFromPath = new URL(`file:///${path}`);
-  const pathParts = urlFromPath.pathname.split('/').filter(Boolean);
-
+  const pathParts = path.split('/').filter(Boolean);
   const rootUrl = fileSystem === 'hdfs' ? '/' : `${fileSystem}://`;
   const rootlabel = fileSystem === 'hdfs' ? '/' : fileSystem;
   const rootNode = {
@@ -57,9 +55,8 @@ export const getBreadcrumbs = (fileSystem: string, path: string): BreadcrumbData
 
   return pathParts.reduce(
     (acc, part, index) => {
-      const decodedPart = decodeURIComponent(part);
-      const currentUrl = `${acc[index].url}${index === 0 ? '' : '/'}${decodedPart}`;
-      acc.push({ url: currentUrl, label: decodedPart });
+      const currentUrl = `${acc[index].url}${index === 0 ? '' : '/'}${part}`;
+      acc.push({ url: currentUrl, label: part });
       return acc;
     },
     [rootNode]