Skip to content
88 changes: 88 additions & 0 deletions e2e/tests/plugin_editor_drawer.unsaved-changes.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { pluginConfigsPom } from '@e2e/pom/plugin_configs';
import { test } from '@e2e/utils/test';
import { uiFillMonacoEditor, uiGetMonacoEditor } from '@e2e/utils/ui';
import { expect } from '@playwright/test';

const openResponseRewriteDrawer = async (page: Parameters<typeof test>[1]['page']) => {
await pluginConfigsPom.toAdd(page);
await pluginConfigsPom.isAddPage(page);

await page.getByRole('button', { name: 'Select Plugins' }).click();

const selectPluginsDialog = page.getByRole('dialog', { name: 'Select Plugins' });
await selectPluginsDialog.getByPlaceholder('Search').fill('response-rewrite');
await selectPluginsDialog
.getByTestId('plugin-response-rewrite')
.getByRole('button', { name: 'Add' })
.click();

const drawer = page.getByRole('dialog', { name: 'Add Plugin' });
await expect(drawer).toBeVisible();
return drawer;
};

test('should show unsaved changes dialog when closing plugin editor with unsaved changes', async ({
page,
}) => {
const drawer = await openResponseRewriteDrawer(page);

await test.step('make changes in the editor', async () => {
const editor = await uiGetMonacoEditor(page, drawer);
await uiFillMonacoEditor(page, editor, '{"body": "test"}');
});

await test.step('closing with unsaved changes shows confirmation dialog', async () => {
await drawer.getByRole('button', { name: 'Close' }).click();

const confirmModal = page.getByRole('dialog', { name: 'Unsaved Changes' });
await expect(confirmModal).toBeVisible();
await expect(
confirmModal.getByText('You have unsaved changes. Are you sure you want to close?')
).toBeVisible();
});

await test.step('cancel keeps drawer open with changes preserved', async () => {
const confirmModal = page.getByRole('dialog', { name: 'Unsaved Changes' });
await confirmModal.getByRole('button', { name: 'Cancel' }).click();

await expect(confirmModal).toBeHidden();
await expect(drawer).toBeVisible();
});

await test.step('discard changes closes the drawer', async () => {
await drawer.getByRole('button', { name: 'Close' }).click();

const confirmModal = page.getByRole('dialog', { name: 'Unsaved Changes' });
await confirmModal.getByRole('button', { name: 'Discard Changes' }).click();

await expect(confirmModal).toBeHidden();
await expect(drawer).toBeHidden();
});
});

test('should close plugin editor silently when there are no unsaved changes', async ({ page }) => {
const drawer = await openResponseRewriteDrawer(page);

await test.step('closing without changes does not show confirmation dialog', async () => {
await drawer.getByRole('button', { name: 'Close' }).click();

await expect(page.getByRole('dialog', { name: 'Unsaved Changes' })).toBeHidden();
await expect(drawer).toBeHidden();
});
});
24 changes: 20 additions & 4 deletions src/components/form-slice/FormItemPlugins/PluginEditorDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Drawer, Group, Title } from '@mantine/core';
import { Drawer, Group, Text, Title } from '@mantine/core';
import { modals } from '@mantine/modals';
import { isEmpty, isNil } from 'rambdax';
import { useEffect } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
Expand Down Expand Up @@ -47,8 +48,21 @@ export const PluginEditorDrawer = (props: PluginEditorDrawerProps) => {
defaultValues: { config: toConfigStr(config) },
});
const handleClose = () => {
onClose();
methods.reset();
if (mode !== 'view' && methods.getValues('config') !== toConfigStr(config)) {
modals.openConfirmModal({
centered: true,
title: t('info.unsaved.title'),
children: <Text size="sm">{t('info.unsaved.content')}</Text>,
labels: { confirm: t('info.unsaved.confirm'), cancel: t('form.btn.cancel') },
onConfirm: () => {
onClose();
methods.reset();
},
});
} else {
onClose();
methods.reset();
}
};

useEffect(() => {
Expand All @@ -64,6 +78,7 @@ export const PluginEditorDrawer = (props: PluginEditorDrawerProps) => {
closeOnEscape={false}
opened={opened}
onClose={handleClose}
closeButtonProps={{ 'aria-label': 'Close' }}
styles={{ body: { paddingTop: '18px' } }}
{...(mode === 'add' && { title: t('form.plugins.addPlugin') })}
{...(mode === 'edit' && { title: t('form.plugins.editPlugin') })}
Expand All @@ -90,7 +105,8 @@ export const PluginEditorDrawer = (props: PluginEditorDrawerProps) => {
variant="light"
onClick={methods.handleSubmit(({ config }) => {
onSave({ name, config: JSON.parse(config) });
handleClose();
onClose();
methods.reset();
})}
>
{mode === 'add' && t('form.btn.add')}
Expand Down
5 changes: 5 additions & 0 deletions src/locales/de/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@
"edit": {
"success": "{{name}} erfolgreich bearbeitet",
"title": "{{name}} bearbeiten"
},
"unsaved": {
"confirm": "Änderungen verwerfen",
"content": "Sie haben nicht gespeicherte Änderungen. Möchten Sie wirklich schließen?",
"title": "Nicht gespeicherte Änderungen"
}
},
"mark": {
Expand Down
5 changes: 5 additions & 0 deletions src/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@
"edit": {
"success": "Edit {{name}} Successfully",
"title": "Edit {{name}}"
},
"unsaved": {
"confirm": "Discard Changes",
"content": "You have unsaved changes. Are you sure you want to close?",
"title": "Unsaved Changes"
}
},
"mark": {
Expand Down
5 changes: 5 additions & 0 deletions src/locales/es/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@
"edit": {
"success": "Editado {{name}} con éxito",
"title": "Editar {{name}}"
},
"unsaved": {
"confirm": "Descartar cambios",
"content": "Tiene cambios sin guardar. ¿Está seguro de que desea cerrar?",
"title": "Cambios sin guardar"
}
},
"mark": {
Expand Down
5 changes: 5 additions & 0 deletions src/locales/tr/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@
"edit": {
"success": "{{name}} başarıyla güncellendi",
"title": "{{name}} Düzenle"
},
"unsaved": {
"confirm": "Değişiklikleri at",
"content": "Kaydedilmemiş değişiklikleriniz var. Kapatmak istediğinizden emin misiniz?",
"title": "Kaydedilmemiş Değişiklikler"
}
},
"mark": {
Expand Down
5 changes: 5 additions & 0 deletions src/locales/zh/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@
"edit": {
"success": "编辑 {{name}} 成功",
"title": "编辑 {{name}}"
},
"unsaved": {
"confirm": "放弃更改",
"content": "您有未保存的更改,确定要关闭吗?",
"title": "未保存的更改"
}
},
"mark": {
Expand Down
Loading