Skip to content

Commit

Permalink
fix(metadata-sidebar): UnsavedChangesModal changes (#3691)
Browse files Browse the repository at this point in the history
* fix(metadata-sidebar): Rename prop for unsaved changes callback

* feat(metadata-editor): bump '@box/metadata-editor'

* fix(metadata-sidebar): fix test suites after modal redesign

* fix(metadata-sidebar): Add test for switching templates

* fix(metadata-sidebar): Add missing prop

* fix(metadata-sidebar): Fix failing test

* fix(metadata-sidebar): Fix updating selected templates in dropdown

* Fix(metadata-sidebar): Temporarily comment out failing test

* fix(metadata-sidebar): Move dropdown button disable logic to useEffect

* fix(metadata-sidebar): Re-add failing test

* fix(metadata-sidebar): Remove redundant dependency

* fix(metadata-sidebar): Bump metadata-editor

* fix(metadata-sidebar): Add scope to template comparison

* Fix(metadata-sidebar): Address suggestions

* fix(metadata-sidebar): Bump metadata-editor

* fix(metadata-sidebar) Address Changes

* fix(metadata-editor): Fix typo

---------

Co-authored-by: Jakub Kida <jkida@box.com>
  • Loading branch information
JakubKida and Jakub Kida authored Oct 7, 2024
1 parent 665aedf commit 305d3af
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 27 deletions.
14 changes: 10 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@
"last 2 Edge versions",
"last 2 iOS versions"
],
"development": ["last 1 Chrome versions", "last 1 Firefox versions", "last 1 Safari versions"]
"development": [
"last 1 Chrome versions",
"last 1 Firefox versions",
"last 1 Safari versions"
]
},
"husky": {
"hooks": {
Expand Down Expand Up @@ -128,7 +132,7 @@
"@box/cldr-data": "^34.2.0",
"@box/frontend": "^10.0.0",
"@box/languages": "^1.0.0",
"@box/metadata-editor": "^0.54.0",
"@box/metadata-editor": "^0.61.1",
"@box/react-virtualized": "9.22.3-rc-box.9",
"@cfaester/enzyme-adapter-react-18": "^0.8.0",
"@chromatic-com/storybook": "^1.6.1",
Expand Down Expand Up @@ -306,7 +310,7 @@
"@box/blueprint-web-assets": "^4.21.0",
"@box/box-ai-content-answers": "^0.50.5",
"@box/cldr-data": ">=34.2.0",
"@box/metadata-editor": "^0.54.0",
"@box/metadata-editor": "^0.61.1",
"@box/react-virtualized": "9.22.3-rc-box.9",
"@hapi/address": "^2.1.4",
"axios": "^0.25.0",
Expand Down Expand Up @@ -366,6 +370,8 @@
}
},
"msw": {
"workerDirectory": [".storybook/public"]
"workerDirectory": [
".storybook/public"
]
}
}
12 changes: 8 additions & 4 deletions src/elements/content-sidebar/MetadataInstanceEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface MetadataInstanceEditorProps {
template: MetadataTemplateInstance;
onSubmit: (values: FormValues, operations: JSONPatchOperations) => Promise<void>;
setIsUnsavedChangesModalOpen: (isUnsavedChangesModalOpen: boolean) => void;
onUnsavedChangesModalCancel: () => void;
onDiscardUnsavedChanges: () => void;
}

const MetadataInstanceEditor: React.FC<MetadataInstanceEditorProps> = ({
Expand All @@ -28,15 +28,19 @@ const MetadataInstanceEditor: React.FC<MetadataInstanceEditorProps> = ({
setIsUnsavedChangesModalOpen,
template,
onCancel,
onUnsavedChangesModalCancel,
onDiscardUnsavedChanges,
}) => {
const handleCancel = () => {
onCancel();
};

return (
<AutofillContextProvider isAiSuggestionsFeatureEnabled={isBoxAiSuggestionsEnabled}>
<AutofillContextProvider
fetchSuggestions={() => Promise.resolve([])}
isAiSuggestionsFeatureEnabled={isBoxAiSuggestionsEnabled}
>
<MetadataInstanceForm
areAiSuggestionsAvailable={true}
isAiSuggestionsFeatureEnabled={isBoxAiSuggestionsEnabled}
isDeleteButtonDisabled={isDeleteButtonDisabled}
isUnsavedChangesModalOpen={isUnsavedChangesModalOpen}
Expand All @@ -45,7 +49,7 @@ const MetadataInstanceEditor: React.FC<MetadataInstanceEditorProps> = ({
onSubmit={onSubmit}
setIsUnsavedChangesModalOpen={setIsUnsavedChangesModalOpen}
onDelete={onDelete}
onUnsavedChangesModalCancel={onUnsavedChangesModalCancel}
onDiscardUnsavedChanges={onDiscardUnsavedChanges}
/>
</AutofillContextProvider>
);
Expand Down
25 changes: 17 additions & 8 deletions src/elements/content-sidebar/MetadataSidebarRedesign.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,37 +93,46 @@ function MetadataSidebarRedesign({
const [pendingTemplateToEdit, setPendingTemplateToEdit] = React.useState<MetadataTemplateInstance | null>(null);

React.useEffect(() => {
setSelectedTemplates(templateInstances);
}, [templateInstances, templateInstances.length]);
// disable only pre-existing template instances from dropdown if not editing or editing pre-exiting one
const isEditingTemplateAlreadyExisting =
editingTemplate &&
templateInstances.some(
t => t.templateKey === editingTemplate.templateKey && t.scope === editingTemplate.scope,
);

if (!editingTemplate || isEditingTemplateAlreadyExisting) {
setSelectedTemplates(templateInstances);
} else {
setSelectedTemplates([...templateInstances, editingTemplate]);
}
}, [editingTemplate, templateInstances, templateInstances.length]);

const handleTemplateSelect = (selectedTemplate: MetadataTemplate) => {
if (editingTemplate) {
setPendingTemplateToEdit(convertTemplateToTemplateInstance(file, selectedTemplate));
setIsUnsavedChangesModalOpen(true);
} else {
setSelectedTemplates([...selectedTemplates, selectedTemplate]);
setEditingTemplate(convertTemplateToTemplateInstance(file, selectedTemplate));
setIsDeleteButtonDisabled(true);
}
};

const handleCancel = () => {
setEditingTemplate(null);
setSelectedTemplates(templateInstances);
};

const handleCancelUnsavedChanges = () => {
const handleDiscardUnsavedChanges = () => {
// check if user tried to edit another template before unsaved changes modal
if (pendingTemplateToEdit) {
setEditingTemplate(pendingTemplateToEdit);
setSelectedTemplates([...templateInstances, pendingTemplateToEdit]);
setIsDeleteButtonDisabled(true);

setPendingTemplateToEdit(null);
setIsUnsavedChangesModalOpen(false);
} else {
handleCancel();
}

setIsUnsavedChangesModalOpen(false);
};

const handleDeleteInstance = async (metadataInstance: MetadataTemplateInstance) => {
Expand Down Expand Up @@ -190,7 +199,7 @@ function MetadataSidebarRedesign({
isDeleteButtonDisabled={isDeleteButtonDisabled}
isUnsavedChangesModalOpen={isUnsavedChangesModalOpen}
onCancel={handleCancel}
onUnsavedChangesModalCancel={handleCancelUnsavedChanges}
onDiscardUnsavedChanges={handleDiscardUnsavedChanges}
onSubmit={handleSubmit}
onDelete={handleDeleteInstance}
template={editingTemplate}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { screen, render } from '../../../test-utils/testing-library';
import MetadataInstanceEditor, { MetadataInstanceEditorProps } from '../MetadataInstanceEditor';

const mockOnCancel = jest.fn();
const mockOnUnsavedChangesModalCancel = jest.fn();
const mockOnDiscardUnsavedChanges = jest.fn();
const mockSetIsUnsavedChangesModalOpen = jest.fn();

describe('MetadataInstanceEditor', () => {
Expand Down Expand Up @@ -57,7 +57,7 @@ describe('MetadataInstanceEditor', () => {
onDelete: jest.fn(),
onSubmit: jest.fn(),
setIsUnsavedChangesModalOpen: mockSetIsUnsavedChangesModalOpen,
onUnsavedChangesModalCancel: mockOnUnsavedChangesModalCancel,
onDiscardUnsavedChanges: mockOnDiscardUnsavedChanges,
};

test('should render MetadataInstanceForm with correct props', () => {
Expand Down Expand Up @@ -108,7 +108,7 @@ describe('MetadataInstanceEditor', () => {
expect(mockOnCancel).toHaveBeenCalled();
});

test('Should call onUnsavedChangesModalCancel instead onCancel when canceling through UnsavedChangesModal', async () => {
test('Should call onDiscardUnsavedChanges instead onCancel when canceling through UnsavedChangesModal', async () => {
const props: MetadataInstanceEditorProps = {
...defaultProps,
template: mockCustomMetadataTemplateWithField,
Expand All @@ -127,10 +127,10 @@ describe('MetadataInstanceEditor', () => {
const unsavedChangesModal = await findByText('Unsaved Changes');

expect(unsavedChangesModal).toBeInTheDocument();
const unsavedChangesModalCancelButton = await findByRole('button', { name: 'Cancel' });
const unsavedChangesModalDiscardButton = await findByRole('button', { name: 'Discard Changes' });

await userEvent.click(unsavedChangesModalCancelButton);
await userEvent.click(unsavedChangesModalDiscardButton);

expect(mockOnUnsavedChangesModalCancel).toHaveBeenCalled();
expect(mockOnDiscardUnsavedChanges).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,60 @@ export const MetadataInstanceEditorAddTemplateAgainAfterCancel: StoryObj<typeof
expect(templateMetadataOptionEnabled).not.toHaveAttribute('aria-disabled');
},
};

export const SwitchEditingTemplateInstances: StoryObj<typeof MetadataSidebarRedesign> = {
args: {
fileId: '416047501580',
metadataSidebarProps: defaultMetadataSidebarProps,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

// open and edit a new template
const addTemplateButton = await canvas.findByRole('button', { name: 'Add template' }, { timeout: 5000 });

await userEvent.click(addTemplateButton);

const templateMetadataOption = canvas.getByRole('option', { name: 'My Template' });

await userEvent.click(templateMetadataOption);

const input = await canvas.findByRole('textbox');

await userEvent.type(input, 'Lorem ipsum dolor.');

// open another template while editing the first one (with discarding changes)
await userEvent.click(addTemplateButton);

const templateMetadataOptionA = canvas.getByRole('option', { name: 'My Template' });
const templateMetadataOptionB = canvas.getByRole('option', { name: 'Virus Scan' });

expect(templateMetadataOptionA).toHaveAttribute('aria-disabled');
expect(templateMetadataOptionB).not.toHaveAttribute('aria-disabled');

await userEvent.click(templateMetadataOptionB);

const unsavedChangesModal = await screen.findByRole(
'heading',
{ level: 2, name: 'Unsaved Changes' },
{ timeout: 5000 },
);
expect(unsavedChangesModal).toBeInTheDocument();

const unsavedChangesModalDiscardButton = await screen.findByRole('button', { name: 'Discard Changes' });

await userEvent.click(unsavedChangesModalDiscardButton);

const newTemplateHeader = await canvas.findByRole('heading', { name: 'Virus Scan' });
expect(newTemplateHeader).toBeInTheDocument();

// check if template buttons disabled correctly after switching editors
await userEvent.click(addTemplateButton);

const templateMetadataOptionAAfterSwitch = canvas.getByRole('option', { name: 'My Template' });
const templateMetadataOptionBAfterSwitch = canvas.getByRole('option', { name: 'Virus Scan' });

expect(templateMetadataOptionAAfterSwitch).not.toHaveAttribute('aria-disabled');
expect(templateMetadataOptionBAfterSwitch).toHaveAttribute('aria-disabled');
},
};
2 changes: 1 addition & 1 deletion src/test-utils/testing-library.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { AutofillContextProvider } from '@box/metadata-editor';
jest.unmock('react-intl');

const Wrapper = ({ children }) => (
<AutofillContextProvider isAiSuggestionsFeatureEnabled={false}>
<AutofillContextProvider isAiSuggestionsFeatureEnabled={false} fetchSuggestions={() => Promise.resolve([])}>
<TooltipProvider>
<IntlProvider locale="en">{children}</IntlProvider>
</TooltipProvider>
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1569,10 +1569,10 @@
resolved "https://registry.yarnpkg.com/@box/languages/-/languages-1.1.2.tgz#cd4266b3da62da18560d881e10b429653186be29"
integrity sha512-d64TGosx+KRmrLZj4CIyLp42LUiEbgBJ8n8cviMQwTJmfU0g+UwZqLjmQZR1j+Q9D64yV4xHzY9K1t5nInWWeQ==

"@box/metadata-editor@^0.54.0":
version "0.54.0"
resolved "https://registry.yarnpkg.com/@box/metadata-editor/-/metadata-editor-0.54.0.tgz#699266252fca2b776eb9df814b158d988e719f01"
integrity sha512-Og7w6DsoDoXpuujDcnrlTWiTmVONuuWDwDitcrXflNkxsx9ZVvgTFwKD9SVj2yW5HjMM5X46X1qHYDe40qDXkg==
"@box/metadata-editor@^0.61.1":
version "0.61.2"
resolved "https://registry.yarnpkg.com/@box/metadata-editor/-/metadata-editor-0.61.2.tgz#b8e66f3e822531ae57463cfdd8be89dd9cabdb21"
integrity sha512-Ot+cGU+benO0ChRrKWahvJmHMgxKTp4nuNr+VypnQtTt63hGCn1F8TbZ2aQNRtPikhoGCAiOwYspG8fRKJ/Fmw==

"@box/react-virtualized@9.22.3-rc-box.9":
version "9.22.3-rc-box.9"
Expand Down

0 comments on commit 305d3af

Please sign in to comment.