Skip to content
Snippets Groups Projects
Commit bd0ba007 authored by moon's avatar moon
Browse files

Merge branch 'user_interaction' into develop

# Conflicts:
#	web/src/components/js/const.js
parents e961567e a25fa6a1
No related branches found
No related tags found
No related merge requests found
Showing
with 923 additions and 66 deletions
'use strict';
/**
* update-item controller
*/
const { createCoreController } = require('@strapi/strapi').factories;
module.exports = createCoreController('api::update-item.update-item', ({ strapi }) => ({
async create(ctx) {
ctx.request.body.data.submittedBy = ctx.state.user;
ctx.request.body.data.SubmittedAt = new Date();
return super.create(ctx);
},
async update(ctx) {
// console.log(ctx.state.user.role.name);
let response;
switch (ctx.state.user.role.name) {
case 'Public':
case 'Authenticated':
case 'Contributor':
// Remove operation should be intact
if (ctx.request.body.data.submittedBy.id !== ctx.state.user.id) {
const sanitizedEntity = await this.sanitizeOutput(null, ctx);
response = this.transformResponse(sanitizedEntity);
} else {
ctx.request.body.data.updatedBy = ctx.state.user.id;
ctx.request.body.data.UpdateSubmissionTimestamp = new Date();
response = await super.update(ctx);
}
break;
case 'Maintainer':
case 'Administrator':
// Handle the review comment and
// If ReviewAt field is null, should be set. Otherwise it continues;
// Apply review operation
// const entity = await strapi.service('api::update-item.update-item').findOne(ctx.params.id);
// console.log(entity);
ctx.request.body.data.updatedBy = ctx.state.user.id;
ctx.request.body.data.UpdateSubmissionTimestamp = new Date();
response = await super.update(ctx);
break;
}
return response;
},
// This updateReview function is called by only either Maintainer or Administrator
async updateReview(ctx) {
// console.log('update info')
let response;
switch (ctx.state.user.role.name) {
case 'Public':
case 'Authenticated':
case 'Contributor':
// Remove operation should be intact
const sanitizedEntity = await this.sanitizeOutput(null, ctx);
response = this.transformResponse(sanitizedEntity);
break;
case 'Maintainer':
case 'Administrator':
// Handle the review comment and
// If ReviewAt field is null, should be set. Otherwise it continues;
// Apply review operation
// const entity = await strapi.service('api::update-item.update-item').findOne(ctx.params.id);
// console.log(entity);
const now = new Date();
if (ctx.request.body.data.ReviewedAt === null) {
ctx.request.body.data.ReviewedAt = now;
}
ctx.request.body.data.reviewedBy = ctx.state.user.id;
ctx.request.body.data.UpdateReviewTimestamp = now;
response = await super.update(ctx);
break;
}
return response;
},
async find(ctx) {
// console.log(ctx.state.user.role.name);
ctx.query['populate'] = ['submittedBy', 'reviewedBy'];
switch (ctx.state.user.role.name) {
case 'Public':
case 'Authenticated':
case 'Contributor':
// Remove operation should be intact
ctx.query['filters'] = { submittedBy: ctx.state.user.id };
break;
case 'Maintainer':
case 'Administrator':
// Handle the review comment and
// If ReviewAt field is null, should be set. Otherwise it continues;
// Apply review operation
// const entity = await strapi.service('api::update-item.update-item').findOne(ctx.params.id);
// console.log(entity);
break;
}
// console.log(ctx.query)
return super.find(ctx)
},
async findOne(ctx) {
// console.log(ctx);
const { id } = ctx.params;
const { query } = ctx;
query['populate'] = ['submittedBy', 'reviewedBy'];
let entity = await strapi.service("api::update-item.update-item").findOne(id, query);
// console.log(entity);
switch (ctx.state.user.role.name) {
case 'Public':
case 'Authenticated':
case 'Contributor':
if (entity.submittedBy === null || entity.submittedBy.id !== ctx.state.user.id) {
entity = null;
}
break;
case 'Maintainer':
case 'Administrator':
break;
}
const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
return this.transformResponse(sanitizedEntity);
}
}));
module.exports = {
routes: [
{
method: 'PUT',
path: '/update-item/review/:id',
handler: 'api::update-item.update-item.updateReview',
},
]
}
'use strict';
/**
* update-item router.
*/
const { createCoreRouter } = require('@strapi/strapi').factories;
module.exports = createCoreRouter('api::update-item.update-item');
'use strict';
/**
* update-item service.
*/
const { createCoreService } = require('@strapi/strapi').factories;
module.exports = createCoreService('api::update-item.update-item');
{
"kind": "collectionType",
"collectionName": "up_users",
"info": {
"name": "user",
"description": "",
"singularName": "user",
"pluralName": "users",
"displayName": "User"
},
"options": {
"draftAndPublish": false,
"timestamps": true
},
"attributes": {
"username": {
"type": "string",
"minLength": 3,
"unique": true,
"configurable": false,
"required": true
},
"email": {
"type": "email",
"minLength": 6,
"configurable": false,
"required": true
},
"provider": {
"type": "string",
"configurable": false
},
"password": {
"type": "password",
"minLength": 6,
"configurable": false,
"private": true
},
"resetPasswordToken": {
"type": "string",
"configurable": false,
"private": true
},
"confirmationToken": {
"type": "string",
"configurable": false,
"private": true
},
"confirmed": {
"type": "boolean",
"default": false,
"configurable": false
},
"blocked": {
"type": "boolean",
"default": false,
"configurable": false
},
"role": {
"type": "relation",
"relation": "manyToOne",
"target": "plugin::users-permissions.role",
"inversedBy": "users",
"configurable": false
},
"Affiliation": {
"type": "string"
},
"ProfileLink": {
"type": "string"
},
"SubmittedUpdateItems": {
"type": "relation",
"relation": "oneToMany",
"target": "api::update-item.update-item",
"mappedBy": "submittedBy"
},
"ReviewedUpdateItems": {
"type": "relation",
"relation": "oneToMany",
"target": "api::update-item.update-item",
"mappedBy": "reviewedBy"
}
}
}
'use strict';
module.exports = {
/**
* An asynchronous register function that runs before
* your application is initialized.
*
* This gives you an opportunity to extend code.
*/
register(/*{ strapi }*/) {},
/**
* An asynchronous bootstrap function that runs before
* your application gets started.
*
* This gives you an opportunity to set up your data model,
* run jobs, or perform some special logic.
*/
bootstrap(/*{ strapi }*/) {},
};
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
"@amcharts/amcharts4": "^4.6.9", "@amcharts/amcharts4": "^4.6.9",
"@geneontology/ribbon": "^1.11.2", "@geneontology/ribbon": "^1.11.2",
"@johmun/vue-tags-input": "2.0.1", "@johmun/vue-tags-input": "2.0.1",
"autoprefixer": "^9",
"clipboard": "^2.0.6", "clipboard": "^2.0.6",
"core-js": "^3.4.3", "core-js": "^3.4.3",
"cytoscape": "^3.2.22", "cytoscape": "^3.2.22",
...@@ -23,8 +24,12 @@ ...@@ -23,8 +24,12 @@
"jquery": "^3.4.1", "jquery": "^3.4.1",
"lodash": "^4.17.15", "lodash": "^4.17.15",
"plotly.js": "~1.33.1", "plotly.js": "~1.33.1",
"postcss": "^7",
"tailwindcss": "npm:@tailwindcss/postcss7-compat",
"vue": "^2.6.10", "vue": "^2.6.10",
"vue-axios": "^3.4.0",
"vue-markdown": "^2.2.4", "vue-markdown": "^2.2.4",
"vue-progress-path": "^0.0.2",
"vue-router": "^3.1.3", "vue-router": "^3.1.3",
"vue-simple-suggest": "^1.10.3", "vue-simple-suggest": "^1.10.3",
"vuera": "^0.2.6", "vuera": "^0.2.6",
......
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}
\ No newline at end of file
<template>
<div>
<slot :response="response" :loading="loading"></slot>
</div>
</template>
<script>
// require modules
const _ = require('lodash');
let host = require('../js/const').apiHost;
export default {
name: "fetchProfile",
data() {
return {
loading: true,
response: '',
isDev: process.env.NODE_ENV === 'development'
}
},
computed: {
jwt: function () {
return this.$store.getters['User/jwt']
},
},
methods: {
getItems() {
const vm = this;
// console.log(host)
if(vm.isDev) {
host = require('../js/const').devApiHost;
}
// console.log(vm.isExperimental)
let url = `${host}/api/users/me`;
const jwt = vm.jwt;
if(jwt === null) {
vm.loading = false;
vm.response = null;
return
}
fetch(url, {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
headers: {
Authorization: `Bearer ${jwt}`
}
})
.then(response => response.json())
.then((response) => {
// /* eslint-disable no-console */
//console.log(response);
setTimeout(() => {
vm.loading = false;
vm.response = response
}, 10);
});
}
},
mounted() {
const vm = this
// /* eslint-disable no-console */
// console.log(vm.locus);
vm.getItems();
},
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div>
<slot :response="response" :loading="loading"></slot>
</div>
</template>
<script>
// require modules
const _ = require('lodash');
let host = require('../js/const').apiHost;
export default {
name: "fetchUpdateItems",
data() {
return {
loading: true,
response: '',
isDev: process.env.NODE_ENV === 'development'
}
},
computed: {
jwt: function () {
return this.$store.getters['User/jwt']
},
},
methods: {
getItems() {
const vm = this;
// console.log(host)
if(vm.isDev) {
host = require('../js/const').devApiHost;
}
// console.log(vm.isExperimental)
const qs = require('qs');
const query = qs.stringify({
sort: ['id:asc'],
pagination: {
pageSize: 1000,
page: 1,
},
}, {
encodeValuesOnly: true,
});
let url = `${host}/api/update-items?${query}`;
const jwt = vm.jwt;
if(jwt === null) {
vm.loading = false;
vm.response = null;
return
}
fetch(url, {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
headers: {
Authorization: `Bearer ${jwt}`
}
})
.then(response => response.json())
.then((response) => {
// /* eslint-disable no-console */
// console.log(response);
setTimeout(() => {
vm.loading = false;
vm.response = response
}, 10);
});
}
},
mounted() {
const vm = this
// /* eslint-disable no-console */
// console.log(vm.locus);
vm.getItems();
},
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div>
<slot :response="response" :loading="loading"></slot>
</div>
</template>
<script>
// require modules
const _ = require('lodash');
let host = require('../js/const').apiHost;
export default {
name: "fetchUsers",
data() {
return {
loading: true,
response: '',
isDev: process.env.NODE_ENV === 'development'
}
},
computed: {
jwt: function () {
return this.$store.getters['User/jwt']
},
},
methods: {
async getItems() {
const vm = this;
// console.log(host)
if(vm.isDev) {
host = require('../js/const').devApiHost;
}
// console.log(vm.isExperimental)
let url = `${host}/api/users`;
const jwt = vm.jwt;
if(jwt === null) {
vm.loading = false;
vm.response = null;
return
}
const response= await fetch(url, {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
headers: {
Authorization: `Bearer ${jwt}`
}
})
const responseData= await response.json()
vm.loading = false;
vm.response = responseData;
}
},
mounted() {
const vm = this
// /* eslint-disable no-console */
// console.log(vm.locus);
vm.getItems();
},
}
</script>
<style scoped>
</style>
\ No newline at end of file
...@@ -50,14 +50,54 @@ ...@@ -50,14 +50,54 @@
Encyclopedia Encyclopedia
</router-link> </router-link>
</li> </li>
<li v-show="userData !== null" role="presentation" v-bind:class="{ active: $route.name === 'profile' }">
<router-link to="/profile">
Profile
</router-link>
</li>
<li v-show="userData !== null" role="presentation">
<router-link to="/login" v-on:click.native="signOut">
<span class="fa fa-sign-out"/>
</router-link>
</li>
<li v-show="userData === null" role="presentation" v-bind:class="{ active: $route.name === 'login' }">
<router-link to="/login">
Login
</router-link>
</li>
</ul> </ul>
</template> </template>
<script> <script>
export default { export default {
name: "Links", name: "Links",
data() {
return {
// userData: this.$store.getters['User/userData']
}
},
methods: {
signOut() {
const vm = this
window.localStorage.removeItem('jwt');
window.localStorage.removeItem('userData');
vm.$store.dispatch('User/logOut')
vm.$router.push('/login')
}
},
computed: {
userData: function () {
return this.$store.getters['User/userData']
},
},
mounted: function () { mounted: function () {
const vm = this
// console.log(vm.userData)
// console.log(this.$route.name) // console.log(this.$route.name)
if(vm.userData !== null) {
vm.$router.push('/profile')
}
} }
} }
</script> </script>
\ No newline at end of file
<template> <template>
<protein-detail-page-detail-page proteinId="A0A1I9LRM4"> <protein-detail-page proteinId="A0A1I9LRM4">
</protein-detail-page-detail-page> </protein-detail-page>
</template> </template>
<script> <script>
import ProteinDetailPageDetailPage from '@/components/ProteinDetailPage.vue' import ProteinDetailPage from '@/components/ProteinDetailPage.vue'
export default { export default {
name: "ProteinExample", name: "ProteinExample",
components: { components: {
ProteinDetailPageDetailPage ProteinDetailPage
}, },
mounted: function () { mounted: function () {
// console.log(this.$route.name) // console.log(this.$route.name)
......
<template>
<div class="flex items-center justify-center panel-table w-full md:w-auto pt-10">
<table :id=id class="table table-striped table-bordered table-hover"></table>
</div>
</template>
<script>
const _ = require('lodash');
const $ = window.jQuery = require('jquery');
require('@/components/js/datatable');
let table;
export default {
name: 'update-item-table',
props: ['id', 'data'],
data() {
return {
};
},
methods: {
editUpdateItem(id) {
// eslint-disable-next-line
this.$router.push('/updateitem/' + id)
},
createTable(id, data) {
const vm = this;
_.forEach(data, (d) => {
d.DT_RowID = `${d.id}`;
});
const columns = [
{
title: 'ID',
data: 'id',
fnCreatedCell: (nTd, sData, oData) => {
$(nTd).html(`<a href="" class="edit-link"> ${sData}</a>`);
},
},
{
title: 'Resource Name',
data: 'attributes.Entity',
},
{
title: 'Resource ID',
data: 'attributes.EntityId',
},
{
title: 'Attribute',
data: 'attributes.Attribute',
},
{
title: 'Value',
data: 'attributes.Value',
},
{
title: 'Change Operation',
data: 'attributes.ChangeOperation',
},
{
title: 'Status',
data: 'attributes.Status',
},
{
title: 'Submitted at',
data: 'attributes.SubmittedAt',
render: function ( data, type, row, meta ) {
return new Date(Date.parse(data)).toLocaleString();
},
},
{
title: 'Submitted by',
data: 'attributes.submittedBy',
render: function ( data, type, row, meta ) {
if(data.data) {
return data.data.attributes.username
} else {
return '';
}
},
},
{
title: 'Reviewer',
data: 'attributes.reviewedBy',
render: function ( data, type, row, meta ) {
if(data.data) {
return data.data.attributes.username
} else {
return '';
}
},
}];
const nTableOptions = {
columns,
// aaSorting: [[ 0, 'asc' ]],
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]],
paging: true,
searching: true,
info: false,
data,
order: [], // order: [[0, 'asc']],
bDestroy: true, // Add this property to new setting,
oLanguage: {
sSearch: "Filter",
},
dom: '<"row"<"col-sm-2"l><"col-sm-2"f><"col-sm-8"p>><"row"t><"row"<"col-sm-4"i><"col-sm-8"p>>'
};
const tableId = `#${id}`;
if (table) {
table.destroy();
$(tableId).empty();
}
table = $(tableId).DataTable(nTableOptions);
const tableBody = `${tableId} tbody`;
$(tableBody).on('click', 'tr td a.edit-link', (e) => {
e.preventDefault()
const tr = $(e.target).parent().parent();
const row = table.row(tr);
vm.editUpdateItem(row.data().id);
});
},
exportTsv() {
// const vm = this;
},
},
mounted() {
const vm = this;
vm.createTable(vm.id, vm.data);
},
};
</script>
<style scoped>
@import url('~@/assets/datatable.css');
select.form-control {
font-size: 12px;
padding: 3px 12px;
}
ul.pagination {
font-size: 1rem;
}
.form-inline .form-control {
height: 25px;
line-height: 25px;
vertical-align: middle;
}
.edit-link {
font-weight: bold;
color: #0065b9;
}
.pagination {
font-size: 1.2rem;
}
.panel-table {
font-size: 1.4rem;
margin-bottom: 20px;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, .05);
border-radius: 4px;
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
}
</style>
<template>
<div class="flex items-center justify-center panel-table w-full md:w-auto pt-10">
<table :id=id class="table table-striped table-bordered table-hover" width="100%"></table>
</div>
</template>
<script>
const _ = require('lodash');
const $ = window.jQuery = require('jquery');
require('@/components/js/datatable');
let table;
export default {
name: 'user-table',
props: ['id', 'data'],
methods:{
createTable(id, data) {
const vm = this;
_.forEach(data, (d) => {
d.DT_RowID = `${d.id}`;
});
const columns = [
{
title: 'ID',
data: 'id',
fnCreatedCell: (nTd, sData, oData) => {
$(nTd).html(`<a href="" class="edit-link"> ${sData}</a>`);
},
},
{
title: 'Name',
data: 'username',
},
{
title: 'Email',
data: 'email',
},
{
title: 'Affiliation',
data: 'Affiliation',
},
{
title: 'Profile Link',
data: 'ProfileLink',
},
{
title: 'Joined',
data: 'createdAt',
},
{
title: 'Updated',
data: 'updatedAt',
},
{
title: 'Status',
data: 'confirmed',
},
];
const nTableOptions = {
columns,
// aaSorting: [[ 0, 'asc' ]],
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]],
paging: true,
searching: true,
info: false,
data,
order: [], // order: [[0, 'asc']],
bDestroy: true, // Add this property to new setting,
oLanguage: {
sSearch: "Filter",
},
dom: '<"row"<"col-sm-2"l><"col-sm-2"f><"col-sm-8"p>><"row"t><"row"<"col-sm-4"i><"col-sm-8"p>>'
};
const tableId = `#${id}`;
if (table) {
table.destroy();
$(tableId).empty();
}
table = $(tableId).DataTable(nTableOptions);
const tableBody = `${tableId} tbody`;
$(tableBody).on('click', 'tr td a.edit-link', (e) => {
e.preventDefault()
const tr = $(e.target).parent().parent();
const row = table.row(tr);
// vm.editUpdateItem(row.data().id);
});
},
},
mounted() {
const vm = this;
vm.createTable(vm.id, vm.data);
},
}
</script>
<style scoped>
@import url('~@/assets/datatable.css');
select.form-control {
font-size: 12px;
padding: 3px 12px;
}
ul.pagination {
font-size: 1rem;
}
.form-inline .form-control {
height: 25px;
line-height: 25px;
vertical-align: middle;
}
.edit-link {
font-weight: bold;
color: #0065b9;
}
.pagination {
font-size: 1.2rem;
}
.panel-table {
font-size: 1.4rem;
margin-bottom: 20px;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, .05);
border-radius: 4px;
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
}
</style>
\ No newline at end of file
/* ./src/main.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
\ No newline at end of file
...@@ -2,9 +2,18 @@ import Vue from 'vue' ...@@ -2,9 +2,18 @@ import Vue from 'vue'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
import store from './store' import store from './store'
import axios from 'axios'
import vueAxios from 'vue-axios'
import './index.css'
import { VuePlugin } from 'vuera' import { VuePlugin } from 'vuera'
import 'vue-progress-path/dist/vue-progress-path.css'
import VueProgress from 'vue-progress-path'
Vue.use(VuePlugin) Vue.use(VuePlugin)
Vue.use(vueAxios, axios)
Vue.use(VueProgress, {
// defaultShape: 'circle',
})
Vue.config.productionTip = false Vue.config.productionTip = false
new Vue({ new Vue({
......
...@@ -71,6 +71,36 @@ export default new Router({ ...@@ -71,6 +71,36 @@ export default new Router({
name: 'condensate', name: 'condensate',
component: () => import('@/components/CondensateDetailPage'), component: () => import('@/components/CondensateDetailPage'),
}, },
{
path: '/profile',
name: 'profile',
component: () => import('@/views/Profile'),
},
{
path: '/signup',
name: 'signup',
component: () => import('@/views/SignUp'),
},
{
path: '/login',
name: 'login',
component: () => import('@/views/Login'),
},
{
path: '/forgotpassword',
name: 'forgotPassword',
component: () => import('@/views/ForgotPassword'),
},
{
path: '/resetpassword',
name: 'resetPassword',
component: () => import('@/views/ResetPassword'),
},
{
path: '/updateitem/:item',
name: 'updateItem',
component: () => import('@/views/UpdateItem'),
},
// { path: '/user/:id', component: User }, // { path: '/user/:id', component: User },
// { // {
// path: '*', // path: '*',
......
const namespaced = true
const state = {
cutoff: 0.005,
pvalueCutoff: 0.001,
proteinList: [],
assays: ['appl'],
marker: 'All',
parameter: 'All'
}
const mutations = {
SET_CUT_OFF (state, cutoff) {
state.cutoff = cutoff
},
SET_P_VALUE_CUT_OFF (state, pvalue) {
state.pvalueCutoff = pvalue
},
SET_PROTEIN_LIST (state, proteinList) {
state.proteinList = proteinList
},
ADD_PROTEIN (state, protein) {
if(state.proteinList.findIndex(d => d.proteinId === protein.proteinId) <0) {
state.proteinList.push(protein)
}
},
REMOVE_PROTEIN (state, proteinIdx) {
state.proteinList.splice(proteinIdx, 1);
},
}
const getters = {
cutoff: state => state.cutoff,
pvalueCutoff: state => state.pvalueCutoff,
proteinList: state => state.proteinList,
}
const actions = {
setCutOff ({ commit }, cutoff) {
commit('SET_CUT_OFF', cutoff)
},
setPValueCutOff ({ commit }, pvalue) {
commit('SET_P_VALUE_CUT_OFF', pvalue)
},
setProteinList ({ commit }, proteinList) {
commit('SET_PROTEIN_LIST', proteinList)
},
addProtein ({ commit }, protein) {
commit('ADD_PROTEIN', protein)
},
removeProtein ({ commit }, protein) {
commit('REMOVE_PROTEIN', protein)
}
}
export default {
namespaced,
state,
mutations,
getters,
actions
}
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