diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-09 09:41:26 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-09 09:41:26 +0000 |
commit | 684921fd9ea9ae521ed736b155c0d01599a94e84 (patch) | |
tree | fb587bb318f8c52ed5d314c2c96c8aeed656c5bd | |
parent | 9922b38ff03500d311dd7de771961154f50ea8f4 (diff) | |
download | gitlab-ce-684921fd9ea9ae521ed736b155c0d01599a94e84.tar.gz |
Add latest changes from gitlab-org/gitlab@15-11-stable-ee
7 files changed, 94 insertions, 5 deletions
diff --git a/app/assets/javascripts/vue_shared/components/markdown/eventhub.js b/app/assets/javascripts/vue_shared/components/markdown/eventhub.js new file mode 100644 index 00000000000..e31806ad199 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/markdown/eventhub.js @@ -0,0 +1,3 @@ +import createEventHub from '~/helpers/event_hub_factory'; + +export default createEventHub(); diff --git a/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue b/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue index 52d8aab30d5..6ffebc51ef8 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue @@ -3,8 +3,13 @@ import Autosize from 'autosize'; import axios from '~/lib/utils/axios_utils'; import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; import { updateDraft, clearDraft, getDraft } from '~/lib/utils/autosave'; -import { EDITING_MODE_MARKDOWN_FIELD, EDITING_MODE_CONTENT_EDITOR } from '../../constants'; +import { + EDITING_MODE_MARKDOWN_FIELD, + EDITING_MODE_CONTENT_EDITOR, + CLEAR_AUTOSAVE_ENTRY_EVENT, +} from '../../constants'; import MarkdownField from './field.vue'; +import eventHub from './eventhub'; export default { components: { @@ -124,6 +129,11 @@ export default { getValue: () => this.getValue(), setValue: (val) => this.setValue(val), }); + + eventHub.$on(CLEAR_AUTOSAVE_ENTRY_EVENT, this.clearDraft); + }, + beforeDestroy() { + eventHub.$off(CLEAR_AUTOSAVE_ENTRY_EVENT, this.clearDraft); }, methods: { getValue() { @@ -183,6 +193,10 @@ export default { if (this.markdown) updateDraft(this.autosaveKey, this.markdown); else clearDraft(this.autosaveKey); }, + clearDraft(key) { + if (!this.autosaveKey || key !== this.autosaveKey) return; + clearDraft(this.autosaveKey); + }, togglePreview(value) { if (this.editingMode === EDITING_MODE_MARKDOWN_FIELD) { this.$refs.markdownField.previewMarkdown = value; diff --git a/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js b/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js index 0f2a46f78f7..b0e609e2433 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js +++ b/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js @@ -1,6 +1,8 @@ import Vue from 'vue'; import { queryToObject, objectToQuery } from '~/lib/utils/url_utility'; +import { CLEAR_AUTOSAVE_ENTRY_EVENT } from '../../constants'; import MarkdownEditor from './markdown_editor.vue'; +import eventHub from './eventhub'; const MR_SOURCE_BRANCH = 'merge_request[source_branch]'; const MR_TARGET_BRANCH = 'merge_request[target_branch]'; @@ -35,6 +37,19 @@ function getSearchTerm(newIssuePath) { return newIssuePath === pathname ? '' : format(search); } +function mountAutosaveClearOnSubmit(autosaveKey) { + const resetAutosaveButtons = document.querySelectorAll('.js-reset-autosave'); + if (resetAutosaveButtons.length === 0) { + return; + } + + for (const resetAutosaveButton of resetAutosaveButtons) { + resetAutosaveButton.addEventListener('click', () => { + eventHub.$emit(CLEAR_AUTOSAVE_ENTRY_EVENT, autosaveKey); + }); + } +} + export function mountMarkdownEditor() { const el = document.querySelector('.js-markdown-editor'); @@ -65,6 +80,7 @@ export function mountMarkdownEditor() { }; const setFacade = (props) => Object.assign(facade, props); + const autosaveKey = `autosave/${document.location.pathname}/${searchTerm}/description`; // eslint-disable-next-line no-new new Vue({ @@ -85,7 +101,7 @@ export function mountMarkdownEditor() { class: formFieldClasses, 'data-qa-selector': qaSelector, }, - autosaveKey: `autosave/${document.location.pathname}/${searchTerm}/description`, + autosaveKey, enableAutocomplete: true, autocompleteDataSources: gl.GfmAutoComplete?.dataSources, supportsQuickActions: true, @@ -95,5 +111,7 @@ export function mountMarkdownEditor() { }, }); + mountAutosaveClearOnSubmit(autosaveKey); + return facade; } diff --git a/app/assets/javascripts/vue_shared/constants.js b/app/assets/javascripts/vue_shared/constants.js index 29a31503840..3896e963a53 100644 --- a/app/assets/javascripts/vue_shared/constants.js +++ b/app/assets/javascripts/vue_shared/constants.js @@ -96,3 +96,4 @@ export const confidentialityInfoText = (workspaceType, issuableType) => export const EDITING_MODE_MARKDOWN_FIELD = 'markdownField'; export const EDITING_MODE_CONTENT_EDITOR = 'contentEditor'; +export const CLEAR_AUTOSAVE_ENTRY_EVENT = 'markdown_clear_autosave_entry'; diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index 5ba92676f89..58d0a39578a 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -62,9 +62,9 @@ = sanitize(html_escape(_('Please review the %{linkStart}contribution guidelines%{linkEnd} for this project.')) % { linkStart: contribution_guidelines_start, linkEnd: contribution_guidelines_end }) - if issuable.new_record? - = form.submit "#{_('Create')} #{issuable.class.model_name.human.downcase}", pajamas_button: true, class: 'gl-mr-2 js-issuable-submit-button', data: { qa_selector: 'issuable_create_button', track_action: 'click_button', track_label: 'submit_mr', track_value: 0 } + = form.submit "#{_('Create')} #{issuable.class.model_name.human.downcase}", pajamas_button: true, class: 'gl-mr-2 js-issuable-submit-button js-reset-autosave', data: { qa_selector: 'issuable_create_button', track_action: 'click_button', track_label: 'submit_mr', track_value: 0 } - else - = form.submit _('Save changes'), pajamas_button: true, class: 'gl-mr-2 js-issuable-submit-button', data: { track_action: 'click_button', track_label: 'submit_mr', track_value: 0 } + = form.submit _('Save changes'), pajamas_button: true, class: 'gl-mr-2 js-issuable-submit-button js-reset-autosave', data: { track_action: 'click_button', track_label: 'submit_mr', track_value: 0 } - if issuable.new_record? = link_to _('Cancel'), polymorphic_path([@project, issuable.class]), class: 'btn gl-button btn-default js-reset-autosave' diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb index 4e3968230b4..42c66f0c40d 100644 --- a/spec/features/issues/user_creates_issue_spec.rb +++ b/spec/features/issues/user_creates_issue_spec.rb @@ -233,6 +233,7 @@ RSpec.describe "User creates issue", feature_category: :team_planning do wait_for_requests expect(page).to have_field('Title', with: '') + expect(page).to have_field('Description', with: '') fill_in 'issue_title', with: 'bug 345' fill_in 'issue_description', with: 'bug description' @@ -240,6 +241,21 @@ RSpec.describe "User creates issue", feature_category: :team_planning do click_button 'Create issue' end end + + it 'clears local storage after cancelling a new issue creation', :js do + 2.times do + visit new_project_issue_path(project) + wait_for_requests + + expect(page).to have_field('Title', with: '') + expect(page).to have_field('Description', with: '') + + fill_in 'issue_title', with: 'bug 345' + fill_in 'issue_description', with: 'bug description' + + click_link 'Cancel' + end + end end context 'when signed in as reporter', :js do diff --git a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js index 69dedd6b68a..fe95ad56f8c 100644 --- a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js +++ b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js @@ -3,7 +3,12 @@ import Autosize from 'autosize'; import MockAdapter from 'axios-mock-adapter'; import { nextTick } from 'vue'; import { mountExtended } from 'helpers/vue_test_utils_helper'; -import { EDITING_MODE_MARKDOWN_FIELD, EDITING_MODE_CONTENT_EDITOR } from '~/vue_shared/constants'; +import { + EDITING_MODE_MARKDOWN_FIELD, + EDITING_MODE_CONTENT_EDITOR, + CLEAR_AUTOSAVE_ENTRY_EVENT, +} from '~/vue_shared/constants'; +import markdownEditorEventHub from '~/vue_shared/components/markdown/eventhub'; import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue'; import ContentEditor from '~/content_editor/components/content_editor.vue'; import BubbleMenu from '~/content_editor/components/bubble_menus/bubble_menu.vue'; @@ -229,6 +234,38 @@ describe('vue_shared/component/markdown/markdown_editor', () => { expect(localStorage.setItem).not.toHaveBeenCalled(); }); + + describe('clear local storage event handler', () => { + it('does not clear the local storage if the autosave key is not defined', async () => { + buildWrapper(); + + await waitForPromises(); + + markdownEditorEventHub.$emit(CLEAR_AUTOSAVE_ENTRY_EVENT, 'issue/1234'); + + expect(localStorage.removeItem).not.toHaveBeenCalled(); + }); + + it('does not clear the local storage if the event autosave key does not match', async () => { + buildWrapper({ propsData: { autosaveKey: 'issue/1234' } }); + + await waitForPromises(); + + markdownEditorEventHub.$emit(CLEAR_AUTOSAVE_ENTRY_EVENT, 'issue/1235'); + + expect(localStorage.removeItem).not.toHaveBeenCalled(); + }); + + it('clears the local storage if the event autosave key matches', async () => { + buildWrapper({ propsData: { autosaveKey: 'issue/1234' } }); + + await waitForPromises(); + + markdownEditorEventHub.$emit(CLEAR_AUTOSAVE_ENTRY_EVENT, 'issue/1234'); + + expect(localStorage.removeItem).toHaveBeenCalledWith('autosave/issue/1234'); + }); + }); }); it('renders markdown field textarea', () => { |