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

Adding context menu to discussion posts #156

2 changes: 1 addition & 1 deletion backend/src/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ class User(BaseModel):
full_name: Optional[str] = None
disabled: Optional[bool] = None
scope: Optional[str] = None
client_id: str


class AccessUserAPI(User):
""" This extends the user class to include the user's credentials for API access """
client_id: str
client_secret: Optional[str] = None


Expand Down
61 changes: 52 additions & 9 deletions frontend/src/components/AnalysisView/DiscussionPost.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
<template>
<div class="discussion-post" data-test="discussion-post">
<div class="discussion-header" data-test="discussion-post-header">
<div>
<b>{{ author_name }}</b>
{{ timestamp }}
</div>
<ul v-if="isUser" class="context-menu" data-test="discussion-post-context-menu">
<ContextMenu :actions="actions" :context_id="id">
<font-awesome-icon class="header-icon" icon="ellipsis-vertical" size="xl" />
</ContextMenu>
</ul>
</div>
<div class="discussion-content" data-test="discussion-post-content">
{{ content }}
Expand All @@ -11,8 +18,13 @@
</template>

<script>
import ContextMenu from '@/components/ContextMenu.vue';

export default {
name: 'discussion-post',
components: {
ContextMenu,
},
props: {
id: {
type: String,
Expand Down Expand Up @@ -41,38 +53,69 @@ export default {
return [];
},
},
userClientId: {
type: String,
},
actions: {
type: Array,
},
},
computed: {
timestamp: function() {
return new Date(this.publish_timestamp).toUTCString();
},
isUser: function() {
return this.userClientId == this.author_id;
},
},
};
</script>

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

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);
background-color: var(--rosalution-grey-50);
}

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

.discussion-header {
margin-top: var(--p-5);
margin-bottom: var(--p-5);
display: flex;
justify-content: space-between;
margin-top: var(--p-5);
margin-bottom: var(--p-5);
}

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

.fill {
width: 100%;
}

.context-menu {
display:flex;
flex-wrap: nowrap;
justify-content: right;
margin-right: var(--p-10);
}

.actions-menu > li {
float: left;
}

.header-icon {
color: var(--rosalution-purple-300);
cursor: pointer;
padding: var(--p-5)
}

</style>
79 changes: 45 additions & 34 deletions frontend/src/components/AnalysisView/DiscussionSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,43 @@
</div>
<div class="rosalution-section-seperator"></div>
<div class="section-content">
<div v-if="this.showNewPost" 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 publish-button"
@click="newDiscussionPost"
data-test="new-discussion-publish"
:disabled="this.checkPostContent"
>
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 v-if="this.showNewPost" 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 publish-button"
@click="newDiscussionPost"
data-test="new-discussion-publish"
:disabled="this.checkPostContent"
>
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"
:userClientId="userClientId"
:actions="actions"
/>
</div>
</div>
</template>
Expand All @@ -75,6 +77,15 @@ export default {
return [];
},
},
userClientId: {
type: String,
},
actions: {
type: Array,
default: () => {
return [];
},
},
},
data: function() {
return {
Expand Down
85 changes: 85 additions & 0 deletions frontend/src/components/ContextMenu.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<template>
<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)">
<span> {{ action.text }} </span>
<font-awesome-icon v-if="action.icon" :icon="action.icon" size="lg" class="right-side-icon" />
</li>
</ul>
</li>
</template>

<script>
export default {
name: 'context-menu',
props: {
actions: {
type: Array,
validator: (prop) => prop.every(
(action) => action.text !== undefined || action.divider,
),
},
context_id: String,
},
methods: {
runAction(actionOperation) {
actionOperation(this.context_id);
this.closeContext();
},
closeContext() {
this.$refs.contextRef.blur();
},
},
};
</script>

<style scoped>
hr {
border: 1px solid var(--rosalution-grey-100);
}

.grey-rounded-menu {
border-radius: var(--content-border-radius);
background-color: var(--rosalution-white);
border: 3px solid var(--rosalution-grey-000);
width: 175px;
padding: .75rem;
margin-right: var(--p-16)
}

ul li ul {
visibility: hidden;
opacity: 0;
position: absolute;
transition: all 0.5s ease;
right: 0;
display: none;
}

ul li ul:hover li:hover {
color: var(--rosalution-purple-300);
background-color: var(--rosalution-purple-100);
}

ul li ul li {
clear: both;
width: 100%;
line-height: 2rem;
}

li:focus ul {
visibility: visible;
opacity: 1;
display: block;
}

.drop-down-content {
text-align: right;
}

.right-side-icon {
margin-left: var(--p-8);
margin-bottom: 0.12rem;
}
</style>
2 changes: 1 addition & 1 deletion frontend/src/components/RosalutionHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
</router-link>
</drop-down-menu>
<drop-down-menu v-if="actionsExist" :actions="actions" data-test="user-menu">
<font-awesome-icon class="header-icon" icon="ellipsis-vertical" size="xl" />
<font-awesome-icon class="header-icon" icon="bars" size="xl" />
</drop-down-menu>
</ul>
</div>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
faAsterisk, faPause, faCheck, faX, faUser, faUsers, faUserGroup, faCalendar, faBookOpen, faList, faLayerGroup,
faBoxArchive, faQuestion, faClock, faClipboardCheck, faMagnifyingGlass, faChevronDown, faChevronRight,
faUpRightFromSquare, faCirclePlus, faPencil, faEllipsisVertical, faLink, faXmark, faUserDoctor, faPaperclip, faPlus,
faAnglesRight, faFileImage, faFileCirclePlus, faMountainSun, faArrowUp, faArrowDown,
faAnglesRight, faFileImage, faFileCirclePlus, faMountainSun, faArrowUp, faArrowDown, faCaretDown, faBars,
} from '@fortawesome/free-solid-svg-icons';
import {
faCopy, faFile, faComment, faCircleCheck, faCircleQuestion, faCircleXmark, faImages,
Expand All @@ -35,7 +35,7 @@ library.add(
faLayerGroup, faBoxArchive, faQuestion, faClock, faClipboardCheck, faChevronDown, faChevronRight,
faUpRightFromSquare, faCopy, faCirclePlus, faFile, faComment, faPencil, faEllipsisVertical, faLink, faXmark,
faUserDoctor, faPaperclip, faPlus, faAnglesRight, faCircleCheck, faCircleQuestion, faCircleXmark, faImages,
faFileImage, faFileCirclePlus, faMountainSun, faArrowUp, faArrowDown,
faFileImage, faFileCirclePlus, faMountainSun, faArrowUp, faArrowDown, faCaretDown, faBars,
);

// The NotFoundView should always be last because it's an ordered array.
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/stores/authStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ const authStore = {
this.state.username = user['username'];
this.state.email = user['email'];
this.state.roles.push(user['scope']);
this.state.clientId = user['client_id'];

user['client_id'] ? this.state.clientId = user['client_id'] : '';
user['client_secret'] ? this.state.clientSecret = user['client_secret'] : '';
},
getUser() {
Expand Down
21 changes: 20 additions & 1 deletion frontend/src/views/AnalysisView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
<DiscussionSection
id="Discussion"
:discussions="this.discussions"
:userClientId="auth.getClientId()"
:actions="this.discussionContextActions"
@discussion:new-post="this.addDiscussionPost"
/>
<SupplementalFormList
Expand Down Expand Up @@ -200,7 +202,24 @@ export default {

return actionChoices;
},

discussionContextActions() {
return [
{
icon: 'pencil',
text: 'Edit',
operation: (postId) => {
console.log(`Editing Discussion Post: ${postId}`);
},
},
{
icon: 'xmark',
text: 'Delete',
operation: (postId) => {
console.log(`Deleting Discussion Post: ${postId}`);
},
},
];
},
sectionsList() {
return this.analysis.sections;
},
Expand Down
Loading