Skip to content

Commit

Permalink
[Workspace]Disable confirm button during collaborators operation (ope…
Browse files Browse the repository at this point in the history
…nsearch-project#8604)

* Keep confirm modal and disable confirm button during operation

Signed-off-by: Lin Wang <[email protected]>

* Changeset file for PR opensearch-project#8604 created/updated

---------

Signed-off-by: Lin Wang <[email protected]>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
  • Loading branch information
wanglam and opensearch-changeset-bot[bot] authored Oct 18, 2024
1 parent a41f0c5 commit 896ac00
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 8 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/8604.yml
Original file line number Diff line number Diff line change
@@ -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))
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>((resolve) => {
setTimeout(resolve, 1000);
});

const { getByText, getByTestId, queryByText } = render(
<Provider>
<>
<WorkspaceCollaboratorTable
{...mockProps}
handleSubmitPermissionSettings={handleSubmitPermissionSettingsMock}
permissionSettings={permissionSettings}
/>
<div data-test-subj="confirm-modal-container" />
</>
</Provider>
);

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 = [
{
Expand Down Expand Up @@ -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<void>((resolve) => {
setTimeout(resolve, 1000);
});

const { getByText, getByTestId, getByRole } = render(
<Provider>
<>
<WorkspaceCollaboratorTable
{...mockProps}
handleSubmitPermissionSettings={handleSubmitPermissionSettingsMock}
permissionSettings={permissionSettings}
/>
<div data-test-subj="confirm-modal-container" />
</>
</Provider>
);
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();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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<void>;
onCancel: () => void;
}
>) => {
const [isProcessing, setIsProcessing] = useState(false);
const isMounted = useMountedState();
return (
<EuiConfirmModal
{...restProps}
onCancel={onCancel}
onConfirm={async () => {
setIsProcessing(true);
try {
await onConfirm();
} finally {
if (isMounted()) {
setIsProcessing(false);
}
}
}}
confirmButtonDisabled={isProcessing}
isLoading={isProcessing}
/>
);
};

const convertPermissionSettingToWorkspaceCollaborator = (
permissionSetting: WorkspacePermissionSetting
) => ({
Expand Down Expand Up @@ -204,7 +238,7 @@ export const WorkspaceCollaboratorTable = ({
onConfirm,
selections,
}: {
onConfirm: () => void;
onConfirm: () => Promise<void>;
selections: PermissionSettingWithAccessLevelAndDisplayedType[];
}) => {
const adminOfSelection = selections.filter(
Expand All @@ -213,7 +247,7 @@ export const WorkspaceCollaboratorTable = ({
const shouldShowWarning =
adminCollaboratorsNum === adminOfSelection && adminCollaboratorsNum !== 0;
const modal = overlays.openModal(
<EuiConfirmModal
<BaseConfirmModal
data-test-subj="delete-confirm-modal"
title={i18n.translate('workspace.detail.collaborator.actions.delete', {
defaultMessage: 'Delete collaborator',
Expand All @@ -226,7 +260,7 @@ export const WorkspaceCollaboratorTable = ({
<EuiText color={shouldShowWarning ? 'danger' : 'default'}>
<p>{shouldShowWarning ? deletionModalWarning : deletionModalConfirm}</p>
</EuiText>
</EuiConfirmModal>
</BaseConfirmModal>
);
return modal;
};
Expand All @@ -236,7 +270,7 @@ export const WorkspaceCollaboratorTable = ({
selections,
type,
}: {
onConfirm: () => void;
onConfirm: () => Promise<void>;
selections: PermissionSettingWithAccessLevelAndDisplayedType[];
type: WorkspaceCollaboratorAccessLevel;
}) => {
Expand All @@ -249,7 +283,7 @@ export const WorkspaceCollaboratorTable = ({
}

const modal = overlays.openModal(
<EuiConfirmModal
<BaseConfirmModal
data-test-subj="change-access-confirm-modal"
title={i18n.translate('workspace.detail.collaborator.table.change.access.level', {
defaultMessage: 'Change access level',
Expand All @@ -276,7 +310,7 @@ export const WorkspaceCollaboratorTable = ({
})}
</p>
</EuiText>
</EuiConfirmModal>
</BaseConfirmModal>
);

return modal;
Expand Down Expand Up @@ -466,15 +500,15 @@ const Actions = ({
onConfirm,
selections,
}: {
onConfirm: () => void;
onConfirm: () => Promise<void>;
selections: PermissionSettingWithAccessLevelAndDisplayedType[];
}) => { close: () => void };
openChangeAccessLevelModal?: ({
onConfirm,
selections,
type,
}: {
onConfirm: () => void;
onConfirm: () => Promise<void>;
selections: PermissionSettingWithAccessLevelAndDisplayedType[];
type: WorkspaceCollaboratorAccessLevel;
}) => { close: () => void };
Expand Down

0 comments on commit 896ac00

Please sign in to comment.