Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Frontend] The vertical '...' context menu functions to delete posts #158

Merged
30 changes: 17 additions & 13 deletions frontend/src/components/AnalysisView/DiscussionPost.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
<div class="discussion-post" data-test="discussion-post">
<div class="discussion-header" data-test="discussion-post-header">
<div>
<b>{{ author_name }}</b>
<b>{{ authorName }}</b>
{{ timestamp }}
</div>
<ul v-if="isUser" class="context-menu" data-test="discussion-post-context-menu">
<ContextMenu :actions="actions" :context_id="id">
<ContextMenu
:actions="actions"
:contextId="id"
@delete="this.deletePost"
>
<font-awesome-icon class="header-icon" icon="ellipsis-vertical" size="xl" />
</ContextMenu>
</ul>
Expand All @@ -22,36 +26,31 @@ import ContextMenu from '@/components/ContextMenu.vue';

export default {
name: 'discussion-post',
emits: ['post:delete'],
components: {
ContextMenu,
},
props: {
id: {
type: String,
},
author_id: {
authorId: {
type: String,
},
author_name: {
authorName: {
type: String,
},
publish_timestamp: {
publishTimestamp: {
type: String,
},
content: {
type: String,
},
attachments: {
type: Array,
default: () => {
return [];
},
},
thread: {
type: Array,
default: () => {
return [];
},
},
userClientId: {
type: String,
Expand All @@ -62,10 +61,15 @@ export default {
},
computed: {
timestamp: function() {
return new Date(this.publish_timestamp).toUTCString();
return new Date(this.publishTimestamp).toUTCString();
},
isUser: function() {
return this.userClientId == this.author_id;
return this.userClientId == this.authorId;
},
},
methods: {
deletePost(postId) {
this.$emit('post:delete', postId);
},
},
};
Expand Down
18 changes: 8 additions & 10 deletions frontend/src/components/AnalysisView/DiscussionSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@
<DiscussionPost v-for="discussion in discussions"
:id="discussion.post_id"
:key="discussion.post_id"
:author_id="discussion.author_id"
:author_name="discussion.author_fullname"
:publish_timestamp="discussion.publish_timestamp"
:authorId="discussion.author_id"
:authorName="discussion.author_fullname"
:publishTimestamp="discussion.publish_timestamp"
:content="discussion.content"
:attachments="discussion.attachments"
:thread="discussion.thread"
:userClientId="userClientId"
:actions="actions"
@post:delete="this.deleteDiscussionPost"
/>
</div>
</div>
Expand All @@ -63,7 +64,7 @@ import DiscussionPost from './DiscussionPost.vue';

export default {
name: 'discussion-section',
emits: ['discussion:new-post'],
emits: ['discussion:new-post', 'discussion:delete-post'],
components: {
DiscussionPost,
},
Expand All @@ -73,18 +74,12 @@ export default {
},
discussions: {
type: Array,
default: () => {
return [];
},
},
userClientId: {
type: String,
},
actions: {
type: Array,
default: () => {
return [];
},
},
},
data: function() {
Expand Down Expand Up @@ -113,6 +108,9 @@ export default {
this.newPostContent = '';
this.showNewPost = false;
},
deleteDiscussionPost(postId) {
this.$emit('discussion:delete-post', postId);
},
},
};

Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/ContextMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<li tabindex="1" ref="contextRef">
<slot></slot>
<ul class="grey-rounded-menu drop-down-content">
<li v-for="action in actions" :key="action.text" @click="this.runAction(action.operation)">
<li v-for="action in actions" :key="action.text" @click="this.runAction(action.emit)">
<span> {{ action.text }} </span>
<font-awesome-icon v-if="action.icon" :icon="action.icon" size="lg" class="right-side-icon" />
</li>
Expand All @@ -20,11 +20,11 @@ export default {
(action) => action.text !== undefined || action.divider,
),
},
context_id: String,
contextId: String,
},
methods: {
runAction(actionOperation) {
actionOperation(this.context_id);
runAction(actionEmit) {
this.$emit(actionEmit, this.contextId);
this.closeContext();
},
closeContext() {
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/models/analyses.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@ export default {
const success = await Requests.postForm(url, attachmentForm);
return success;
},
async deleteDiscussionThreadById(analysisName, postId) {
const url = `/rosalution/api/analysis/${analysisName}/discussions/${postId}`;

const success = await Requests.delete(url);

return success;
},
};

const annotationRenderingTemporary = [
Expand Down
6 changes: 1 addition & 5 deletions frontend/src/requests.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,7 @@ export default {
throw new Error(`Status Code: ${response.status} ${ response.statusText}\nURL: \n${response.url}`);
}

if ( response.bodyUsed) {
return await response.json();
}

return response.ok;
return await response.json();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So need for change. Great cleanup/investigation on what was going on here!

},
async postForm(url, data) {
return await sendFormData('POST', url, data);
Expand Down
29 changes: 23 additions & 6 deletions frontend/src/views/AnalysisView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
:userClientId="auth.getClientId()"
:actions="this.discussionContextActions"
@discussion:new-post="this.addDiscussionPost"
@discussion:delete-post="this.deleteDiscussionPost"
/>
<SupplementalFormList
id="Supporting_Evidence"
Expand Down Expand Up @@ -122,15 +123,12 @@ export default {
},
menuActions() {
const actionChoices = [];


actionChoices.push({
icon: 'paperclip',
text: 'Attach',
operation: this.addSupportingEvidence,
});


if ( !this.auth.hasWritePermissions() ) {
return actionChoices;
}
Expand Down Expand Up @@ -214,9 +212,8 @@ export default {
{
icon: 'xmark',
text: 'Delete',
operation: (postId) => {
console.log(`Deleting Discussion Post: ${postId}`);
},
emit: 'delete',
operation: () => {},
},
];
},
Expand Down Expand Up @@ -634,6 +631,26 @@ export default {

this.analysis.discussions = discussions;
},
async deleteDiscussionPost(postId) {
const analysisName = this.analysis_name;

const confirmedDelete = await notificationDialog
.title(`Remove Discussion Post`)
.confirmText('Delete')
.cancelText('Cancel')
.confirm(`Deleting your discussion post from the section.`);

if (!confirmedDelete) {
return;
}

try {
const discussions = await Analyses.deleteDiscussionThreadById(analysisName, postId);
this.analysis.discussions = discussions;
} catch (error) {
await notificationDialog.title('Failure').confirmText('Ok').alert(error);
}
},
copyToClipboard(copiedText) {
toast.success(`Copied ${copiedText} to clipboard!`);
},
Expand Down
21 changes: 15 additions & 6 deletions frontend/test/components/AnalysisView/DiscussionPost.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {it, expect, describe} from 'vitest';
import {shallowMount} from '@vue/test-utils';

import ContextMenu from '../../../src/components/ContextMenu.vue';
import DiscussionPost from '../../../src/components/AnalysisView/DiscussionPost.vue';
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome';

Expand All @@ -13,9 +14,9 @@ function getMountedComponent(props) {
const defaultProps = {
id: '9027ec8d-6298-4afb-add5-6ef710eb5e98',
key: '9027ec8d-6298-4afb-add5-6ef710eb5e98',
author_id: 'fake-user-id',
author_name: 'Developer Person',
publish_timestamp: '2023-10-09T21:13:22.687000',
authorId: 'fake-user-id',
authorName: 'Developer Person',
publishTimestamp: '2023-10-09T21:13:22.687000',
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse eget metus nec erat accumsan rutrum',
attachments: [],
thread: [],
Expand Down Expand Up @@ -54,11 +55,19 @@ describe('DiscussionPost.vue', () => {
expect(contextMenu.exists()).toBe(false);
});

it('Edit test', () => {
it('Should recieve an emit to delete a post and emits a post:delete with postId', async () => {
const wrapper = getMountedComponent({userClientId: 'fake-user-id'});

const contextMenu = wrapper.find('[data-test=discussion-post-context-menu]');
const postId = '9027ec8d-6298-4afb-add5-6ef710eb5e98';

const contextMenu = wrapper.getComponent(ContextMenu);

contextMenu.vm.$emit('delete', postId);

await wrapper.vm.$nextTick();

const emittedObject = wrapper.emitted()['post:delete'][0];

console.log(contextMenu.html());
expect(emittedObject[0]).toBe(postId);
});
});
72 changes: 71 additions & 1 deletion frontend/test/components/AnalysisView/DiscussionSection.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import {it, expect, describe, beforeEach} from 'vitest';
import {shallowMount} from '@vue/test-utils';

import DiscussionSection from '../../../src/components/AnalysisView/DiscussionSection.vue';
import DiscussionPost from '../../../src/components/AnalysisView/DiscussionPost.vue';

import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome';

describe('DiscussionSection.vue', () => {
let wrapper;

beforeEach(() => {
beforeEach((props) => {
const defaultProps = fixtureData();
wrapper = shallowMount(DiscussionSection, {
props: {...defaultProps, ...props},
global: {
components: {
'font-awesome-icon': FontAwesomeIcon,
Expand All @@ -22,6 +25,12 @@ describe('DiscussionSection.vue', () => {
expect(typeof wrapper).toBe('object');
});

it('Should contain 3 discussion posts', () => {
const discussionPosts = wrapper.findAllComponents(DiscussionPost);

expect(discussionPosts.length).toBe(3);
});

it('Should emit a discussion:new-post event when the publish button is pressed', async () => {
await wrapper.setData({newPostContent: 'Test post content'});

Expand Down Expand Up @@ -52,4 +61,65 @@ describe('DiscussionSection.vue', () => {

await newDiscussionCancelButton.trigger('click');
});

it('Should recieve an emit to delete a post and then emit discussion:delete-post with the post id', async () => {
const discussionPosts = wrapper.findAllComponents(DiscussionPost);

const postId = '9027ec8d-6298-4afb-add5-6ef710eb5e98';

discussionPosts[0].vm.$emit('post:delete', postId);

await wrapper.vm.$nextTick();

const emittedObject = wrapper.emitted()['discussion:delete-post'][0];

expect(emittedObject[0]).toBe(postId);
});
});

/**
* Returns fixture data
* @return {Object} containing discussion data from CPAM0002.
*/
function fixtureData() {
return {
userClientId: 'fake-user-id',
discussions: [
{
'post_id': '9027ec8d-6298-4afb-add5-6ef710eb5e98',
'author_id': '3bghhsmnyqi6uxovazy07ryn9q1tqbnt',
'author_fullname': 'Developer Person',
'publish_timestamp': '2023-10-09T21:13:22.687000',
'content': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'attachments': [],
'thread': [],
},
{
'post_id': 'a677bb36-acf8-4ff9-a406-b113a7952f7e',
'author_id': 'kw0g790fdx715xsr1ead2jk0pqubtlyz',
'author_fullname': 'Researcher Person',
'publish_timestamp': '2023-10-10T21:13:22.687000',
'content': 'Mauris at mauris eu neque varius suscipit.',
'attachments': [],
'thread': [],
},
{
'post_id': 'e6023fa7-b598-416a-9f42-862c826255ef',
'author_id': 'exqkhvidr7uh2ndslsdymbzfbmqjlunk',
'author_fullname': 'Variant Review Report Preparer Person',
'publish_timestamp': '2023-10-13T21:13:22.687000',
'content': 'Mauris at mauris eu neque varius suscipit.',
'attachments': [],
'thread': [],
},
],
actions: [
{
icon: 'xmark',
text: 'Delete',
emit: 'delete',
operation: () => {},
},
],
};
}
1 change: 0 additions & 1 deletion frontend/test/components/RosalutionHeader.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ afterAll(() => {
describe('RosalutionHeaderComponent.vue', () => {
it('should display application title by default', () => {
const wrapper = getMountedComponent();
console.log(wrapper.html());
const headerTextLink = wrapper.find('[data-test="header-title-text"]');
expect(headerTextLink.html()).to.contains('rosalution');
});
Expand Down
Loading
Loading