From 9f393d329b6d64c3e66a1f2db61c1d2686b0c191 Mon Sep 17 00:00:00 2001 From: Paulina Shakirova Date: Thu, 17 Oct 2024 12:39:42 +0200 Subject: [PATCH] fix: updating dashboard - initial save button state is "disabled" (#196137) ## Summary This PR fixes [[Dashboard] User can click on update dashboard even without changing anything](https://github.com/elastic/kibana/issues/187800) issue. ## Change - When the flyout is open, the initial state of the button is `disabled`. - When there is a change made, the `disabled` state is removed. ![Screenshot 2024-10-14 at 15 21 28](https://github.com/user-attachments/assets/7f4a6234-959b-4779-bb4b-3f8bc221b3f2) ![Screenshot 2024-10-14 at 15 21 55](https://github.com/user-attachments/assets/24349b06-d6ee-4749-8981-d192eda8fd9d) (cherry picked from commit 0ead257ff4912218775a70484ac5754b4b3baa31) --- .../src/components/editor_flyout_content.tsx | 18 +++++++- .../inspector_flyout_content.test.tsx | 43 +++++++++++++------ 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/packages/content-management/content_editor/src/components/editor_flyout_content.tsx b/packages/content-management/content_editor/src/components/editor_flyout_content.tsx index 8db5e59b1fc27..cf9bead5a4e30 100644 --- a/packages/content-management/content_editor/src/components/editor_flyout_content.tsx +++ b/packages/content-management/content_editor/src/components/editor_flyout_content.tsx @@ -79,6 +79,22 @@ export const ContentEditorFlyoutContent: FC = ({ const i18nTexts = useMemo(() => getI18nTexts({ entityName }), [entityName]); const form = useMetadataForm({ item, customValidators }); + const hasNoChanges = () => { + const itemTags = item.tags.map((obj) => obj.id).sort(); + const formTags = form.tags.value.slice().sort(); + + const compareTags = (arr1: string[], arr2: string[]) => { + if (arr1.length !== arr2.length) return false; + return arr1.every((tag: string, index) => tag === arr2[index]); + }; + + return ( + item.title === form.title.value && + item.description === form.description.value && + compareTags(itemTags, formTags) + ); + }; + const onClickSave = useCallback(async () => { if (form.isValid && onSave && !form.getIsChangingValue()) { const id = item.id; @@ -177,7 +193,7 @@ export const ContentEditorFlyoutContent: FC = ({ onClick={onClickSave} data-test-subj="saveButton" fill - disabled={isSubmitted && !form.isValid} + disabled={(isSubmitted && !form.isValid) || hasNoChanges()} isLoading={isSubmitting} > {i18nTexts.saveButtonLabel} diff --git a/packages/content-management/content_editor/src/components/inspector_flyout_content.test.tsx b/packages/content-management/content_editor/src/components/inspector_flyout_content.test.tsx index b21c325ca9ed5..44ac09d8d666e 100644 --- a/packages/content-management/content_editor/src/components/inspector_flyout_content.test.tsx +++ b/packages/content-management/content_editor/src/components/inspector_flyout_content.test.tsx @@ -104,32 +104,37 @@ describe('', () => { expect(find('saveButton').text()).toBe('Update foo'); }); - test('should send back the updated item to the onSave() handler', async () => { + test('should save form only if something changes', async () => { const onSave = jest.fn(); await act(async () => { testBed = await setup({ onSave, isReadonly: false }); }); - const { - find, - component, - form: { setInputValue }, - } = testBed!; - - await waitForValidationResults(); + const { find, component } = testBed!; await act(async () => { find('saveButton').simulate('click'); }); - expect(onSave).toHaveBeenCalledWith({ - id: '123', - title: 'Foo', - description: 'Some description', - tags: ['id-1', 'id-2'], + component.update(); + + expect(onSave).not.toHaveBeenCalled(); + }); + + test('should send back the updated item to the onSave() handler', async () => { + const onSave = jest.fn(); + + await act(async () => { + testBed = await setup({ onSave, isReadonly: false }); }); + const { + find, + component, + form: { setInputValue }, + } = testBed!; + await act(async () => { setInputValue('metadataForm.nameInput', 'newTitle'); setInputValue('metadataForm.descriptionInput', 'newDescription'); @@ -196,7 +201,17 @@ describe('', () => { testBed = await setup({ onSave, isReadonly: false, services: { notifyError } }); }); - const { find, component } = testBed!; + const { + find, + component, + form: { setInputValue }, + } = testBed!; + + await act(async () => { + setInputValue('metadataForm.nameInput', 'changingTitleToUnblockDisabledButtonState'); + }); + + await waitForValidationResults(); component.update();