From 896ac00e55c3a119eb921d7a4a995fc646fc42d6 Mon Sep 17 00:00:00 2001 From: Lin Wang Date: Fri, 18 Oct 2024 20:48:58 +0800 Subject: [PATCH] [Workspace]Disable confirm button during collaborators operation (#8604) * Keep confirm modal and disable confirm button during operation Signed-off-by: Lin Wang * Changeset file for PR #8604 created/updated --------- Signed-off-by: Lin Wang Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/8604.yml | 2 + .../workspace_collaborator_table.test.tsx | 106 ++++++++++++++++++ .../workspace_collaborator_table.tsx | 50 +++++++-- 3 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 changelogs/fragments/8604.yml diff --git a/changelogs/fragments/8604.yml b/changelogs/fragments/8604.yml new file mode 100644 index 000000000000..0b186eaa5ef1 --- /dev/null +++ b/changelogs/fragments/8604.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace]Keep confirm modal and disable confirm button during collaborators operation ([#8604](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8604)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.test.tsx index 051bb5fa9037..bb891d4d16fc 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.test.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.test.tsx @@ -132,6 +132,60 @@ describe('WorkspaceCollaboratorTable', () => { expect(mockOverlays.openModal).toHaveBeenCalled(); }); + it('should disable delete confirm button when submitting', async () => { + const permissionSettings = [ + { + id: 0, + modes: ['library_write', 'write'], + type: 'user', + userId: 'admin', + }, + ]; + const handleSubmitPermissionSettingsMock = () => + new Promise((resolve) => { + setTimeout(resolve, 1000); + }); + + const { getByText, getByTestId, queryByText } = render( + + <> + +
+ + + ); + + mockOverlays.openModal.mockReturnValue({ + onClose: Promise.resolve(), + close: async () => { + ReactDOM.unmountComponentAtNode(getByTestId('confirm-modal-container')); + }, + }); + const action = getByTestId('workspace-detail-collaborator-table-actions-box'); + fireEvent.click(action); + const deleteCollaborator = getByText('Delete collaborator'); + fireEvent.click(deleteCollaborator); + + mockOverlays.openModal.mock.calls[0][0](getByTestId('confirm-modal-container')); + await waitFor(() => { + expect(getByText('Confirm')).toBeInTheDocument(); + }); + jest.useFakeTimers(); + fireEvent.click(getByText('Confirm')); + await waitFor(() => { + expect(getByText('Confirm').closest('button')).toBeDisabled(); + }); + jest.runAllTimers(); + jest.useRealTimers(); + await waitFor(() => { + expect(queryByText('Confirm')).toBe(null); + }); + }); + it('should openModal when clicking one selection delete', () => { const permissionSettings = [ { @@ -252,4 +306,56 @@ describe('WorkspaceCollaboratorTable', () => { jest.runAllTimers(); jest.useRealTimers(); }); + + it('should disable change access level confirm button when submitting', async () => { + const permissionSettings = [ + { + id: 0, + modes: ['library_write', 'write'], + type: 'user', + userId: 'admin', + }, + ]; + const handleSubmitPermissionSettingsMock = () => + new Promise((resolve) => { + setTimeout(resolve, 1000); + }); + + const { getByText, getByTestId, getByRole } = render( + + <> + +
+ + + ); + mockOverlays.openModal.mockReturnValue({ + onClose: Promise.resolve(), + close: async () => { + ReactDOM.unmountComponentAtNode(getByTestId('confirm-modal-container')); + }, + }); + const action = getByTestId('workspace-detail-collaborator-table-actions-box'); + fireEvent.click(action); + fireEvent.click(getByText('Change access level')); + await waitFor(() => { + fireEvent.click(within(getByRole('dialog')).getByText('Read only')); + }); + + mockOverlays.openModal.mock.calls[0][0](getByTestId('confirm-modal-container')); + await waitFor(() => { + expect(getByText('Confirm')).toBeInTheDocument(); + }); + jest.useFakeTimers(); + fireEvent.click(getByText('Confirm')); + await waitFor(() => { + expect(getByText('Confirm').closest('button')).toBeDisabled(); + }); + jest.runAllTimers(); + jest.useRealTimers(); + }); }); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.tsx index 4642554c4c19..d0b00739e922 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_collaborator_table.tsx @@ -19,8 +19,10 @@ import { EuiText, EuiFlexGroup, EuiFlexItem, + EuiConfirmModalProps, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; +import { useMountedState } from 'react-use'; import { WorkspacePermissionSetting } from './types'; import { WorkspacePermissionItemType } from './constants'; import { getPermissionModeId, isWorkspacePermissionSetting } from './utils'; @@ -81,6 +83,38 @@ const deletionModalConfirm = i18n.translate('workspace.detail.collaborator.modal defaultMessage: 'Delete collaborator? The collaborators will not have access to the workspace.', }); +const BaseConfirmModal = ({ + onCancel, + onConfirm, + ...restProps +}: React.PropsWithChildren< + EuiConfirmModalProps & { + onConfirm: () => Promise; + onCancel: () => void; + } +>) => { + const [isProcessing, setIsProcessing] = useState(false); + const isMounted = useMountedState(); + return ( + { + setIsProcessing(true); + try { + await onConfirm(); + } finally { + if (isMounted()) { + setIsProcessing(false); + } + } + }} + confirmButtonDisabled={isProcessing} + isLoading={isProcessing} + /> + ); +}; + const convertPermissionSettingToWorkspaceCollaborator = ( permissionSetting: WorkspacePermissionSetting ) => ({ @@ -204,7 +238,7 @@ export const WorkspaceCollaboratorTable = ({ onConfirm, selections, }: { - onConfirm: () => void; + onConfirm: () => Promise; selections: PermissionSettingWithAccessLevelAndDisplayedType[]; }) => { const adminOfSelection = selections.filter( @@ -213,7 +247,7 @@ export const WorkspaceCollaboratorTable = ({ const shouldShowWarning = adminCollaboratorsNum === adminOfSelection && adminCollaboratorsNum !== 0; const modal = overlays.openModal( -

{shouldShowWarning ? deletionModalWarning : deletionModalConfirm}

-
+ ); return modal; }; @@ -236,7 +270,7 @@ export const WorkspaceCollaboratorTable = ({ selections, type, }: { - onConfirm: () => void; + onConfirm: () => Promise; selections: PermissionSettingWithAccessLevelAndDisplayedType[]; type: WorkspaceCollaboratorAccessLevel; }) => { @@ -249,7 +283,7 @@ export const WorkspaceCollaboratorTable = ({ } const modal = overlays.openModal( - - + ); return modal; @@ -466,7 +500,7 @@ const Actions = ({ onConfirm, selections, }: { - onConfirm: () => void; + onConfirm: () => Promise; selections: PermissionSettingWithAccessLevelAndDisplayedType[]; }) => { close: () => void }; openChangeAccessLevelModal?: ({ @@ -474,7 +508,7 @@ const Actions = ({ selections, type, }: { - onConfirm: () => void; + onConfirm: () => Promise; selections: PermissionSettingWithAccessLevelAndDisplayedType[]; type: WorkspaceCollaboratorAccessLevel; }) => { close: () => void };