Skip to content
Snippets Groups Projects
Verified Commit 14f61ea6 authored by Himanshu Kapoor's avatar Himanshu Kapoor Committed by GitLab
Browse files

Merge branch 'fix/delete-wiki-notes' into 'master'

fix deleting first note on wiki threads

See merge request !176061



Merged-by: default avatarHimanshu Kapoor <info@fleon.org>
Approved-by: default avatarHimanshu Kapoor <info@fleon.org>
Co-authored-by: Salihu Dickson's avatarSalihu <salihudickson@gmail.com>
parents 19ec934d 34695038
No related branches found
No related tags found
3 merge requests!181325Fix ambiguous `created_at` in project.rb,!179611Draft: Rebase CR approach for zoekt assignments,!176061fix deleting first note on wiki threads
Pipeline #1612864111 passed
......@@ -112,10 +112,12 @@ export default {
<template>
<timeline-entry-item class="note discussion note-comment">
<wiki-note
:key="firstNote.id"
:user-permissions="getUserPermissions(firstNote)"
:note="firstNote"
:noteable-id="noteableId"
@reply="toggleReplying(true)"
@note-deleted="$emit('note-deleted', firstNote.id)"
>
<template v-if="replies.length || isReplying" #note-footer>
<div
......@@ -129,6 +131,7 @@ export default {
:noteable-id="noteableId"
:user-permissions="getUserPermissions(reply)"
:note="reply"
@note-deleted="$emit('note-deleted', reply.id)"
/>
</div>
......
......@@ -47,7 +47,6 @@ export default {
isEditing: false,
isUpdating: false,
isDeleting: false,
isDeleted: false,
};
},
computed: {
......@@ -138,7 +137,7 @@ export default {
variables: { input: { id: this.note.id } },
});
this.isDeleted = true;
this.$emit('note-deleted');
} catch (err) {
createAlert({
message: __('Something went wrong while deleting your note. Please try again.'),
......@@ -152,7 +151,6 @@ export default {
</script>
<template>
<timeline-entry-item
v-if="!isDeleted"
:id="noteAnchorId"
:class="dynamicClasses.timeLineEntryItem"
:data-note-id="noteId"
......
<script>
import { GlAlert } from '@gitlab/ui';
import { cloneDeep } from 'lodash';
import { __ } from '~/locale';
import wikiPageQuery from '~/wikis/graphql/wiki_page.query.graphql';
import SkeletonNote from '~/vue_shared/components/notes/skeleton_note.vue';
......@@ -61,7 +62,7 @@ export default {
},
result({ data }) {
this.noteableId = data?.wikiPage?.id || '';
this.discussions = data?.wikiPage?.discussions?.nodes || [];
this.discussions = cloneDeep(data?.wikiPage?.discussions?.nodes) || [];
},
},
},
......@@ -116,6 +117,24 @@ export default {
getDiscussionKey(key, stringModifier) {
return [key, stringModifier].join('-');
},
handleDeleteNote(noteId, discussionId) {
const discussionIndex = this.discussions.findIndex(
(discussion) => discussion.id === discussionId,
);
if (discussionIndex === -1) return;
if (this.discussions[discussionIndex].notes.nodes.length === 1) {
this.discussions = this.discussions.filter(({ id }) => id !== discussionId);
} else {
const updatedNotes = this.discussions[discussionIndex].notes.nodes.filter(
({ id }) => id !== noteId,
);
this.discussions[discussionIndex].notes.nodes = updatedNotes;
}
},
},
};
</script>
......@@ -159,6 +178,7 @@ export default {
:key="getDiscussionKey(discussion.id, 'discussion')"
:noteable-id="noteableId"
:discussion="discussion.notes.nodes"
@note-deleted="(noteId) => handleDeleteNote(noteId, discussion.id)"
/>
</template>
</ul>
......
......@@ -12,6 +12,10 @@ import { currentUserData, note, noteableId, noteableType } from '../mock_data';
describe('WikiDiscussion', () => {
let wrapper;
const $apollo = {
mutate: jest.fn(),
};
const createWrapper = ({ props, provideData = { userData: currentUserData } } = {}) =>
shallowMountExtended(WikiDiscussion, {
propsData: {
......@@ -19,6 +23,9 @@ describe('WikiDiscussion', () => {
noteableId,
...props,
},
mocks: {
$apollo,
},
provide: {
noteableType,
currentUserData,
......@@ -87,6 +94,54 @@ describe('WikiDiscussion', () => {
body: 'another example note',
});
});
describe('when note-deleted is emmitted from a note', () => {
beforeEach(() => {
wrapper = createWrapper({
props: {
discussion: [
note,
{
...note,
id: 2,
body: 'first note',
bodyHtml: '<p data-sourcepos="1:1-1:29" dir="auto">first note</p>',
},
{
...note,
id: 3,
body: 'second note',
bodyHtml: '<p data-sourcepos="1:1-1:29" dir="auto">second note</p>',
},
{
...note,
id: 4,
body: 'third note',
bodyHtml: '<p data-sourcepos="1:1-1:29" dir="auto">third note</p>',
},
],
},
});
});
it('should emit "note-deleted" with the first note id when emitted from the first note', async () => {
await wrapper.findComponent(WikiNote).vm.$emit('note-deleted');
expect(wrapper.emitted('note-deleted')).toEqual([[note.id]]);
});
it.each`
replyIndex | noteId
${0} | ${2}
${1} | ${3}
${2} | ${4}
`(
'should emit "note-deleted" with the correct id when emitted from a reply',
async ({ replyIndex, noteId }) => {
await noteFooter().findAllComponents(WikiNote).at(replyIndex).vm.$emit('note-deleted');
expect(wrapper.emitted('note-deleted')).toEqual([[noteId]]);
},
);
});
});
});
......
......@@ -357,13 +357,12 @@ describe('WikiNote', () => {
verifyEditingOrDeletingStyles(false);
});
it('should set deleted to true when delete note is successful', async () => {
it('should emit "note-deleted" when delete note is successful', async () => {
jest.spyOn(confirmViaGLModal, 'confirmAction').mockImplementation(() => true);
$apollo.mutate.mockResolvedValue();
await wrapper.vm.deleteNote();
expect(wrapper.findComponent(TimelineEntryItem).exists()).toBe(false);
expect(Boolean(wrapper.emitted('note-deleted'))).toBe(true);
});
});
});
......
......@@ -143,6 +143,16 @@ describe('WikiNotesApp', () => {
nodes: [
{ id: 1, notes: { nodes: [{ body: 'Discussion 1' }] } },
{ id: 2, notes: { nodes: [{ body: 'Discussion 2' }] } },
{
id: 3,
notes: {
nodes: [
{ id: 31, body: 'Discussion 3 Note 1' },
{ id: 32, body: 'Discussion 3 Note 2' },
{ id: 33, body: 'Discussion 3 Note 3' },
],
},
},
],
},
},
......@@ -158,7 +168,7 @@ describe('WikiNotesApp', () => {
it('should render discussions correctly', () => {
const wikiDiscussions = wrapper.findAllComponents(WikiDiscussion);
expect(wikiDiscussions.length).toBe(2);
expect(wikiDiscussions.length).toBe(3);
expect(wikiDiscussions.at(0).props()).toMatchObject({
discussion: [{ body: 'Discussion 1' }],
noteableId: 'gid://gitlab/WikiPage/1',
......@@ -173,6 +183,40 @@ describe('WikiNotesApp', () => {
const errorAlert = wrapper.findComponent(GlAlert);
expect(errorAlert.exists()).toBe(false);
});
it('should delete the note correctly when the WikiDiscussions emits "note-deleted" when there are replies', () => {
const wikiDiscussions = wrapper.findAllComponents(WikiDiscussion);
// delete first note
wikiDiscussions.at(2).vm.$emit('note-deleted', 31);
let notes = wrapper.vm.discussions[2].notes.nodes;
expect(notes).toHaveLength(2);
expect(notes).not.toContainEqual({
id: 31,
body: 'Discussion 3 Note 1',
});
// delete last note
wikiDiscussions.at(2).vm.$emit('note-deleted', 33);
notes = wrapper.vm.discussions[2].notes.nodes;
expect(notes).toHaveLength(1);
expect(notes).toMatchObject([
{
id: 32,
body: 'Discussion 3 Note 2',
},
]);
// delete only note
wikiDiscussions.at(2).vm.$emit('note-deleted', 32);
const { discussions } = wrapper.vm;
expect(discussions).toHaveLength(2);
expect(discussions).not.toContainEqual(
expect.objectContaining({
id: 3,
}),
);
});
});
describe('when fetching discussions', () => {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment