Commit c23c141e authored by Rajat Jain's avatar Rajat Jain Committed by Kushal Pandya

Autosave description in epics

When editing an epic, the progress was previously lost due to
lack of localstorage syncing code. This commit adds support for
localstorage sync.
parent 224916f8
......@@ -159,9 +159,23 @@ export default {
return !!this.state.updatedAt;
},
issueChanged() {
const descriptionChanged = this.initialDescriptionText !== this.store.formState.description;
const titleChanged = this.initialTitleText !== this.store.formState.title;
return descriptionChanged || titleChanged;
const {
store: {
formState: { description, title },
},
initialDescriptionText,
initialTitleText,
} = this;
if (initialDescriptionText || description) {
return initialDescriptionText !== description;
}
if (initialTitleText || title) {
return initialTitleText !== title;
}
return false;
},
defaultErrorMessage() {
return sprintf(s__('Error updating %{issuableType}'), { issuableType: this.issuableType });
......
......@@ -145,6 +145,7 @@ export default {
></div>
<textarea
v-if="descriptionText"
ref="textarea"
v-model="descriptionText"
:data-update-url="updateUrl"
class="hidden js-task-list-field"
......
......@@ -17,6 +17,7 @@ export default {
<label class="sr-only" for="issuable-title"> Title </label>
<input
id="issuable-title"
ref="input"
v-model="formState.title"
class="form-control qa-title-input"
type="text"
......
<script>
import $ from 'jquery';
import lockedWarning from './locked_warning.vue';
import titleField from './fields/title.vue';
import descriptionField from './fields/description.vue';
import editActions from './edit_actions.vue';
import descriptionTemplate from './fields/description_template.vue';
import Autosave from '~/autosave';
import eventHub from '../event_hub';
export default {
components: {
......@@ -68,6 +71,47 @@ export default {
return this.issuableTemplates.length;
},
},
created() {
eventHub.$on('delete.issuable', this.resetAutosave);
eventHub.$on('update.issuable', this.resetAutosave);
eventHub.$on('close.form', this.resetAutosave);
},
mounted() {
this.initAutosave();
},
beforeDestroy() {
eventHub.$off('delete.issuable', this.resetAutosave);
eventHub.$off('update.issuable', this.resetAutosave);
eventHub.$off('close.form', this.resetAutosave);
},
methods: {
initAutosave() {
const {
description: {
$refs: { textarea },
},
title: {
$refs: { input },
},
} = this.$refs;
this.autosaveDescription = new Autosave($(textarea), [
document.location.pathname,
document.location.search,
'description',
]);
this.autosaveTitle = new Autosave($(input), [
document.location.pathname,
document.location.search,
'title',
]);
},
resetAutosave() {
this.autosaveDescription.reset();
this.autosaveTitle.reset();
},
},
};
</script>
......@@ -89,10 +133,11 @@ export default {
'col-12': !hasIssuableTemplates,
}"
>
<title-field :form-state="formState" :issuable-templates="issuableTemplates" />
<title-field ref="title" :form-state="formState" :issuable-templates="issuableTemplates" />
</div>
</div>
<description-field
ref="description"
:form-state="formState"
:markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
......
---
title: Autosave description in epics
merge_request: 27296
author:
type: added
......@@ -470,4 +470,51 @@ describe('Issuable output', () => {
.catch(done.fail);
});
});
describe('issueChanged', () => {
beforeEach(() => {
vm.store.formState.title = '';
vm.store.formState.description = '';
vm.initialDescriptionText = '';
vm.initialTitleText = '';
});
it('returns true when title is changed', () => {
vm.store.formState.title = 'RandomText';
expect(vm.issueChanged).toBe(true);
});
it('returns false when title is empty null', () => {
vm.store.formState.title = null;
expect(vm.issueChanged).toBe(false);
});
it('returns false when `initialTitleText` is null and `formState.title` is empty string', () => {
vm.store.formState.title = '';
vm.initialTitleText = null;
expect(vm.issueChanged).toBe(false);
});
it('returns true when description is changed', () => {
vm.store.formState.description = 'RandomText';
expect(vm.issueChanged).toBe(true);
});
it('returns false when description is empty null', () => {
vm.store.formState.title = null;
expect(vm.issueChanged).toBe(false);
});
it('returns false when `initialDescriptionText` is null and `formState.description` is empty string', () => {
vm.store.formState.description = '';
vm.initialDescriptionText = null;
expect(vm.issueChanged).toBe(false);
});
});
});
......@@ -63,4 +63,8 @@ describe('Description field component', () => {
expect(eventHub.$emit).toHaveBeenCalled();
});
it('has a ref named `textarea`', () => {
expect(vm.$refs.textarea).not.toBeNull();
});
});
......@@ -41,4 +41,8 @@ describe('Title field component', () => {
expect(eventHub.$emit).toHaveBeenCalled();
});
it('has a ref named `input`', () => {
expect(vm.$refs.input).not.toBeNull();
});
});
import Vue from 'vue';
import formComponent from '~/issue_show/components/form.vue';
import eventHub from '~/issue_show/event_hub';
describe('Inline edit form component', () => {
let vm;
let autosave;
let autosaveObj;
beforeEach(done => {
autosaveObj = { reset: jasmine.createSpy() };
autosave = spyOnDependency(formComponent, 'Autosave').and.returnValue(autosaveObj);
const Component = Vue.extend(formComponent);
vm = new Component({
......@@ -53,4 +60,22 @@ describe('Inline edit form component', () => {
done();
});
});
it('initialized Autosave on mount', () => {
expect(autosave).toHaveBeenCalledTimes(2);
});
it('calls reset on autosave when eventHub emits appropriate events', () => {
eventHub.$emit('close.form');
expect(autosaveObj.reset).toHaveBeenCalledTimes(2);
eventHub.$emit('delete.issuable');
expect(autosaveObj.reset).toHaveBeenCalledTimes(4);
eventHub.$emit('update.issuable');
expect(autosaveObj.reset).toHaveBeenCalledTimes(6);
});
});
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