Commit 3de8d8b0 authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch 'pipeline-editor-confirm-dialog' into 'master'

Show confirmation dialog when exiting pipeline editor

See merge request gitlab-org/gitlab!52458
parents 94e118a1 b2fc9d46
<script>
export default {
props: {
hasUnsavedChanges: {
type: Boolean,
required: true,
},
},
created() {
window.addEventListener('beforeunload', this.confirmChanges);
},
destroyed() {
window.removeEventListener('beforeunload', this.confirmChanges);
},
methods: {
confirmChanges(e = {}) {
if (this.hasUnsavedChanges) {
e.preventDefault();
// eslint-disable-next-line no-param-reassign
e.returnValue = ''; // Chrome requires returnValue to be set
}
},
},
render: () => null,
};
</script>
...@@ -8,6 +8,7 @@ import httpStatusCodes from '~/lib/utils/http_status'; ...@@ -8,6 +8,7 @@ import httpStatusCodes from '~/lib/utils/http_status';
import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue'; import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
import CiLint from './components/lint/ci_lint.vue'; import CiLint from './components/lint/ci_lint.vue';
import CommitForm from './components/commit/commit_form.vue'; import CommitForm from './components/commit/commit_form.vue';
import ConfirmUnsavedChangesDialog from './components/ui/confirm_unsaved_changes_dialog.vue';
import EditorTab from './components/ui/editor_tab.vue'; import EditorTab from './components/ui/editor_tab.vue';
import TextEditor from './components/text_editor.vue'; import TextEditor from './components/text_editor.vue';
import ValidationSegment from './components/info/validation_segment.vue'; import ValidationSegment from './components/info/validation_segment.vue';
...@@ -30,6 +31,7 @@ export default { ...@@ -30,6 +31,7 @@ export default {
components: { components: {
CiLint, CiLint,
CommitForm, CommitForm,
ConfirmUnsavedChangesDialog,
EditorTab, EditorTab,
GlAlert, GlAlert,
GlLoadingIcon, GlLoadingIcon,
...@@ -66,6 +68,7 @@ export default { ...@@ -66,6 +68,7 @@ export default {
ciConfigData: {}, ciConfigData: {},
content: '', content: '',
contentModel: '', contentModel: '',
lastCommittedContent: '',
lastCommitSha: this.commitSha, lastCommitSha: this.commitSha,
isSaving: false, isSaving: false,
...@@ -88,7 +91,9 @@ export default { ...@@ -88,7 +91,9 @@ export default {
}; };
}, },
update(data) { update(data) {
return data?.blobContent?.rawData; const content = data?.blobContent?.rawData;
this.lastCommittedContent = content;
return content;
}, },
result({ data }) { result({ data }) {
this.contentModel = data?.blobContent?.rawData ?? ''; this.contentModel = data?.blobContent?.rawData ?? '';
...@@ -122,6 +127,9 @@ export default { ...@@ -122,6 +127,9 @@ export default {
}, },
}, },
computed: { computed: {
hasUnsavedChanges() {
return this.lastCommittedContent !== this.contentModel;
},
isBlobContentLoading() { isBlobContentLoading() {
return this.$apollo.queries.content.loading; return this.$apollo.queries.content.loading;
}, },
...@@ -264,6 +272,7 @@ export default { ...@@ -264,6 +272,7 @@ export default {
// Update latest commit // Update latest commit
this.lastCommitSha = commit.sha; this.lastCommitSha = commit.sha;
this.lastCommittedContent = this.contentModel;
} }
} catch (error) { } catch (error) {
this.reportFailure(COMMIT_FAILURE, [error?.message]); this.reportFailure(COMMIT_FAILURE, [error?.message]);
...@@ -342,5 +351,6 @@ export default { ...@@ -342,5 +351,6 @@ export default {
@submit="onCommitSubmit" @submit="onCommitSubmit"
/> />
</div> </div>
<confirm-unsaved-changes-dialog :has-unsaved-changes="hasUnsavedChanges" />
</div> </div>
</template> </template>
---
title: Show confirmation dialog when exiting pipeline editor
merge_request: 52458
author:
type: added
import { shallowMount } from '@vue/test-utils';
import ConfirmDialog from '~/pipeline_editor/components/ui/confirm_unsaved_changes_dialog.vue';
describe('pipeline_editor/components/ui/confirm_unsaved_changes_dialog', () => {
let beforeUnloadEvent;
let setDialogContent;
let wrapper;
const createComponent = (propsData = {}) => {
wrapper = shallowMount(ConfirmDialog, {
propsData,
});
};
beforeEach(() => {
beforeUnloadEvent = new Event('beforeunload');
jest.spyOn(beforeUnloadEvent, 'preventDefault');
setDialogContent = jest.spyOn(beforeUnloadEvent, 'returnValue', 'set');
});
afterEach(() => {
beforeUnloadEvent.preventDefault.mockRestore();
setDialogContent.mockRestore();
wrapper.destroy();
});
it('shows confirmation dialog when there are unsaved changes', () => {
createComponent({ hasUnsavedChanges: true });
window.dispatchEvent(beforeUnloadEvent);
expect(beforeUnloadEvent.preventDefault).toHaveBeenCalled();
expect(setDialogContent).toHaveBeenCalledWith('');
});
it('does not show confirmation dialog when there are no unsaved changes', () => {
createComponent({ hasUnsavedChanges: false });
window.dispatchEvent(beforeUnloadEvent);
expect(beforeUnloadEvent.preventDefault).not.toHaveBeenCalled();
expect(setDialogContent).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