Browse Source

[ui-storagebrowser] fixes labels and default value in create file (#3988)

Ram Prasad Agarwal 9 months ago
parent
commit
76b7c71fa1

+ 2 - 2
desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/CreateAndUploadAction/CreateAndUploadAction.test.tsx

@@ -55,7 +55,7 @@ describe('CreateAndUploadAction', () => {
     const newFolderButton = screen.getByText('New Folder');
     await act(async () => fireEvent.click(newFolderButton));
 
-    expect(screen.getByText('Create New Folder')).toBeInTheDocument();
+    expect(screen.getByText('Create Folder')).toBeInTheDocument();
   });
 
   it('should open the file creation modal when "New File" is clicked', async () => {
@@ -65,7 +65,7 @@ describe('CreateAndUploadAction', () => {
     const newFileButton = screen.getByText('New File');
     await act(async () => fireEvent.click(newFileButton));
 
-    expect(screen.getByText('Create New File')).toBeInTheDocument();
+    expect(screen.getByText('Create File')).toBeInTheDocument();
   });
 
   it('should open the upload file modal when "New Upload" is clicked', async () => {

+ 14 - 19
desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/CreateAndUploadAction/CreateAndUploadAction.tsx

@@ -32,7 +32,7 @@ import {
 } from '../../../../reactComponents/FileChooser/api';
 import { FileStats } from '../../../../reactComponents/FileChooser/types';
 import useSaveData from '../../../../utils/hooks/useSaveData/useSaveData';
-import InputModal from '../../InputModal/InputModal';
+import InputModal from '../../../../reactComponents/InputModal/InputModal';
 import './CreateAndUploadAction.scss';
 import DragAndDrop from '../../../../reactComponents/DragAndDrop/DragAndDrop';
 
@@ -151,24 +151,19 @@ const CreateAndUploadAction = ({
           <DropDownIcon />
         </PrimaryButton>
       </Dropdown>
-      <InputModal
-        title={t('Create New Folder')}
-        inputLabel={t('Enter New Folder Name')}
-        submitText={t('Create')}
-        showModal={selectedAction === ActionType.createFolder}
-        onSubmit={handleCreate}
-        onClose={onModalClose}
-        buttonDisabled={loading}
-      />
-      <InputModal
-        title={t('Create New File')}
-        inputLabel={t('Enter New File Name')}
-        submitText={t('Create')}
-        showModal={selectedAction === ActionType.createFile}
-        onSubmit={handleCreate}
-        onClose={onModalClose}
-        buttonDisabled={loading}
-      />
+      {(selectedAction === ActionType.createFolder || selectedAction === ActionType.createFile) && (
+        <InputModal
+          showModal={true}
+          title={selectedAction === ActionType.createFolder ? t('Create Folder') : t('Create File')}
+          inputLabel={
+            selectedAction === ActionType.createFolder ? t('Folder name') : t('File name')
+          }
+          submitText={t('Create')}
+          onSubmit={handleCreate}
+          onClose={onModalClose}
+          buttonDisabled={loading}
+        />
+      )}
       <Modal
         onCancel={onModalClose}
         className="hue-file-upload-modal cuix antd"

+ 2 - 2
desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/StorageBrowserActions/DeletionModal/DeletionModal.test.tsx

@@ -65,7 +65,7 @@ describe('DeletionModal Component', () => {
       />
     );
 
-    expect(getByText('Delete file')).toBeInTheDocument();
+    expect(getByText('Confirm Delete')).toBeInTheDocument();
     expect(getByText('Move to Trash')).toBeInTheDocument();
     expect(getByText('Delete Permanently')).toBeInTheDocument();
     expect(getByRole('button', { name: 'Cancel' })).toBeInTheDocument();
@@ -84,7 +84,7 @@ describe('DeletionModal Component', () => {
       />
     );
 
-    expect(getByText('Delete file')).toBeInTheDocument();
+    expect(getByText('Confirm Delete')).toBeInTheDocument();
     expect(queryByText('Move to Trash')).not.toBeInTheDocument();
     expect(getByText('Delete Permanently')).toBeInTheDocument();
     expect(getByRole('button', { name: 'Cancel' })).toBeInTheDocument();

+ 1 - 1
desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/StorageBrowserActions/DeletionModal/DeletionModal.tsx

@@ -81,7 +81,7 @@ const DeletionModal = ({
       onCancel={onClose}
       onOk={() => handleDeletion()}
       open={isOpen}
-      title={t('Delete file')}
+      title={t('Confirm Delete')}
       secondaryButtonText={isTrashEnabled ? t('Delete Permanently') : undefined}
       onSecondary={() => handleDeletion(true)}
       secondaryButtonProps={{ disabled: loading }}

+ 1 - 1
desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/StorageBrowserActions/RenameModal/RenameModal.tsx

@@ -19,7 +19,7 @@ import { StorageDirectoryTableData } from '../../../../../reactComponents/FileCh
 import { i18nReact } from '../../../../../utils/i18nReact';
 import useSaveData from '../../../../../utils/hooks/useSaveData/useSaveData';
 import { RENAME_API_URL } from '../../../../../reactComponents/FileChooser/api';
-import InputModal from '../../../InputModal/InputModal';
+import InputModal from '../../../../../reactComponents/InputModal/InputModal';
 
 interface RenameModalProps {
   isOpen?: boolean;

+ 1 - 1
desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/StorageBrowserActions/ReplicationModal/ReplicationModal.tsx

@@ -19,7 +19,7 @@ import { StorageDirectoryTableData } from '../../../../../reactComponents/FileCh
 import { i18nReact } from '../../../../../utils/i18nReact';
 import useSaveData from '../../../../../utils/hooks/useSaveData/useSaveData';
 import { SET_REPLICATION_API_URL } from '../../../../../reactComponents/FileChooser/api';
-import InputModal from '../../../InputModal/InputModal';
+import InputModal from '../../../../../reactComponents/InputModal/InputModal';
 
 interface ReplicationModalProps {
   isOpen?: boolean;

+ 2 - 2
desktop/core/src/desktop/js/reactComponents/DragAndDrop/DragAndDrop.test.tsx

@@ -29,7 +29,7 @@ describe('DragAndDrop', () => {
   it('should render the initial message when not dragging and children not present', () => {
     const { getByText } = render(<DragAndDrop onDrop={mockOnFilesDrop} />);
 
-    expect(getByText('Drag and Drop files')).toBeInTheDocument();
+    expect(getByText('Browse files or drag and drop files')).toBeInTheDocument();
   });
 
   it('should render children when provided and not dragging', () => {
@@ -49,7 +49,7 @@ describe('DragAndDrop', () => {
       </DragAndDrop>
     );
 
-    expect(queryByText('Drag and Drop files')).not.toBeInTheDocument();
+    expect(queryByText('Browse files or drag and drop files')).not.toBeInTheDocument();
     expect(getByText('Custom Child Element')).toBeInTheDocument();
   });
 

+ 2 - 2
desktop/core/src/desktop/js/reactComponents/DragAndDrop/DragAndDrop.tsx

@@ -41,9 +41,9 @@ const DragAndDrop = ({ children, onDrop }: DragAndDropProps): JSX.Element => {
         {!isDragActive && !children && (
           <div className="drag-drop__message">
             <div className="drag-drop__message__select-file">
-              <ImportIcon /> {t('Browse file')}
+              <ImportIcon /> {t('Select file')}
             </div>
-            <div>{t('Drag and Drop files')}</div>
+            <div>{t('Browse files or drag and drop files')}</div>
           </div>
         )}
         {!isDragActive && children}

+ 0 - 0
desktop/core/src/desktop/js/apps/storageBrowser/InputModal/InputModal.scss → desktop/core/src/desktop/js/reactComponents/InputModal/InputModal.scss


+ 85 - 61
desktop/core/src/desktop/js/apps/storageBrowser/InputModal/InputModal.test.tsx → desktop/core/src/desktop/js/reactComponents/InputModal/InputModal.test.tsx

@@ -28,14 +28,14 @@ describe('InputModal', () => {
   it('should render custom modal title', () => {
     const inputModal = render(
       <InputModal
-        title={'Custom title'}
-        inputLabel={'Enter File name here'}
-        submitText={'Create'}
+        title="Custom title"
+        inputLabel="Enter File name here"
+        submitText="Create"
         showModal={true}
         onSubmit={mockOnSubmit}
         onClose={mockOnClose}
-        initialValue={''}
-        inputType={'text'}
+        initialValue=""
+        inputType="text"
       />
     );
     expect(inputModal.getByText('Custom title')).toBeVisible();
@@ -44,14 +44,14 @@ describe('InputModal', () => {
   it('should render custom input label', () => {
     const inputModal = render(
       <InputModal
-        title={'Create New File'}
-        inputLabel={'Custom input label'}
-        submitText={'Create'}
+        title="Create File"
+        inputLabel="Custom input label"
+        submitText="Create"
         showModal={true}
         onSubmit={mockOnSubmit}
         onClose={mockOnClose}
-        initialValue={''}
-        inputType={'text'}
+        initialValue=""
+        inputType="text"
       />
     );
     expect(inputModal.getByText('Custom input label')).toBeVisible();
@@ -61,19 +61,23 @@ describe('InputModal', () => {
     const user = userEvent.setup();
     render(
       <InputModal
-        title={'Create New File'}
-        inputLabel={'Enter File name here'}
-        submitText={'Create'}
+        title="Create File"
+        inputLabel="Enter File name here"
+        submitText="Create"
         showModal={true}
         onSubmit={mockOnSubmit}
         onClose={mockOnClose}
-        initialValue={''}
-        inputType={'text'}
+        initialValue=""
+        inputType="text"
       />
     );
     const submitButton = screen.getByRole('button', { name: 'Create' });
 
     expect(mockOnSubmit).not.toHaveBeenCalled();
+
+    const inputField = screen.getByRole('textbox');
+    await user.type(inputField, 'test-file.txt');
+
     await user.click(submitButton);
     expect(mockOnSubmit).toHaveBeenCalled();
   });
@@ -82,14 +86,14 @@ describe('InputModal', () => {
     const user = userEvent.setup();
     render(
       <InputModal
-        title={'Create New File'}
-        inputLabel={'Enter File name here'}
-        submitText={'Create'}
+        title="Create File"
+        inputLabel="Enter File name here"
+        submitText="Create"
         showModal={true}
         onSubmit={mockOnSubmit}
         onClose={mockOnClose}
-        initialValue={''}
-        inputType={'text'}
+        initialValue=""
+        inputType="text"
       />
     );
     const closeButton = screen.getByRole('button', { name: 'Cancel' });
@@ -102,14 +106,14 @@ describe('InputModal', () => {
   it('should render modal with input visible', () => {
     render(
       <InputModal
-        title={'Create New File'}
-        inputLabel={'Custom input label'}
-        submitText={'Create'}
+        title="Create File"
+        inputLabel="Custom input label"
+        submitText="Create"
         showModal={true}
         onSubmit={mockOnSubmit}
         onClose={mockOnClose}
-        initialValue={''}
-        inputType={'text'}
+        initialValue=""
+        inputType="text"
       />
     );
     const input = screen.getByRole('textbox');
@@ -120,14 +124,14 @@ describe('InputModal', () => {
   it('should render modal with number input when input type is number', () => {
     render(
       <InputModal
-        title={'Set replication'}
-        inputLabel={'Custom input label'}
-        submitText={'Submit'}
+        title="Set replication"
+        inputLabel="Custom input label"
+        submitText="Submit"
         showModal={true}
         onSubmit={mockOnSubmit}
         onClose={mockOnClose}
         initialValue={2}
-        inputType={'number'}
+        inputType="number"
       />
     );
     const input = screen.getByRole('spinbutton');
@@ -138,14 +142,14 @@ describe('InputModal', () => {
   it('should render modal with empty input value when intial value is empty', () => {
     render(
       <InputModal
-        title={'Create New File'}
-        inputLabel={'Custom input label'}
-        submitText={'Create'}
+        title="Create File"
+        inputLabel="Custom input label"
+        submitText="Create"
         showModal={true}
         onSubmit={mockOnSubmit}
         onClose={mockOnClose}
-        initialValue={''}
-        inputType={'text'}
+        initialValue=""
+        inputType="text"
       />
     );
     expect(screen.getByRole('textbox')).toHaveValue('');
@@ -154,14 +158,14 @@ describe('InputModal', () => {
   it('should render modal with intial value in input while input type is text', () => {
     render(
       <InputModal
-        title={'Create New File'}
-        inputLabel={'Custom input label'}
-        submitText={'Create'}
+        title="Create File"
+        inputLabel="Custom input label"
+        submitText="Create"
         showModal={true}
         onSubmit={mockOnSubmit}
         onClose={mockOnClose}
-        initialValue={'hello'}
-        inputType={'text'}
+        initialValue="hello"
+        inputType="text"
       />
     );
     expect(screen.getByRole('textbox')).toHaveValue('hello');
@@ -170,14 +174,14 @@ describe('InputModal', () => {
   it('should render modal with intial value in input while input type is number', () => {
     render(
       <InputModal
-        title={'Create New File'}
-        inputLabel={'Custom input label'}
-        submitText={'Create'}
+        title="Create File"
+        inputLabel="Custom input label"
+        submitText="Create"
         showModal={true}
         onSubmit={mockOnSubmit}
         onClose={mockOnClose}
         initialValue={2}
-        inputType={'number'}
+        inputType="number"
       />
     );
     expect(screen.getByRole('spinbutton')).toHaveValue(2);
@@ -187,28 +191,24 @@ describe('InputModal', () => {
     const user = userEvent.setup();
     render(
       <InputModal
-        title={'Create New File'}
-        inputLabel={'Custom input label'}
-        submitText={'Create'}
+        title="Create File"
+        inputLabel="Custom input label"
+        submitText="Create"
         showModal={true}
         onSubmit={mockOnSubmit}
         onClose={mockOnClose}
-        initialValue={''}
-        inputType={'text'}
+        initialValue=""
+        inputType="text"
       />
     );
-    const inputModal = screen.getByRole('dialog', { name: 'Create New File' });
-    const closeIconButton = within(inputModal).getByRole('button', { name: 'Close' });
+    const inputModal = screen.getByRole('dialog', { name: 'Create File' });
     const inputTextBox = within(inputModal).getByRole('textbox');
     const submitButton = within(inputModal).getByRole('button', { name: 'Create' });
     const cancelButton = within(inputModal).getByRole('button', { name: 'Cancel' });
 
-    await user.tab();
-    if (!closeIconButton.matches(':focus')) {
-      await user.tab(); // Tab again if the focus is on the sentinel
-    }
-    expect(closeIconButton).toHaveFocus();
-    await user.tab();
+    const inputField = screen.getByRole('textbox');
+    await user.type(inputField, 'test-file.txt');
+
     expect(inputTextBox).toHaveFocus();
     await user.tab();
     expect(submitButton).toHaveFocus();
@@ -219,18 +219,42 @@ describe('InputModal', () => {
   it('should disable the submit button when buttonDisabled is true', () => {
     render(
       <InputModal
-        title={'Create New File'}
-        inputLabel={'Custom input label'}
-        submitText={'Create'}
+        title="Create File"
+        inputLabel="Custom input label"
+        submitText="Create"
         showModal={true}
         onSubmit={mockOnSubmit}
         onClose={mockOnClose}
-        initialValue={''}
-        inputType={'text'}
+        initialValue=""
+        inputType="text"
         buttonDisabled={true}
       />
     );
     const submitButton = screen.getByRole('button', { name: 'Create' });
     expect(submitButton).toBeDisabled();
   });
+
+  it('should disable the submit button when input value is same as initial value', async () => {
+    const user = userEvent.setup();
+    render(
+      <InputModal
+        title="Create File"
+        inputLabel="Custom input label"
+        submitText="Create"
+        showModal={true}
+        onSubmit={mockOnSubmit}
+        onClose={mockOnClose}
+        initialValue="sample_file.txt"
+        inputType="text"
+      />
+    );
+
+    const submitButton = screen.getByRole('button', { name: 'Create' });
+    expect(submitButton).toBeDisabled();
+
+    const inputField = screen.getByRole('textbox');
+    await user.type(inputField, 'test-file.txt');
+
+    expect(submitButton).not.toBeDisabled();
+  });
 });

+ 12 - 7
desktop/core/src/desktop/js/apps/storageBrowser/InputModal/InputModal.tsx → desktop/core/src/desktop/js/reactComponents/InputModal/InputModal.tsx

@@ -13,11 +13,12 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-import React, { useEffect, useState } from 'react';
+
+import React, { useEffect, useRef, useState } from 'react';
 import Modal from 'cuix/dist/components/Modal';
-import { Input } from 'antd';
+import { Input, InputRef } from 'antd';
 
-import { i18nReact } from '../../../utils/i18nReact';
+import { i18nReact } from '../../utils/i18nReact';
 
 import './InputModal.scss';
 
@@ -45,6 +46,8 @@ const InputModal = ({
   buttonDisabled,
   ...i18n
 }: InputModalProps): JSX.Element => {
+  const inputRef = useRef<InputRef>(null);
+
   const [value, setValue] = useState<string | number>(initialValue);
   const { t } = i18nReact.useTranslation();
   const { cancelText = t('Cancel'), submitText = t('Submit') } = i18n;
@@ -54,8 +57,8 @@ const InputModal = ({
   };
 
   useEffect(() => {
-    setValue(initialValue);
-  }, [initialValue]);
+    inputRef?.current?.focus();
+  }, [inputRef.current]);
 
   return (
     <Modal
@@ -67,15 +70,17 @@ const InputModal = ({
       open={showModal}
       title={title}
       secondaryButtonProps={{ disabled: buttonDisabled }}
-      okButtonProps={{ disabled: buttonDisabled }}
+      okButtonProps={{ disabled: buttonDisabled || initialValue === value }}
       cancelButtonProps={{ disabled: buttonDisabled }}
     >
       <div className="hue-input-modal__input-label">{inputLabel}</div>
       <Input
         className="hue-input-modal__input"
-        value={value}
+        defaultValue={value}
         type={inputType}
+        disabled={buttonDisabled}
         onPressEnter={handleSubmit}
+        ref={inputRef}
         onChange={e => {
           setValue(e.target.value);
         }}

+ 1 - 1
desktop/core/src/desktop/templates/global_js_constants.mako

@@ -72,7 +72,7 @@
     oozie_info: { url: '/oozie/list_oozie_info', title: '${_('Oozie')}' },
     jobbrowser: { url: '/jobbrowser/apps', title: '${_('Job Browser')}' },
     filebrowser: { url: '/filebrowser/view=*', title: '${_('File Browser')}' },
-    newfilebrowser: { url: '/filebrowser/new', title: '${_('New File Browser')}' },
+    newfilebrowser: { url: '/filebrowser/new', title: '${_('Storage Browser')}' },
     home: { url: '/home*', title: '${_('Home')}' },
     catalog: { url: '/catalog', title: '${_('Catalog')}' },
     indexer: { url: '/indexer/indexer/', title: '${_('Indexer')}' },