Skip to content

Commit

Permalink
Keep confirm modal and disable confirm button during operation
Browse files Browse the repository at this point in the history
Signed-off-by: Lin Wang <[email protected]>
  • Loading branch information
wanglam committed Oct 16, 2024
1 parent 47ae28b commit d4b1038
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
*/

import React from 'react';
import { fireEvent, render } from '@testing-library/react';
import { fireEvent, render, waitFor, within } from '@testing-library/react';
import ReactDOM from 'react-dom';

import { WorkspaceCollaboratorTable, getDisplayedType } from './workspace_collaborator_table';
import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public';
Expand All @@ -28,14 +29,9 @@ const displayedCollaboratorTypes = [
},
];

const mockOverlays = {
openModal: jest.fn(),
};
const mockOverlays = mockCoreStart.overlays;

const { Provider } = createOpenSearchDashboardsReactContext({
...mockCoreStart,
overlays: mockOverlays,
});
const { Provider } = createOpenSearchDashboardsReactContext(mockCoreStart);

describe('getDisplayedTypes', () => {
it('should return undefined if not match any collaborator type', () => {
Expand Down Expand Up @@ -64,6 +60,10 @@ describe('getDisplayedTypes', () => {
});

describe('WorkspaceCollaboratorTable', () => {
beforeEach(() => {
mockOverlays.openModal.mockClear();
});

const mockProps = {
displayedCollaboratorTypes,
permissionSettings: [
Expand Down Expand Up @@ -133,6 +133,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 @@ -188,7 +242,7 @@ describe('WorkspaceCollaboratorTable', () => {
expect(mockOverlays.openModal).toHaveBeenCalled();
});

it('should openModal when clicking action tools when multi selection', () => {
it('should openModal when clicking action tools when multi selection', async () => {
const permissionSettings = [
{
id: 0,
Expand All @@ -204,7 +258,7 @@ describe('WorkspaceCollaboratorTable', () => {
},
];

const { getByText, getByTestId } = render(
const { getByText, getByTestId, getByRole } = render(
<Provider>
<WorkspaceCollaboratorTable {...mockProps} permissionSettings={permissionSettings} />
</Provider>
Expand All @@ -215,6 +269,61 @@ describe('WorkspaceCollaboratorTable', () => {
fireEvent.click(actions);
const changeAccessLevel = getByText('Change access level');
fireEvent.click(changeAccessLevel);
await waitFor(() => {
fireEvent.click(within(getByRole('dialog')).getByText('Admin'));
});
expect(mockOverlays.openModal).toHaveBeenCalled();
});

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 @@ -72,6 +74,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 @@ -193,7 +227,7 @@ export const WorkspaceCollaboratorTable = ({
onConfirm,
selections,
}: {
onConfirm: () => void;
onConfirm: () => Promise<void>;
selections: PermissionSettingWithAccessLevelAndDisplayedType[];
}) => {
const adminOfSelection = selections.filter(
Expand All @@ -202,7 +236,7 @@ export const WorkspaceCollaboratorTable = ({
const shouldShowWarning =
adminCollarboratorsNum === adminOfSelection && adminCollarboratorsNum !== 0;
const modal = overlays.openModal(
<EuiConfirmModal
<BaseConfirmModal
title={i18n.translate('workspace.detail.collaborator.actions.delete', {
defaultMessage: 'Delete collaborator',
})}
Expand All @@ -214,7 +248,7 @@ export const WorkspaceCollaboratorTable = ({
<EuiText color={shouldShowWarning ? 'danger' : 'default'}>
<p>{shouldShowWarning ? deletionModalWarning : deletionModalConfirm}</p>
</EuiText>
</EuiConfirmModal>
</BaseConfirmModal>
);
return modal;
};
Expand All @@ -226,12 +260,12 @@ export const WorkspaceCollaboratorTable = ({

const onClick = () => {
const modal = openDeleteConfirmModal({
onConfirm: () => {
onConfirm: async () => {
let newSettings = permissionSettings;
selection.forEach(({ id }) => {
newSettings = newSettings.filter((_item) => _item.id !== id);
});
handleSubmitPermissionSettings(newSettings as WorkspacePermissionSetting[]);
await handleSubmitPermissionSettings(newSettings as WorkspacePermissionSetting[]);
setSelection([]);
modal.close();
},
Expand Down Expand Up @@ -367,7 +401,7 @@ const Actions = ({
onConfirm,
selections,
}: {
onConfirm: () => void;
onConfirm: () => Promise<void>;
selections: PermissionSettingWithAccessLevelAndDisplayedType[];
}) => { close: () => void };
}) => {
Expand All @@ -382,12 +416,12 @@ const Actions = ({
setIsPopoverOpen(false);
if (selection) {
const modal = overlays.openModal(
<EuiConfirmModal
<BaseConfirmModal
title={i18n.translate('workspace.detail.collaborator.table.change.access.level', {
defaultMessage: 'Change access level',
})}
onCancel={() => modal.close()}
onConfirm={() => {
onConfirm={async () => {
let newSettings = permissionSettings;
selection.forEach(({ id }) => {
newSettings = newSettings.map((item) =>
Expand All @@ -399,7 +433,7 @@ const Actions = ({
: item
);
});
handleSubmitPermissionSettings(newSettings as WorkspacePermissionSetting[]);
await handleSubmitPermissionSettings(newSettings as WorkspacePermissionSetting[]);
modal.close();
}}
cancelButtonText="Cancel"
Expand All @@ -418,7 +452,7 @@ const Actions = ({
})}
</p>
</EuiText>
</EuiConfirmModal>
</BaseConfirmModal>
);
}
},
Expand All @@ -443,12 +477,12 @@ const Actions = ({
setIsPopoverOpen(false);
if (selection && openDeleteConfirmModal) {
const modal = openDeleteConfirmModal({
onConfirm: () => {
onConfirm: async () => {
let newSettings = permissionSettings;
selection.forEach(({ id }) => {
newSettings = newSettings.filter((_item) => _item.id !== id);
});
handleSubmitPermissionSettings(newSettings as WorkspacePermissionSetting[]);
await handleSubmitPermissionSettings(newSettings as WorkspacePermissionSetting[]);
modal.close();
},
selections: selection,
Expand Down

0 comments on commit d4b1038

Please sign in to comment.