Commit e3e3caa2 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 7d32b766
......@@ -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: 10844
author:
type: added
......@@ -57,6 +57,28 @@ describe 'Update Epic', :js do
expect(find('.issuable-details .description')).to have_content('New epic description')
end
it 'updates the epic and keep the description saved across reload' do
fill_in 'issue-description', with: 'New epic description'
page.within('.detail-page-description') do
click_button('Preview')
expect(find('.md-preview-holder')).to have_content('New epic description')
end
visit group_epic_path(group, epic)
# Deal with the beforeunload browser popup
page.driver.browser.switch_to.alert.accept
wait_for_requests
find('.btn-edit').click
page.within('.detail-page-description') do
click_button('Preview')
expect(find('.md-preview-holder')).to have_content('New epic description')
end
end
it 'creates a todo only for mentioned users' do
mentioned = create(:user)
......
......@@ -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