Commit d58e8168 authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera

Merge branch '216865-confirm-leave-site' into 'master'

Display confirm modal before leaving Static Site Editor

Closes #216865

See merge request gitlab-org/gitlab!33103
parents d150fcb2 47541ff5
......@@ -2,12 +2,14 @@
import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_content_editor.vue';
import PublishToolbar from './publish_toolbar.vue';
import EditHeader from './edit_header.vue';
import UnsavedChangesConfirmDialog from './unsaved_changes_confirm_dialog.vue';
export default {
components: {
RichContentEditor,
PublishToolbar,
EditHeader,
UnsavedChangesConfirmDialog,
},
props: {
title: {
......@@ -50,6 +52,7 @@ export default {
<div class="d-flex flex-grow-1 flex-column h-100">
<edit-header class="py-2" :title="title" />
<rich-content-editor v-model="editableContent" class="mb-9 h-100" />
<unsaved-changes-confirm-dialog :modified="modified" />
<publish-toolbar
class="gl-fixed gl-left-0 gl-bottom-0 gl-w-full"
:return-url="returnUrl"
......
<script>
export default {
props: {
modified: {
type: Boolean,
required: false,
default: false,
},
},
created() {
window.addEventListener('beforeunload', this.requestConfirmation);
},
destroyed() {
window.removeEventListener('beforeunload', this.requestConfirmation);
},
methods: {
requestConfirmation(e) {
if (this.modified) {
e.preventDefault();
// eslint-disable-next-line no-param-reassign
e.returnValue = '';
}
},
},
render: () => null,
};
</script>
---
title: Display confirmation modal when user exits SSE and there are unsaved changes
merge_request: 33103
author:
type: added
......@@ -5,6 +5,7 @@ import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_
import EditArea from '~/static_site_editor/components/edit_area.vue';
import PublishToolbar from '~/static_site_editor/components/publish_toolbar.vue';
import EditHeader from '~/static_site_editor/components/edit_header.vue';
import UnsavedChangesConfirmDialog from '~/static_site_editor/components/unsaved_changes_confirm_dialog.vue';
import { sourceContentTitle as title, sourceContent as content, returnUrl } from '../mock_data';
......@@ -28,6 +29,7 @@ describe('~/static_site_editor/components/edit_area.vue', () => {
const findEditHeader = () => wrapper.find(EditHeader);
const findRichContentEditor = () => wrapper.find(RichContentEditor);
const findPublishToolbar = () => wrapper.find(PublishToolbar);
const findUnsavedChangesConfirmDialog = () => wrapper.find(UnsavedChangesConfirmDialog);
beforeEach(() => {
buildWrapper();
......@@ -49,9 +51,16 @@ describe('~/static_site_editor/components/edit_area.vue', () => {
it('renders publish toolbar', () => {
expect(findPublishToolbar().exists()).toBe(true);
expect(findPublishToolbar().props('returnUrl')).toBe(returnUrl);
expect(findPublishToolbar().props('savingChanges')).toBe(savingChanges);
expect(findPublishToolbar().props('saveable')).toBe(false);
expect(findPublishToolbar().props()).toMatchObject({
returnUrl,
savingChanges,
saveable: false,
});
});
it('renders unsaved changes confirm dialog', () => {
expect(findUnsavedChangesConfirmDialog().exists()).toBe(true);
expect(findUnsavedChangesConfirmDialog().props('modified')).toBe(false);
});
describe('when content changes', () => {
......@@ -61,10 +70,14 @@ describe('~/static_site_editor/components/edit_area.vue', () => {
return wrapper.vm.$nextTick();
});
it('sets publish toolbar as saveable when content changes', () => {
it('sets publish toolbar as saveable', () => {
expect(findPublishToolbar().props('saveable')).toBe(true);
});
it('sets unsaved changes confirm dialog as modified', () => {
expect(findUnsavedChangesConfirmDialog().props('modified')).toBe(true);
});
it('sets publish toolbar as not saveable when content changes are rollback', () => {
findRichContentEditor().vm.$emit('input', content);
......
import { shallowMount } from '@vue/test-utils';
import UnsavedChangesConfirmDialog from '~/static_site_editor/components/unsaved_changes_confirm_dialog.vue';
describe('static_site_editor/components/unsaved_changes_confirm_dialog', () => {
let wrapper;
let event;
let returnValueSetter;
const buildWrapper = (propsData = {}) => {
wrapper = shallowMount(UnsavedChangesConfirmDialog, {
propsData,
});
};
beforeEach(() => {
event = new Event('beforeunload');
jest.spyOn(event, 'preventDefault');
returnValueSetter = jest.spyOn(event, 'returnValue', 'set');
});
afterEach(() => {
event.preventDefault.mockRestore();
returnValueSetter.mockRestore();
wrapper.destroy();
});
it('displays confirmation dialog when modified = true', () => {
buildWrapper({ modified: true });
window.dispatchEvent(event);
expect(event.preventDefault).toHaveBeenCalled();
expect(returnValueSetter).toHaveBeenCalledWith('');
});
it('does not display confirmation dialog when modified = false', () => {
buildWrapper();
window.dispatchEvent(event);
expect(event.preventDefault).not.toHaveBeenCalled();
expect(returnValueSetter).not.toHaveBeenCalled();
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment