Pārlūkot izejas kodu

[ui-storagebrowser] adds disable button to InputModal component (#3924)

Ram Prasad Agarwal 10 mēneši atpakaļ
vecāks
revīzija
f3b3ec9025

+ 55 - 61
desktop/core/src/desktop/js/apps/storageBrowser/InputModal/InputModal.test.tsx

@@ -22,15 +22,18 @@ import '@testing-library/jest-dom';
 import InputModal from './InputModal';
 
 describe('InputModal', () => {
-  test('renders custom modal title', () => {
+  const mockOnClose = jest.fn();
+  const mockOnSubmit = jest.fn();
+
+  it('should render custom modal title', () => {
     const inputModal = render(
       <InputModal
         title={'Custom title'}
         inputLabel={'Enter File name here'}
         submitText={'Create'}
         showModal={true}
-        onSubmit={jest.fn()}
-        onClose={jest.fn()}
+        onSubmit={mockOnSubmit}
+        onClose={mockOnClose}
         initialValue={''}
         inputType={'text'}
       />
@@ -38,15 +41,15 @@ describe('InputModal', () => {
     expect(inputModal.getByText('Custom title')).toBeVisible();
   });
 
-  test('renders custom input label', () => {
+  it('should render custom input label', () => {
     const inputModal = render(
       <InputModal
         title={'Create New File'}
         inputLabel={'Custom input label'}
         submitText={'Create'}
         showModal={true}
-        onSubmit={jest.fn()}
-        onClose={jest.fn()}
+        onSubmit={mockOnSubmit}
+        onClose={mockOnClose}
         initialValue={''}
         inputType={'text'}
       />
@@ -54,32 +57,7 @@ describe('InputModal', () => {
     expect(inputModal.getByText('Custom input label')).toBeVisible();
   });
 
-  test('calls onSubmit when create button is clicked', async () => {
-    const onCloseMock = jest.fn();
-    const onSubmitMock = jest.fn();
-    const user = userEvent.setup();
-    render(
-      <InputModal
-        title={'Create New File'}
-        inputLabel={'Enter File name here'}
-        submitText={'Create'}
-        showModal={true}
-        onSubmit={onSubmitMock}
-        onClose={onCloseMock}
-        initialValue={''}
-        inputType={'text'}
-      />
-    );
-    const submitButton = screen.getByRole('button', { name: 'Create' });
-
-    expect(onSubmitMock).not.toHaveBeenCalled();
-    await user.click(submitButton);
-    expect(onSubmitMock).toHaveBeenCalled();
-  });
-
-  test('calls onClose after submission when submit button is clicked', async () => {
-    const onCloseMock = jest.fn();
-    const onSubmitMock = jest.fn();
+  it('should call onSubmit when create button is clicked', async () => {
     const user = userEvent.setup();
     render(
       <InputModal
@@ -87,22 +65,20 @@ describe('InputModal', () => {
         inputLabel={'Enter File name here'}
         submitText={'Create'}
         showModal={true}
-        onSubmit={onSubmitMock}
-        onClose={onCloseMock}
+        onSubmit={mockOnSubmit}
+        onClose={mockOnClose}
         initialValue={''}
         inputType={'text'}
       />
     );
     const submitButton = screen.getByRole('button', { name: 'Create' });
 
+    expect(mockOnSubmit).not.toHaveBeenCalled();
     await user.click(submitButton);
-    expect(onSubmitMock).toHaveBeenCalled();
-    expect(onCloseMock).toHaveBeenCalled();
+    expect(mockOnSubmit).toHaveBeenCalled();
   });
 
-  test('calls onClose when close button is clicked', async () => {
-    const onCloseMock = jest.fn();
-    const onSubmitMock = jest.fn();
+  it('should call onClose when close button is clicked', async () => {
     const user = userEvent.setup();
     render(
       <InputModal
@@ -110,28 +86,28 @@ describe('InputModal', () => {
         inputLabel={'Enter File name here'}
         submitText={'Create'}
         showModal={true}
-        onSubmit={onSubmitMock}
-        onClose={onCloseMock}
+        onSubmit={mockOnSubmit}
+        onClose={mockOnClose}
         initialValue={''}
         inputType={'text'}
       />
     );
     const closeButton = screen.getByRole('button', { name: 'Cancel' });
 
-    expect(onCloseMock).not.toHaveBeenCalled();
+    expect(mockOnClose).not.toHaveBeenCalled();
     await user.click(closeButton);
-    expect(onCloseMock).toHaveBeenCalled();
+    expect(mockOnClose).toHaveBeenCalled();
   });
 
-  test('renders modal with input visible', () => {
+  it('should render modal with input visible', () => {
     render(
       <InputModal
         title={'Create New File'}
         inputLabel={'Custom input label'}
         submitText={'Create'}
         showModal={true}
-        onSubmit={jest.fn()}
-        onClose={jest.fn()}
+        onSubmit={mockOnSubmit}
+        onClose={mockOnClose}
         initialValue={''}
         inputType={'text'}
       />
@@ -141,15 +117,15 @@ describe('InputModal', () => {
     expect(input).toBeVisible();
   });
 
-  test('renders modal with number input when input type is number', () => {
+  it('should render modal with number input when input type is number', () => {
     render(
       <InputModal
         title={'Set replication'}
         inputLabel={'Custom input label'}
         submitText={'Submit'}
         showModal={true}
-        onSubmit={jest.fn()}
-        onClose={jest.fn()}
+        onSubmit={mockOnSubmit}
+        onClose={mockOnClose}
         initialValue={2}
         inputType={'number'}
       />
@@ -159,15 +135,15 @@ describe('InputModal', () => {
     expect(input).toBeVisible();
   });
 
-  test('renders modal with empty input value when intial value is empty', () => {
+  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'}
         showModal={true}
-        onSubmit={jest.fn()}
-        onClose={jest.fn()}
+        onSubmit={mockOnSubmit}
+        onClose={mockOnClose}
         initialValue={''}
         inputType={'text'}
       />
@@ -175,15 +151,15 @@ describe('InputModal', () => {
     expect(screen.getByRole('textbox')).toHaveValue('');
   });
 
-  test('renders modal with intial value in input while input type is text', () => {
+  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'}
         showModal={true}
-        onSubmit={jest.fn()}
-        onClose={jest.fn()}
+        onSubmit={mockOnSubmit}
+        onClose={mockOnClose}
         initialValue={'hello'}
         inputType={'text'}
       />
@@ -191,15 +167,15 @@ describe('InputModal', () => {
     expect(screen.getByRole('textbox')).toHaveValue('hello');
   });
 
-  test('renders modal with intial value in input while input type is number', () => {
+  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'}
         showModal={true}
-        onSubmit={jest.fn()}
-        onClose={jest.fn()}
+        onSubmit={mockOnSubmit}
+        onClose={mockOnClose}
         initialValue={2}
         inputType={'number'}
       />
@@ -207,7 +183,7 @@ describe('InputModal', () => {
     expect(screen.getByRole('spinbutton')).toHaveValue(2);
   });
 
-  test('accepts tab focus on input elements placed in the drawer', async () => {
+  it('should accept tab focus on input elements placed in the drawer', async () => {
     const user = userEvent.setup();
     render(
       <InputModal
@@ -215,8 +191,8 @@ describe('InputModal', () => {
         inputLabel={'Custom input label'}
         submitText={'Create'}
         showModal={true}
-        onSubmit={jest.fn()}
-        onClose={jest.fn()}
+        onSubmit={mockOnSubmit}
+        onClose={mockOnClose}
         initialValue={''}
         inputType={'text'}
       />
@@ -239,4 +215,22 @@ describe('InputModal', () => {
     await user.tab();
     expect(cancelButton).toHaveFocus();
   });
+
+  it('should disable the submit button when buttonDisabled is true', () => {
+    render(
+      <InputModal
+        title={'Create New File'}
+        inputLabel={'Custom input label'}
+        submitText={'Create'}
+        showModal={true}
+        onSubmit={mockOnSubmit}
+        onClose={mockOnClose}
+        initialValue={''}
+        inputType={'text'}
+        buttonDisabled={true}
+      />
+    );
+    const submitButton = screen.getByRole('button', { name: 'Create' });
+    expect(submitButton).toBeDisabled();
+  });
 });

+ 11 - 4
desktop/core/src/desktop/js/apps/storageBrowser/InputModal/InputModal.tsx

@@ -31,6 +31,7 @@ interface InputModalProps {
   submitText?: string;
   showModal: boolean;
   title: string;
+  buttonDisabled?: boolean;
 }
 
 const InputModal = ({
@@ -41,12 +42,17 @@ const InputModal = ({
   onSubmit,
   showModal,
   title,
+  buttonDisabled,
   ...i18n
 }: InputModalProps): JSX.Element => {
   const [value, setValue] = useState<string | number>(initialValue);
   const { t } = i18nReact.useTranslation();
   const { cancelText = t('Cancel'), submitText = t('Submit') } = i18n;
 
+  const handleSubmit = () => {
+    onSubmit(value);
+  };
+
   useEffect(() => {
     setValue(initialValue);
   }, [initialValue]);
@@ -57,18 +63,19 @@ const InputModal = ({
       className="hue-input-modal cuix antd"
       okText={submitText}
       onCancel={onClose}
-      onOk={() => {
-        onSubmit(value);
-        onClose();
-      }}
+      onOk={handleSubmit}
       open={showModal}
       title={title}
+      secondaryButtonProps={{ disabled: buttonDisabled }}
+      okButtonProps={{ disabled: buttonDisabled }}
+      cancelButtonProps={{ disabled: buttonDisabled }}
     >
       <div className="hue-input-modal__input-label">{inputLabel}</div>
       <Input
         className="hue-input-modal__input"
         value={value}
         type={inputType}
+        onPressEnter={handleSubmit}
         onChange={e => {
           setValue(e.target.value);
         }}

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

@@ -13,6 +13,7 @@
 // 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.
+
 @use 'mixins';
 
 $action-dropdown-width: 214px;
@@ -23,5 +24,12 @@ $action-dropdown-width: 214px;
 }
 
 .hue-file-upload-modal {
-  height: 200px;
+  .ant-modal-body {
+    cursor: pointer;
+    height: 150px;
+  }
+
+  .ant-modal-footer {
+    display: none;
+  }
 }

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

@@ -24,6 +24,7 @@ describe('CreateAndUploadAction', () => {
   const currentPath = '/some/path';
   const onSuccessfulAction = jest.fn();
   const setLoadingFiles = jest.fn();
+  const mockFilesUpload = jest.fn();
 
   beforeEach(() => {
     render(
@@ -31,6 +32,7 @@ describe('CreateAndUploadAction', () => {
         currentPath={currentPath}
         onSuccessfulAction={onSuccessfulAction}
         setLoadingFiles={setLoadingFiles}
+        onFilesUpload={mockFilesUpload}
       />
     );
   });
@@ -74,7 +76,7 @@ describe('CreateAndUploadAction', () => {
     fireEvent.click(newUploadButton);
 
     // Check if the upload modal is opened
-    expect(screen.getByText('Upload A File')).toBeInTheDocument();
+    expect(screen.getByText('Upload a File')).toBeInTheDocument();
   });
 
   it('should call the correct API for creating a folder', async () => {

+ 16 - 15
desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/CreateAndUploadAction/CreateAndUploadAction.tsx

@@ -59,8 +59,18 @@ const CreateAndUploadAction = ({
 
   const [selectedAction, setSelectedAction] = useState<ActionType>();
 
+  const onModalClose = () => {
+    setSelectedAction(undefined);
+  };
+
+  const onUpload = (files: File[]) => {
+    onModalClose();
+    onFilesUpload(files);
+  };
+
   const onApiSuccess = () => {
     setLoadingFiles(false);
+    onModalClose();
     onSuccessfulAction();
   };
 
@@ -69,7 +79,7 @@ const CreateAndUploadAction = ({
     huePubSub.publish('hue.error', error);
   };
 
-  const { save } = useSaveData(undefined, {
+  const { save, loading } = useSaveData(undefined, {
     onSuccess: onApiSuccess,
     onError: onApiError
   });
@@ -78,15 +88,6 @@ const CreateAndUploadAction = ({
     setSelectedAction(action);
   };
 
-  const onModalClose = () => {
-    setSelectedAction(undefined);
-  };
-
-  const onUpload = (files: File[]) => {
-    onModalClose();
-    onFilesUpload(files);
-  };
-
   const newActionsMenuItems: MenuItemGroupType[] = [
     {
       key: 'create',
@@ -157,6 +158,7 @@ const CreateAndUploadAction = ({
         showModal={selectedAction === ActionType.createFolder}
         onSubmit={handleCreate}
         onClose={onModalClose}
+        buttonDisabled={loading}
       />
       <InputModal
         title={t('Create New File')}
@@ -165,16 +167,15 @@ const CreateAndUploadAction = ({
         showModal={selectedAction === ActionType.createFile}
         onSubmit={handleCreate}
         onClose={onModalClose}
+        buttonDisabled={loading}
       />
       <Modal
         onCancel={onModalClose}
-        className="cuix antd"
+        className="hue-file-upload-modal cuix antd"
         open={selectedAction === ActionType.uploadFile}
-        title={t('Upload A File')}
+        title={t('Upload a File')}
       >
-        <div className="hue-file-upload-modal">
-          <DragAndDrop onDrop={onUpload} />
-        </div>
+        <DragAndDrop onDrop={onUpload} />
       </Modal>
     </>
   );