diff --git a/app/assets/javascripts/lib/utils/autosave.js b/app/assets/javascripts/lib/utils/autosave.js new file mode 100644 index 00000000000..023c336db02 --- /dev/null +++ b/app/assets/javascripts/lib/utils/autosave.js @@ -0,0 +1,32 @@ +import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; + +export const clearDraft = autosaveKey => { + try { + window.localStorage.removeItem(`autosave/${autosaveKey}`); + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + } +}; + +export const getDraft = autosaveKey => { + try { + return window.localStorage.getItem(`autosave/${autosaveKey}`); + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + return null; + } +}; + +export const updateDraft = (autosaveKey, text) => { + try { + window.localStorage.setItem(`autosave/${autosaveKey}`, text); + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + } +}; + +export const getDiscussionReplyKey = (noteableType, discussionId) => + ['Note', capitalizeFirstCharacter(noteableType), discussionId, 'Reply'].join('/'); diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue index 92258a25438..57d6b181bd7 100644 --- a/app/assets/javascripts/notes/components/note_form.vue +++ b/app/assets/javascripts/notes/components/note_form.vue @@ -7,6 +7,7 @@ import markdownField from '../../vue_shared/components/markdown/field.vue'; import issuableStateMixin from '../mixins/issuable_state'; import resolvable from '../mixins/resolvable'; import { __ } from '~/locale'; +import { getDraft, updateDraft } from '~/lib/utils/autosave'; export default { name: 'NoteForm', @@ -65,10 +66,21 @@ export default { required: false, default: '', }, + autosaveKey: { + type: String, + required: false, + default: '', + }, }, data() { + let updatedNoteBody = this.noteBody; + + if (!updatedNoteBody && this.autosaveKey) { + updatedNoteBody = getDraft(this.autosaveKey) || ''; + } + return { - updatedNoteBody: this.noteBody, + updatedNoteBody, conflictWhileEditing: false, isSubmitting: false, isResolving: this.resolveDiscussion, @@ -175,6 +187,12 @@ export default { // Sends information about confirm message and if the textarea has changed this.$emit('cancelForm', shouldConfirm, this.noteBody !== this.updatedNoteBody); }, + onInput() { + if (this.autosaveKey) { + const { autosaveKey, updatedNoteBody: text } = this; + updateDraft(autosaveKey, text); + } + }, }, }; @@ -218,6 +236,7 @@ export default { @keydown.ctrl.enter="handleKeySubmit()" @keydown.up="editMyLastNote()" @keydown.esc="cancelHandler(true)" + @input="onInput" >
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index fc51998935d..0fabbfb06b5 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -4,6 +4,7 @@ import { mapActions, mapGetters } from 'vuex'; import { GlTooltipDirective } from '@gitlab/ui'; import { truncateSha } from '~/lib/utils/text_utility'; import { s__, __, sprintf } from '~/locale'; +import { clearDraft, getDiscussionReplyKey } from '~/lib/utils/autosave'; import systemNote from '~/vue_shared/components/notes/system_note.vue'; import icon from '~/vue_shared/components/icon.vue'; import diffLineNoteFormMixin from 'ee_else_ce/notes/mixins/diff_line_note_form'; @@ -21,7 +22,6 @@ import noteForm from './note_form.vue'; import diffWithNote from './diff_with_note.vue'; import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue'; import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue'; -import autosave from '../mixins/autosave'; import noteable from '../mixins/noteable'; import resolvable from '../mixins/resolvable'; import discussionNavigation from '../mixins/discussion_navigation'; @@ -54,7 +54,7 @@ export default { directives: { GlTooltip: GlTooltipDirective, }, - mixins: [autosave, noteable, resolvable, discussionNavigation, diffLineNoteFormMixin], + mixins: [noteable, resolvable, discussionNavigation, diffLineNoteFormMixin], props: { discussion: { type: Object, @@ -106,7 +106,10 @@ export default { 'showJumpToNextDiscussion', ]), author() { - return this.initialDiscussion.author; + return this.firstNote.author; + }, + autosaveKey() { + return getDiscussionReplyKey(this.firstNote.noteable_type, this.discussion.id); }, canReply() { return this.getNoteableData.current_user.can_create_note; @@ -117,7 +120,7 @@ export default { hasReplies() { return this.discussion.notes.length > 1; }, - initialDiscussion() { + firstNote() { return this.discussion.notes.slice(0, 1)[0]; }, replies() { @@ -242,18 +245,6 @@ export default { return !this.discussionResolved && this.discussion.resolve_with_issue_path; }, }, - watch: { - isReplying() { - if (this.isReplying) { - this.$nextTick(() => { - // Pass an extra key to separate reply and note edit forms - this.initAutoSave({ ...this.initialDiscussion, ...this.discussion }, ['Reply']); - }); - } else { - this.disposeAutoSave(); - } - }, - }, created() { eventHub.$on('startReplying', this.onStartReplying); }, @@ -312,7 +303,7 @@ export default { } this.isReplying = false; - this.resetAutoSave(); + clearDraft(this.autosaveKey); }, saveReply(noteText, form, callback) { const postData = { @@ -338,7 +329,7 @@ export default { this.isReplying = false; this.saveNote(replyData) .then(() => { - this.resetAutoSave(); + clearDraft(this.autosaveKey); callback(); }) .catch(err => { @@ -390,8 +381,8 @@ Please check your network connection and try again.`;