Commit c84238ff authored by Florie Guibert's avatar Florie Guibert

Delete description change history

- Backend fix for caching issue
- Remove append diff to previous
- Tests
parent b5adc096
...@@ -509,7 +509,8 @@ export const fetchDescriptionVersion = (_, { endpoint, startingVersion }) => { ...@@ -509,7 +509,8 @@ export const fetchDescriptionVersion = (_, { endpoint, startingVersion }) => {
export const setCurrentDiscussionId = ({ commit }, discussionId) => export const setCurrentDiscussionId = ({ commit }, discussionId) =>
commit(types.SET_CURRENT_DISCUSSION_ID, discussionId); commit(types.SET_CURRENT_DISCUSSION_ID, discussionId);
export const softDeleteDescriptionVersion = ({ commit }, { endpoint, startingVersion }) => {
export const softDeleteDescriptionVersion = (_, { endpoint, startingVersion }) => {
let requestUrl = endpoint; let requestUrl = endpoint;
if (startingVersion) { if (startingVersion) {
...@@ -518,11 +519,7 @@ export const softDeleteDescriptionVersion = ({ commit }, { endpoint, startingVer ...@@ -518,11 +519,7 @@ export const softDeleteDescriptionVersion = ({ commit }, { endpoint, startingVer
return axios return axios
.delete(requestUrl) .delete(requestUrl)
.then(res => { .then(res => res.data)
// Invalidate lastFatechedAt to trigger refetch on next page refresh
commit(types.SET_LAST_FETCHED_AT, null);
return res.data;
})
.catch(() => { .catch(() => {
Flash(__('Something went wrong while deleting description changes. Please try again.')); Flash(__('Something went wrong while deleting description changes. Please try again.'));
}); });
......
...@@ -45,7 +45,11 @@ export const collapseSystemNotes = notes => { ...@@ -45,7 +45,11 @@ export const collapseSystemNotes = notes => {
const timeDifferenceMinutes = getTimeDifferenceMinutes(lastDescriptionSystemNote, note); const timeDifferenceMinutes = getTimeDifferenceMinutes(lastDescriptionSystemNote, note);
// are they less than 10 minutes apart from the same user? // are they less than 10 minutes apart from the same user?
if (timeDifferenceMinutes > 10 || note.author.id !== lastDescriptionSystemNote.author.id) { if (
timeDifferenceMinutes > 10 ||
note.author.id !== lastDescriptionSystemNote.author.id ||
lastDescriptionSystemNote.description_version_deleted
) {
// update the previous system note // update the previous system note
lastDescriptionSystemNote = note; lastDescriptionSystemNote = note;
lastDescriptionSystemNoteIndex = acc.length; lastDescriptionSystemNoteIndex = acc.length;
......
...@@ -22,6 +22,7 @@ import { GlSkeletonLoading, GlTooltipDirective } from '@gitlab/ui'; ...@@ -22,6 +22,7 @@ import { GlSkeletonLoading, GlTooltipDirective } from '@gitlab/ui';
import descriptionVersionHistoryMixin from 'ee_else_ce/notes/mixins/description_version_history'; import descriptionVersionHistoryMixin from 'ee_else_ce/notes/mixins/description_version_history';
import noteHeader from '~/notes/components/note_header.vue'; import noteHeader from '~/notes/components/note_header.vue';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import TimelineEntryItem from './timeline_entry_item.vue'; import TimelineEntryItem from './timeline_entry_item.vue';
import { spriteIcon } from '../../../lib/utils/common_utils'; import { spriteIcon } from '../../../lib/utils/common_utils';
import initMRPopovers from '~/mr_popover/'; import initMRPopovers from '~/mr_popover/';
...@@ -39,7 +40,7 @@ export default { ...@@ -39,7 +40,7 @@ export default {
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
}, },
mixins: [descriptionVersionHistoryMixin], mixins: [descriptionVersionHistoryMixin, glFeatureFlagsMixin()],
props: { props: {
note: { note: {
type: Object, type: Object,
......
...@@ -39,6 +39,8 @@ module EE ...@@ -39,6 +39,8 @@ module EE
issuable_description_versions.where('id BETWEEN ? AND ?', start_id, self.id) issuable_description_versions.where('id BETWEEN ? AND ?', start_id, self.id)
description_versions.update_all(deleted_at: Time.now) description_versions.update_all(deleted_at: Time.now)
issuable&.expire_note_etag_cache
end end
def deleted? def deleted?
......
...@@ -53,6 +53,14 @@ describe DescriptionVersion do ...@@ -53,6 +53,14 @@ describe DescriptionVersion do
.count .count
end end
it 'expires issuable etag cache' do
version = epic.description_versions.last
expect(epic).to receive(:expire_note_etag_cache)
version.delete!
end
context 'when start_id is not present' do context 'when start_id is not present' do
it 'only soft deletes description_version' do it 'only soft deletes description_version' do
version = epic.description_versions.last version = epic.description_versions.last
......
...@@ -17783,6 +17783,9 @@ msgstr "" ...@@ -17783,6 +17783,9 @@ msgstr ""
msgid "Something went wrong while closing the %{issuable}. Please try again later" msgid "Something went wrong while closing the %{issuable}. Please try again later"
msgstr "" msgstr ""
msgid "Something went wrong while deleting description changes. Please try again."
msgstr ""
msgid "Something went wrong while deleting the image." msgid "Something went wrong while deleting the image."
msgstr "" msgstr ""
......
import Vue from 'vue';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import axios from '~/lib/utils/axios_utils';
import MockAdapter from 'axios-mock-adapter';
import IssueSystemNote from '~/vue_shared/components/notes/system_note.vue'; import IssueSystemNote from '~/vue_shared/components/notes/system_note.vue';
import createStore from '~/notes/stores'; import createStore from '~/notes/stores';
import initMRPopovers from '~/mr_popover/index'; import initMRPopovers from '~/mr_popover/index';
...@@ -8,6 +11,7 @@ jest.mock('~/mr_popover/index', () => jest.fn()); ...@@ -8,6 +11,7 @@ jest.mock('~/mr_popover/index', () => jest.fn());
describe('system note component', () => { describe('system note component', () => {
let vm; let vm;
let props; let props;
let mock;
beforeEach(() => { beforeEach(() => {
props = { props = {
...@@ -24,19 +28,30 @@ describe('system note component', () => { ...@@ -24,19 +28,30 @@ describe('system note component', () => {
note_html: '<p dir="auto">closed</p>', note_html: '<p dir="auto">closed</p>',
system_note_icon_name: 'status_closed', system_note_icon_name: 'status_closed',
created_at: '2017-08-02T10:51:58.559Z', created_at: '2017-08-02T10:51:58.559Z',
description_version_id: 1,
description_diff_path: 'path/to/diff',
delete_description_version_path: 'path/to/diff/1',
can_delete_description_version: true,
description_version_deleted: false,
}, },
}; };
const store = createStore(); const store = createStore();
store.dispatch('setTargetNoteHash', `note_${props.note.id}`); store.dispatch('setTargetNoteHash', `note_${props.note.id}`);
mock = new MockAdapter(axios);
vm = mount(IssueSystemNote, { vm = mount(IssueSystemNote, {
store, store,
propsData: props, propsData: props,
provide: {
glFeatures: { saveDescriptionVersions: true, descriptionDiffs: true },
},
}); });
}); });
afterEach(() => { afterEach(() => {
mock.restore();
vm.destroy(); vm.destroy();
}); });
...@@ -62,4 +77,42 @@ describe('system note component', () => { ...@@ -62,4 +77,42 @@ describe('system note component', () => {
it('should initMRPopovers onMount', () => { it('should initMRPopovers onMount', () => {
expect(initMRPopovers).toHaveBeenCalled(); expect(initMRPopovers).toHaveBeenCalled();
}); });
it('should display button to toggle description diff, description version does not display', () => {
const button = vm.find('.note-headline-light .btn-blank');
expect(button).toExist();
expect(button.text()).toContain('Compare with previous version');
expect(vm.find('.description-version').exists()).toBe(false);
});
it('click on button to toggle description diff displays description diff with delete icon button', done => {
const diffData =
'<span class="idiff">Description</span><span class="idiff addition">Diff</span>';
mock.onGet(`/path/to/diff/1`).replyOnce(200, {
data: diffData,
});
const button = vm.find('.note-headline-light .btn-blank');
button.trigger('click');
Vue.nextTick(() => {
expect(vm.find('.description-version').exists()).toBe(true);
expect(vm.find('.description-version').html()).toContain(diffData);
expect(
vm.find('.description-version button.delete-description-history svg.s16').exists(),
).toBe(true);
done();
});
});
it('click on delete icon button deletes description diff', done => {
vm.find('.note-headline-light .btn-blank').trigger('click');
Vue.nextTick(() => {
const button = vm.find('.description-version button.delete-description-history');
button.trigger('click');
expect(vm.find('.description-version').text()).toContain('Deleted');
done();
});
});
}); });
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