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

Displaying discussion posts #150

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions backend/src/routers/analysis_discussion_router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# pylint: disable=too-many-arguments
# Due to adding scope checks, it's adding too many arguments (7/6) to functions, so diabling this for now.
# Need to refactor later.
""" Analysis endpoint routes that provide an interface to interact with an Analysis' discussions """
from datetime import datetime, timezone
import logging
from uuid import uuid4

from fastapi import (APIRouter, Depends, Form, Security)

from ..dependencies import database
from ..models.user import VerifyUser
from ..security.security import get_current_user

logger = logging.getLogger(__name__)

router = APIRouter(tags=["analysis"], dependencies=[Depends(database)])


def mock_discussion_fixture():
"""Mock dicussion fixture to fake the discussions being returned"""
return [{
"post_id": "90jkflsd8d-6298-4afb-add5-6ef710eb5e98", "author_id": "3bghhsmnyqi6uxovazy07ryn9q1tqbnt",
"author_fullname": "Hello Person", "publish_timestamp": "2023-10-09T21:13:22.687000",
"content": "Nulla diam mi, semper vitae.", "attachments": [], "thread": []
}, {
"post_id": "a677fdsfsacf8-4ff9-a406-b113a7952f7e", "author_id": "kw0g790fdx715xsr1ead2jk0pqubtlyz",
"author_fullname": "Developer Person", "publish_timestamp": "2023-10-10T21:13:22.687000",
"content": "Morbi laoreet justo.", "attachments": [], "thread": []
}, {
"post_id": "e602ffdsfa-fdsfdsa-9f42-862c826255ef", "author_id": "exqkhvidr7uh2ndslsdymbzfbmqjlunk",
"author_fullname": "Variant Review Report Preparer Person", "publish_timestamp": "2023-10-13T21:13:22.687000",
"content": "Mauris pretium sem at nunc sollicitudin also.", "attachments": [], "thread": []
}]


@router.get("/{analysis_name}/discussions")
def get_analysis_discussions(analysis_name: str):
""" Returns a list of genomic units for a given analysis """
logger.info("Retrieving the analysis '%s' discussions ", analysis_name)
return mock_discussion_fixture()


@router.post("/{analysis_name}/discussions")
def add_analysis_discussions(
analysis_name: str,
discussion_content: str = Form(...),
repositories=Depends(database),
client_id: VerifyUser = Security(get_current_user)
):
""" Adds a new analysis topic """
logger.info("Adding the analysis '%s' from user '%s'", analysis_name, client_id)
logger.info("The message: %s", discussion_content)

current_user = repositories["user"].find_by_client_id(client_id)

current_discussions = mock_discussion_fixture()
current_discussions.append({
"post_id": str(uuid4()),
"author_id": client_id,
"author_fullname": current_user["full_name"],
"publish_timestamp": datetime.now(timezone.utc),
"content": discussion_content,
"attachments": [],
"thread": [],
})
return current_discussions
3 changes: 3 additions & 0 deletions backend/src/routers/analysis_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@
from ..models.phenotips_json import BasePhenotips
from ..models.user import VerifyUser
from ..security.security import get_authorization, get_current_user
from . import analysis_discussion_router

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/analysis", tags=["analysis"], dependencies=[Depends(database)])
logger.info('including the api roter for discussions')
router.include_router(analysis_discussion_router.router)


@router.get("/", response_model=List[Analysis])
Expand Down
78 changes: 78 additions & 0 deletions frontend/src/components/AnalysisView/DiscussionPost.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<template>
<div class="discussion-post" data-test="discussion-post">
<div class="discussion-header" data-test="discussion-post-header">
<b>{{ author_name }}</b>
{{ timestamp }}
</div>
<div class="discussion-content" data-test="discussion-post-content">
{{ content }}
</div>
</div>
</template>

<script>
export default {
name: 'discussion-post',
props: {
id: {
type: String,
},
author_id: {
type: String,
},
author_name: {
type: String,
},
publish_timestamp: {
type: String,
},
content: {
type: String,
},
attachments: {
type: Array,
default: () => {
return [];
},
},
thread: {
type: Array,
default: () => {
return [];
},
},
},
computed: {
timestamp: function() {
return new Date(this.publish_timestamp).toUTCString();
},
},
};
</script>

<style scoped>
.discussion-post {
border-radius: var(--content-border-radius);
padding: var(--p-8);
margin-top: var(--p-10);

}

.discussion-post:nth-child(even) {
background-color: var(--rosalution-grey-50);
}

.discussion-post:nth-child(odd) {
background-color: var(--rosalution-grey-100);
}

.discussion-header {
margin-top: var(--p-5);
margin-bottom: var(--p-5);
}

.discussion-content {
margin-bottom: var(--p-10);
}

</style>
88 changes: 83 additions & 5 deletions frontend/src/components/AnalysisView/DiscussionSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,116 @@
<div class="rosalution-section-header">
<h2 class="rosalution-section-header-text">Discussion</h2>
<span class="rosalution-section-center" data-test="header-datasets"/>
<button class="primary-button new-discussion-button">New Discussion</button>
<button class="primary-button discussion-new-button" @click="this.newDiscussionPost">New Discussion</button>
<label class="collapsable-icon" for="discussion_toggle">
<font-awesome-icon icon="chevron-down" size="lg"/>
</label>
</div>
<div class="rosalution-section-seperator"></div>
<div class="section-content">
Content
<div class="discussion-new-post">
<textarea
contenteditable="plaintext-only"
class="discussion-new-post-text-area"
v-model="newPostContent"
data-test="new-discussion-input"
/>
<div class="discussion-actions">
<button class="secondary-button" @click="cancelNewDiscussionPost" data-test="new-discussion-cancel">
Cancel
</button>
<button class="primary-button" @click="newDiscussionPost" data-test="new-discussion-publish">
Publish
</button>
</div>
</div>
<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"
:content="discussion.content"
:attachments="discussion.attachments"
:thread="discussion.thread"
/>
</div>
</div>
</template>

<script>
import DiscussionPost from './DiscussionPost.vue';

export default {
name: 'discussion-section',
emits: ['discussion:new-post'],
components: {
DiscussionPost,
},
props: {
header: {
type: String,
},
discussions: {
type: Array,
default: () => {
return [];
},
},
},
data: function() {
return {
newPostContent: '',
};
},
methods: {
newDiscussionPost() {
this.$emit('discussion:new-post', this.newPostContent);
},
cancelNewDiscussionPost() {
// Currently does nothing, will need to update to turn off the new post text
console.log('Cancelled post');
},
},
};

</script>

<style scoped>

.new-discussion-button {
.discussion-new-button {
margin-bottom: var(--p-8);
margin-right: var(--p-8);
}

.discussion-new-post {
background-color: var(--rosalution-grey-50);
border-radius: var(--content-border-radius);
margin-top: var(--p-8);
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
width: 100%;
}

.discussion-new-post-text-area {
background-color: var(--rosalution-white);
border-radius: var(--content-border-radius);
border: solid;
border-color: var(--rosalution-grey-000);
padding: var(--p-16);
margin: var(--p-10);
position: relative;
width: 100%;
}

.discussion-actions {
width: 100%;
display: flex;
justify-content: right;
margin-right: var(--p-16);
}

.collapsable-icon {
color: var(--rosalution-grey-200);
cursor: pointer;
Expand All @@ -51,5 +130,4 @@ input[type="checkbox"] {
input[type="checkbox"]:checked ~ .rosalution-section-header > span ~ label.collapsable-icon {
transform: scaleY(-1);
}

</style>
9 changes: 9 additions & 0 deletions frontend/src/models/analyses.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,16 @@ export default {
const success = await Requests.putForm(url, attachmentForm);
return success;
},
async postNewDiscussionThread(analysisName, postContent) {
const url = `/rosalution/api/analysis/${analysisName}/discussions`;

const attachmentForm = {
'discussion_content': postContent,
};

const success = await Requests.postForm(url, attachmentForm);
return success;
},
};

const annotationRenderingTemporary = [
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/stores/authStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ const authStore = {
getUsername() {
return this.state.username;
},
getClientId() {
return this.state.clientId;
},
hasWritePermissions() {
return this.hasRole('write');
},
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/styles/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ html {
--p-28: 1.75rem;

scroll-padding-top: 4rem;


}

/** || General Styles **/
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/views/AnalysisView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
/>
<DiscussionSection
id="Discussion"
:discussions="this.discussions"
@discussion:new-post="this.addDiscussionPost"
/>
<SupplementalFormList
id="Supporting_Evidence"
Expand Down Expand Up @@ -205,6 +207,9 @@ export default {
attachments() {
return this.analysis.supporting_evidence_files;
},
discussions() {
return this.analysis.discussions;
},
genomicUnitsList() {
return this.analysis.genomic_units;
},
Expand Down Expand Up @@ -605,7 +610,11 @@ export default {
await notificationDialog.title('Failure').confirmText('Ok').alert(error);
}
},
async addDiscussionPost(newPostContent) {
const discussions = await Analyses.postNewDiscussionThread(this.analysis['name'], newPostContent);

this.analysis.discussions = discussions;
},
copyToClipboard(copiedText) {
toast.success(`Copied ${copiedText} to clipboard!`);
},
Expand Down
23 changes: 23 additions & 0 deletions frontend/test/components/AnalysisView/DiscussionPost.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {it, expect, describe, beforeEach} from 'vitest';
import {shallowMount} from '@vue/test-utils';

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

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

beforeEach(() => {
wrapper = shallowMount(DiscussionPost, {
global: {
components: {
'font-awesome-icon': FontAwesomeIcon,
},
},
});
});

it('Vue instance exists and it is an object', () => {
expect(typeof wrapper).toBe('object');
});
});
Loading