Skip to content

Commit

Permalink
add UI for proposal review workflow (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
jashan-lco authored Jul 11, 2024
1 parent ec2208d commit d6507d0
Show file tree
Hide file tree
Showing 7 changed files with 572 additions and 2 deletions.
5 changes: 4 additions & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@
<b-navbar-nav>
<b-nav-item :to="{ name: 'home' }">Home</b-nav-item>
<b-nav-item :to="{ name: 'create' }">Submit Observation</b-nav-item>
<b-nav-item :to="{ name: 'proposals' }">Manage Proposals</b-nav-item>
<b-nav-item-dropdown text="Manage Proposals" right>
<b-dropdown-item :to="{ name: 'proposals' }">Your Proposals</b-dropdown-item>
<b-dropdown-item :to="{ name: 'proposalReviewDashboard' }">Reviews</b-dropdown-item>
</b-nav-item-dropdown>
<b-nav-item href="https://lco.global/observatory/tools/">Planning Tools</b-nav-item>
<b-nav-item :to="{ name: 'help' }">Help</b-nav-item>
<template v-if="userIsAuthenticated">
Expand Down
160 changes: 160 additions & 0 deletions src/components/SciApplicationReviews.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<template>
<b-container>
<b-table class="text-center" id="sciapplication-reviews-table" :items="data.results" :fields="fields" :busy="isBusy" show-empty striped responsive>
<template v-slot:table-busy>
<div class="text-center my-2"><i class="fa fa-spin fa-spinner" /> Loading...</div>
</template>
<template v-slot:empty>
<div>
No applications to review.
</div>
</template>
<template v-slot:head(mean_grade)="data">
<span v-b-tooltip.hover title="Mean of all grades from panelists for this proposal.">{{ data.label }}<sup><b-icon icon="question-octagon" ></b-icon></sup></span>
</template>

<template v-slot:head(is_primary_reviewer)="data">
<span v-b-tooltip.hover title="As the primary reviewer of a proposal, you can summarize all other panel reviews.">{{ data.label }}<sup><b-icon icon="question-octagon" ></b-icon></sup></span>
</template>

<template v-slot:head(is_secondary_reviewer)="data">
<span v-b-tooltip.hover title="As the secondary reviewer of a proposal, you can also summarize all other panel reviews.">{{ data.label }}<sup><b-icon icon="question-octagon" ></b-icon></sup></span>
</template>

<template v-slot:cell(title)="row">
<b-button variant="link" @click="row.toggleDetails" v-b-tooltip.hover title="Toggle Abstract" >{{ row.item.title }}</b-button>
</template>

<template #row-details="row">
<b-card border-variant="primary" header="Abstract" header-bg-variant="primary" header-text-variant="white">
<b-card-text class="text-left">{{ row.item.abstract || 'N/A' }}</b-card-text>
</b-card>
</template>

<template v-slot:cell(pdf)="data">
<div v-if="data.item.pdf_url !== null">
<b-avatar
icon="file-text-fill"
variant="primary"
size="2em"
v-b-tooltip.hover
title="PDF"
:href="data.item.pdf_url"
>
</b-avatar>
</div>
<div v-else> - </div>
</template>

<template v-slot:cell(mean_grade)="data">
<b-icon
v-if="data.item.status === 'AWAITING_REVIEWS'"
icon="eye-slash-fill"
variant="dark"
size="2em"
title="Hidden until panel discussions have started"
></b-icon>
<span v-else>{{ data.item.mean_grade || '-' }}</span>
</template>

<template v-slot:cell(panel_review)="data">
<b-icon
v-if="data.item.status === 'AWAITING_REVIEWS'"
icon="eye-slash-fill"
variant="dark"
size="2em"
title="Hidden until panel discussions have started"
></b-icon>
<b-avatar
v-else
badge
badge-bottom badge-offset="-2px"
:badge-variant="data.item.completed ? 'success' : 'warning'"
icon="people-fill"
variant="primary"
size="2em"
title="View all panel reviews."
:to="{ name: 'proposalReviewPanelDetail', params: { id: data.item.id } }"
></b-avatar>
</template>

<template v-slot:cell(review)="data">
<b-avatar
icon="person-lines-fill"
variant="primary"
size="2em"
title="Make changes to your review."
:to="{ name: 'proposalReviewUserDetail', params: { id: data.item.id } }"
>
</b-avatar>
</template>

<template v-slot:cell(my_review.finished)="data">
<b-icon v-if="data.item.my_review && data.item.my_review.finished" icon="check-circle-fill" variant="success"></b-icon>
</template>

<template v-slot:cell(is_primary_reviewer)="data">
<b-icon v-if="data.item.is_primary_reviewer" icon="check-circle-fill" variant="success"></b-icon>
</template>

<template v-slot:cell(is_secondary_reviewer)="data">
<b-icon v-if="data.item.is_secondary_reviewer" icon="check-circle-fill" variant="success"></b-icon>
</template>

</b-table>

<ocs-pagination
v-if="!isBusy"
table-id="sciapplication-reviews-table"
:per-page="queryParams.limit"
:total-rows="data.count"
:current-page="currentPage"
@pageChange="onPageChange"
@limitChange="onLimitChange"
>
</ocs-pagination>
</b-container>
</template>
<script>
import { OCSMixin } from 'ocs-component-lib';
import { clearAndSetErrorsMixin } from '@/components/util/utilMixins.js';
export default {
name: 'SciApplicationReviews',
mixins: [OCSMixin.paginationAndFilteringMixin, clearAndSetErrorsMixin],
data: function() {
return {
fields: [
{ key: 'title', label: 'Proposal', tdClass: 'align-middle' },
{ key: 'semester', label: 'Semester', tdClass: 'align-middle' },
{ key: 'science_category', label: 'Category', tdClass: 'align-middle' },
{ key: 'pdf', label: 'PDF', tdClass: 'align-middle' },
{ key: 'mean_grade', label: 'Mean Grade', tdClass: 'align-middle' },
{ key: 'panel_review', label: 'Panel Reviews', tdClass: 'align-middle' },
{ key: 'review', label: 'Review', tdClass: 'align-middle' },
{ key: 'my_review.grade', label: 'Grade', tdClass: 'align-middle' },
{ key: 'my_review.finished', label: 'Finished', tdClass: 'align-middle' },
{ key: 'is_primary_reviewer', label: 'Primary', tdClass: 'align-middle' },
{ key: 'is_secondary_reviewer', label: 'Secondary', tdClass: 'align-middle' }
]
};
},
computed: {
observationPortalApiUrl: function() {
return this.$store.state.urls.observationPortalApi;
}
},
methods: {
initializeDataEndpoint: function() {
return this.$store.state.urls.observationPortalApi + '/api/scienceapplication-reviews/';
},
onSuccessfulDataRetrieval: function() {
this.clearErrors();
},
onErrorRetrievingData: function(response) {
this.setErrorsOnFailedAJAXCall(response);
}
}
};
</script>
3 changes: 2 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import { BootstrapVue, BIcon, BIconStickies } from 'bootstrap-vue';
import { BootstrapVue, BIcon, BIconStickies, BootstrapVueIcons } from 'bootstrap-vue';
import 'bootstrap';
import '@/assets/scss/app.scss';
import $ from 'jquery';
Expand All @@ -19,6 +19,7 @@ import 'katex/dist/katex.min.css';

Vue.use(VueCompositionAPI);
Vue.use(BootstrapVue);
Vue.use(BootstrapVueIcons);
Vue.component('BIcon', BIcon);
Vue.component('BIconStickies', BIconStickies);
Vue.use(OCSComponentLib);
Expand Down
32 changes: 32 additions & 0 deletions src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import Observations from '../views/Observations.vue';
import ObservationDetail from '../views/ObservationDetail.vue';
import Compose from '../views/Compose.vue';
import ProposalList from '../views/ProposalList.vue';
import ProposalReviewDashboard from '../views/ProposalReviewDashboard.vue';
import ProposalReviewUserDetail from '../views/ProposalReviewUserDetail.vue';
import ProposalReviewPanelDetail from '../views/ProposalReviewPanelDetail.vue';
import ProposalDetail from '../views/ProposalDetail.vue';
import SemesterDetail from '../views/SemesterDetail.vue';
import SemesterDetailCurrent from '../views/SemesterDetailCurrent.vue';
Expand Down Expand Up @@ -49,6 +52,35 @@ const routes = [
title: 'Help'
}
},
{
path: '/proposal-reviews',
name: 'proposalReviewDashboard',
component: ProposalReviewDashboard,
meta: {
title: 'Proposal Reviews',
requiresAuth: true
}
},
{
path: '/proposal-reviews/:id/my-review',
name: 'proposalReviewUserDetail',
props: true,
component: ProposalReviewUserDetail,
meta: {
title: 'Edit Your Proposal Review',
requiresAuth: true
}
},
{
path: '/proposal-reviews/:id/panel',
name: 'proposalReviewPanelDetail',
props: true,
component: ProposalReviewPanelDetail,
meta: {
title: 'Panel Proposal Reviews',
requiresAuth: true
}
},
{
path: '/proposals',
name: 'proposals',
Expand Down
23 changes: 23 additions & 0 deletions src/views/ProposalReviewDashboard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<b-container>
<b-row>
<h2>Proposal Reviews</h2>
</b-row>
<b-row>
<p>Here you can grade and comment on the proposals assigned to you.</p>
</b-row>
<b-row>
<sci-application-reviews></sci-application-reviews>
</b-row>
</b-container>
</template>
<script>
import SciApplicationReviews from '@/components/SciApplicationReviews.vue';
export default {
name: 'ProposalReviewDashboard',
components: {
SciApplicationReviews,
}
};
</script>
Loading

0 comments on commit d6507d0

Please sign in to comment.