Commit 975c4d03 authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch...

Merge branch '34817-issue-description-reverts-to-an-older-version-when-saving-without-prompting-the-conflict-vue' into 'master'

Resolve "Issue description reverts to an older version when saving without prompting the conflict"

See merge request gitlab-org/gitlab!29438
parents 5e121361 3654a979
......@@ -418,6 +418,7 @@ export default {
<div v-if="canUpdate && showForm">
<form-component
:form-state="formState"
:initial-description-text="initialDescriptionText"
:can-destroy="canDestroy"
:issuable-templates="issuableTemplates"
:markdown-docs-path="markdownDocsPath"
......
<script>
import { GlAlert } from '@gitlab/ui';
import $ from 'jquery';
import Autosave from '~/autosave';
import eventHub from '../event_hub';
......@@ -15,6 +16,7 @@ export default {
descriptionField,
descriptionTemplate,
editActions,
GlAlert,
},
props: {
canDestroy: {
......@@ -69,6 +71,16 @@ export default {
required: false,
default: true,
},
initialDescriptionText: {
type: String,
required: false,
default: '',
},
},
data() {
return {
showOutdatedDescriptionWarning: false,
};
},
computed: {
hasIssuableTemplates() {
......@@ -102,11 +114,17 @@ export default {
},
} = this.$refs;
this.autosaveDescription = new Autosave($(textarea), [
document.location.pathname,
document.location.search,
'description',
]);
this.autosaveDescription = new Autosave(
$(textarea),
[document.location.pathname, document.location.search, 'description'],
null,
this.formState.lock_version,
);
const savedLockVersion = this.autosaveDescription.getSavedLockVersion();
this.showOutdatedDescriptionWarning =
savedLockVersion && String(this.formState.lock_version) !== savedLockVersion;
this.autosaveTitle = new Autosave($(input), [
document.location.pathname,
......@@ -118,6 +136,27 @@ export default {
this.autosaveDescription.reset();
this.autosaveTitle.reset();
},
keepAutosave() {
const {
description: {
$refs: { textarea },
},
} = this.$refs;
textarea.focus();
this.showOutdatedDescriptionWarning = false;
},
discardAutosave() {
const {
description: {
$refs: { textarea },
},
} = this.$refs;
textarea.value = this.initialDescriptionText;
textarea.focus();
this.showOutdatedDescriptionWarning = false;
},
},
};
</script>
......@@ -125,6 +164,21 @@ export default {
<template>
<form>
<locked-warning v-if="showLockedWarning" />
<gl-alert
v-if="showOutdatedDescriptionWarning"
class="gl-mb-5"
variant="warning"
primary-button-text="__('Keep')"
secondary-button-text="__('Discard')"
:dismissible="false"
@primaryAction="keepAutosave"
@secondaryAction="discardAutosave"
>{{
__(
'The comment you are editing has been changed by another user. Would you like to keep your changes and overwrite the new description or discard your changes?',
)
}}</gl-alert
>
<div class="row">
<div v-if="hasIssuableTemplates" class="col-sm-4 col-lg-3">
<description-template
......
---
title: Add warning when locally stored description is out of date.
merge_request: 29438
author:
type: fixed
......@@ -31740,6 +31740,9 @@ msgstr ""
msgid "The collection of events added to the data gathered for that stage."
msgstr ""
msgid "The comment you are editing has been changed by another user. Would you like to keep your changes and overwrite the new description or discard your changes?"
msgstr ""
msgid "The commit does not exist"
msgstr ""
......
import Vue from 'vue';
import mountComponent from 'helpers/vue_mount_component_helper';
import { GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Autosave from '~/autosave';
import DescriptionTemplate from '~/issue_show/components/fields/description_template.vue';
import formComponent from '~/issue_show/components/form.vue';
import LockedWarning from '~/issue_show/components/locked_warning.vue';
import eventHub from '~/issue_show/event_hub';
jest.mock('~/autosave');
describe('Inline edit form component', () => {
let vm;
let wrapper;
const defaultProps = {
canDestroy: true,
formState: {
......@@ -24,22 +26,26 @@ describe('Inline edit form component', () => {
};
afterEach(() => {
vm.$destroy();
wrapper.destroy();
});
const createComponent = (props) => {
const Component = Vue.extend(formComponent);
vm = mountComponent(Component, {
...defaultProps,
...props,
wrapper = shallowMount(formComponent, {
propsData: {
...defaultProps,
...props,
},
});
};
const findDescriptionTemplate = () => wrapper.findComponent(DescriptionTemplate);
const findLockedWarning = () => wrapper.findComponent(LockedWarning);
const findAlert = () => wrapper.findComponent(GlAlert);
it('does not render template selector if no templates exist', () => {
createComponent();
expect(vm.$el.querySelector('.js-issuable-selector-wrap')).toBeNull();
expect(findDescriptionTemplate().exists()).toBe(false);
});
it('renders template selector when templates as array exists', () => {
......@@ -49,7 +55,7 @@ describe('Inline edit form component', () => {
],
});
expect(vm.$el.querySelector('.js-issuable-selector-wrap')).not.toBeNull();
expect(findDescriptionTemplate().exists()).toBe(true);
});
it('renders template selector when templates as hash exists', () => {
......@@ -59,19 +65,19 @@ describe('Inline edit form component', () => {
},
});
expect(vm.$el.querySelector('.js-issuable-selector-wrap')).not.toBeNull();
expect(findDescriptionTemplate().exists()).toBe(true);
});
it('hides locked warning by default', () => {
createComponent();
expect(vm.$el.querySelector('.alert')).toBeNull();
expect(findLockedWarning().exists()).toBe(false);
});
it('shows locked warning if formState is different', () => {
createComponent({ formState: { ...defaultProps.formState, lockedWarningVisible: true } });
expect(vm.$el.querySelector('.alert')).not.toBeNull();
expect(findLockedWarning().exists()).toBe(true);
});
it('hides locked warning when currently saving', () => {
......@@ -79,7 +85,7 @@ describe('Inline edit form component', () => {
formState: { ...defaultProps.formState, updateLoading: true, lockedWarningVisible: true },
});
expect(vm.$el.querySelector('.alert')).toBeNull();
expect(findLockedWarning().exists()).toBe(false);
});
describe('autosave', () => {
......@@ -110,5 +116,23 @@ describe('Inline edit form component', () => {
expect(spy).toHaveBeenCalledTimes(6);
});
describe('outdated description', () => {
it('does not show warning if lock version from server is the same as the local lock version', () => {
createComponent();
expect(findAlert().exists()).toBe(false);
});
it('shows warning if lock version from server differs than the local lock version', async () => {
Autosave.prototype.getSavedLockVersion.mockResolvedValue('lock version from local storage');
createComponent({
formState: { ...defaultProps.formState, lock_version: 'lock version from server' },
});
await wrapper.vm.$nextTick();
expect(findAlert().exists()).toBe(true);
});
});
});
});
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