ProteinDetailPage.vue 22.49 KiB
<template>
<div
class="flex flex-wrap justify-center"
>
<!-- Sidebar -->
<!--<div class="bg-light border-right" id="sidebar-wrapper">-->
<!--<!–<div class="sidebar-heading">Menu </div>–>-->
<!--<div class="list-group list-group-flush">-->
<!--<a href="#" class="list-group-item list-group-item-action bg-light">Search</a>-->
<!--<a href="#" class="list-group-item list-group-item-action bg-light">Columns</a>-->
<!--<a href="#" class="list-group-item list-group-item-action bg-light">Filters</a>-->
<!--<a href="#" class="list-group-item list-group-item-action bg-light">Download</a>-->
<!--<a href="#" class="list-group-item list-group-item-action bg-light">Contacts</a>-->
<!--</div>-->
<!--</div>-->
<!-- /#sidebar-wrapper -->
<div
class="w-5/6"
>
<!-- <base-toaster @close="hideDialog" :open="toasterIsOpen">
<p>This is a test roaster</p>
<button class="btn btn-outline" @click="hideDialog">Close</button>
</base-toaster> -->
<fetch-protein :protein="protein">
<template slot-scope="{ response, loading }">
<slot
:response="response"
:loading="loading"
>
<div v-if="loading">
<base-spinner v-if="loading" />
</div>
<div v-else-if="response !== null">
<h2>{{ response.data.gene_name }}</h2>
<h4 class="round">
General Information
</h4>
<div class="panel panel-default">
<div class="panel-body">
<div class="container-fluid col-md-12">
<div class="row">
<div class="text col-sm-3">
Name
</div>
<div class="col-sm-9">
<b>Protein {{ response.data.name }}</b>
</div>
</div>
<div class="row">
<div class="text col-sm-3">
Species
</div>
<div class="col-sm-9">
{{
response.data.species_name +
" (" +
response.data.species_tax_id +
")"
}}
</div>
</div>
<div class="row">
<div class="text col-sm-3">
Ensembl ID
</div>
<div class="col-sm-9">
<div v-if="response.data.ensembl_id">
<a
:href="
'https://www.ensembl.org/id/' +
response.data.ensembl_id
"
class="uniprot-link"
target="_blank"
>
{{ response.data.ensembl_id }}
<i class="glyphicon glyphicon-link" /></a>
</div>
</div>
</div>
<div class="row">
<div class="text col-sm-3">
Ensembl Gene ID
</div>
<div class="col-sm-9">
<div v-if="response.data.ensembl_gene_id">
<a
:href="
'https://www.ensembl.org/id/' +
response.data.ensembl_gene_id
"
class="uniprot-link"
target="_blank"
>
{{ response.data.ensembl_gene_id }}
<i class="glyphicon glyphicon-link" /></a>
</div>
</div>
</div>
<div class="row">
<div class="text col-sm-3">
UniProt
</div>
<div class="col-sm-9">
<div v-if="response.data.uniprot_id">
<a
:href="
'https://www.uniprot.org/uniprot/' +
response.data.uniprot_id
"
class="uniprot-link"
target="_blank"
>
{{
response.data.uniprot_id +
" (" +
response.data.uniprot_readable_id +
")"
}}
<i class="glyphicon glyphicon-link" /></a>
</div>
</div>
</div>
<div class="row">
<div class="text col-sm-3">
Antibodies
</div>
<div class="col-sm-9">
<div v-if="response.data.uniprot_id">
<a
:href="response.data.antibody_link"
class="uniprot-link"
target="_blank"
>
{{ response.data.uniprot_id }}
<i class="glyphicon glyphicon-link" /></a>
</div>
</div>
</div>
<div class="row">
<div class="text col-sm-3">
Functional Type
<a
class="
uniprot-link
tooltipped tooltipped-e tooltipped-multiline
"
aria-label="- Driver: A protein that undergoes phase separation or self assembles to form liquid droplets independent of other proteins, induces the formation of a condensate, or is essential for the integrity of a condensate. This protein is known to be a driver in at least one of the known condensates.
- Client: A protein that is part of a condensate, but is driven to the condensate by a driver protein. This protein is known to be a client in at least one of the known condensates, but never known to be a driver.
- Regulator: A protein that biochemically or enzymatically regulates the formation of a condensate, but is not a part of the condensate. This protein is never known to be a driver or client.
"
>
<span class="fa fa-info-circle" />
</a>
</div>
<div class="col-sm-9">
{{ response.data.functional_type }}
<button
v-if="
getUserData !== null &&
(getUserData === 'Maintainer' ||
getUserData === 'Contributor')
"
class="btn btn-primary btn-link"
@click="
showUpdateFunctionType = !showUpdateFunctionType
"
>
<font-awesome-icon
icon="fa-solid fa-pen-to-square fa-xl"
/>
</button>
<update-functional-type
v-if="showUpdateFunctionType"
:type="response.data.functional_type"
:data="response.data"
@update-key="updatedKey += 1"
@close="closeUpdateFunctionalType"
/>
</div>
</div>
<div class="row">
<div class="text col-sm-3">
Primary Datasource
</div>
<div class="col-sm-9">
{{ response.data.source_db_tags.join(", ") }}
</div>
</div>
<div
v-if="response.data.pubmed_ids"
class="row"
>
<div class="text col-sm-3">
Pubmed
</div>
<div class="col-sm-6">
<div>
<span
v-for="(item, index) in getPubMedIds(
response.data.pubmed_ids
)"
:key="index"
>
<a
:id="item"
:href="'https://pubmed.ncbi.nlm.nih.gov/' + item"
class="
uniprot-link
tooltipped tooltipped-n tooltipped-multiline
"
target="_blank"
@mouseover="fetchPubMedId(item)"
>
{{ item }}
<i class="glyphicon glyphicon-link" />
</a>
</span>
<button
v-if="
getUserData !== null &&
(getUserData === 'Maintainer' ||
getUserData === 'Contributor')
"
class="btn btn-primary btn-link"
@click="
showAddOrDeletePubmedId = !showAddOrDeletePubmedId
"
>
<font-awesome-icon
icon="fa-solid fa-pen-to-square fa-xl"
/>
</button>
<add-delete-pubmed
v-if="showAddOrDeletePubmedId"
:data="response.data"
mode="protein"
@update-key="updatedKey += 1"
@cancel="cancelAddOrDeletePubmedId"
/>
</div>
<div
id="more"
:class="{
active: response.data.pubmed_ids.length <= 7,
}"
>
<span
v-for="(item, index) in getMorePubIds(
response.data.pubmed_ids
)"
:key="index"
>
<a
:id="item"
:href="'https://pubmed.ncbi.nlm.nih.gov/' + item"
class="
uniprot-link
tooltipped tooltipped-n tooltipped-multiline
"
target="_blank"
@mouseover="fetchPubMedId(item)"
>
{{ item }}
<i class="glyphicon glyphicon-link" />
</a>
<br v-if="index % 7 === 6">
</span>
</div>
</div>
<div
v-show="response.data.pubmed_ids.length > 7"
class="col-sm-2"
>
<a
v-show="!shownMore.pub"
class="uniprot-link"
@click="showMore('#more', 'pub', response.length)"
><i
class="fa fa-angle-double-down"
aria-hidden="true"
style="color: royalblue"
/>
Show more</a>
<a
v-show="shownMore.pub"
class="uniprot-link"
@click="showLess('#more', 'pub')"
><i
class="fa fa-angle-double-up"
aria-hidden="true"
style="color: royalblue"
/>
Show less</a>
</div>
</div>
<div class="row">
<div class="text col-sm-3">
Sequence
</div>
<div class="col-sm-9">
<input
type="text"
:value="response.data.sequence"
>
<button
:id="'sequence'"
class="copy-button"
:name="'sequence'"
:data-clipboard-text="response.data.sequence"
>
<i class="glyphicon glyphicon-copy" />
</button>
</div>
</div>
</div>
</div>
</div>
<div v-if="response.data.iupred_score !== null">
<iu-pred2-chart
:x="response.data.sequence"
:score="response.data.iupred_score"
/>
</div>
<barcode-plot :x="response.data.sequence" />
<div
v-show="
response.data.llps_ptms !== null &&
response.data.llps_ptms.length > 0
"
>
<h4 class="round">
PTMs affecting condensate formation
</h4>
<div class="panel panel-default">
<table class="csi table table-hover table-responsive">
<thead>
<tr class="active">
<th>Name</th>
<th>Type</th>
<th>Enzyme</th>
<th>Position</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, index) in response.data.llps_ptms"
:key="index"
>
<td>{{ item.name }}</td>
<td>{{ item.effect_type }}</td>
<td class="text-nowrap">
{{ item.enzyme }}
</td>
<td>{{ item.position }}</td>
<td>{{ item.effect_description }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div
v-show="
response.data.condensates !== null &&
response.data.condensates.length > 0
"
class="my-14 border border-gray-300 rounded-lg p-8"
>
<h4 class="round">
Condensates
</h4>
<div class="panel panel-default">
<table class="csi table table-hover table-responsive">
<thead>
<tr class="active">
<th>Name</th>
<!--<th>Data Sources</th>-->
<th>No. of Proteins</th>
<!--<th>Evidence Stars</th>-->
<th>Species</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, index) in response.data.condensates"
:key="index"
>
<td>
<a
:href="'/condensate/' + item.canonical_id"
class="uniprot-link"
>{{ item.name }}</a>
</td>
<!--<td>{{getDbNames(item.data_sources)}}</td>-->
<td>{{ item.protein_count }}</td>
<!--<td>-->
<!--<span v-for="(item, index) in getSingleRating(item.data_sources)" :class="item" v-bind:key="index"/>-->
<!--</td>-->
<td>{{ item.species_name }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div
v-if="getUserData"
class="my-14 border border-gray-300 rounded-lg p-8"
>
<h4 class="round mb-8">
All submitted changes for this protein
</h4>
<protein-update-item-table
id="proteinUpdateTable"
:key="updatedKey"
:data="protein"
/>
</div>
</div>
</slot>
</template>
</fetch-protein>
</div>
</div>
<!-- /#wrapper -->
</template>
<script>
import fetchProtein from '@/components/DDCODE/fetchProtein.vue';
import IuPred2Chart from '@/components/IUPred2Chart';
import BarcodePlot from '@/components/BarcodePlot';
import UpdateFunctionalType from './CMS/updateFunctionalType.vue';
import AddDeletePubmed from './CMS/addDeletePubmed.vue';
//import FetchUserSpecificUpdateItems from './CMS/fetchUserSpecificUpdateItems.vue';
import ProteinUpdateItemTable from './ProteinUpdateItemTable.vue';
import BaseSpinner from './UI/BaseSpinner.vue';
//import BaseToaster from "./UI/BaseToaster.vue";
const $ = (window.jQuery = require('jquery'));
const _ = require('lodash');
require('./js/clipboard');
export default {
name: 'LandingPage',
components: {
fetchProtein,
IuPred2Chart,
BarcodePlot,
UpdateFunctionalType,
AddDeletePubmed,
ProteinUpdateItemTable,
BaseSpinner,
},
props: ['proteinId'],
data() {
return {
showUpdateFunctionType: false,
showAddOrDeletePubmedId: false,
shownMore: {
pub: false,
},
protein: this.$route.params.protein
? this.$route.params.protein
: this.proteinId,
dbNames: require('./js/const').db,
toasterIsOpen: false,
updatedKey: 0,
};
},
computed: {
getUserData() {
const userRole = this.$store.getters['User/userRole'];
// console.log('role is', userRole);
return userRole;
},
},
methods: {
showDialog() {
this.toasterIsOpen = true;
},
hideDialog() {
this.toasterIsOpen = false;
},
closeUpdateFunctionalType() {
this.showUpdateFunctionType = false;
},
cancelAddOrDeletePubmedId() {
this.showAddOrDeletePubmedId = false;
},
getPubMedIds(ids) {
let outIds = [];
ids.forEach((i, idx) => {
outIds.push(`${i}`);
});
return outIds.slice(0, 7);
},
getMorePubIds(ids) {
let outIds = [];
ids.forEach((i) => {
outIds.push(`${i}`);
});
return outIds.slice(7);
},
showLess(id, clazz) {
let $rows = $(id);
$rows.removeClass('active');
this.shownMore[clazz] = false;
},
showMore(id, clazz) {
let $rows = $(id);
$rows.addClass('active');
this.shownMore[clazz] = true;
},
getDbNames(names) {
return _.map(names, (i) => this.dbNames[i]).join(', ');
},
getTitleAuthors(title, data) {
return `${title}\n\n${_.map(data, (a) => a.name).join(', ')}`;
},
fetchPubMedId(item) {
const vm = this;
// console.log(item)
const url =
'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&retmode=json&id=';
const request = url + item;
let $row = $('#' + item);
if (!$row.attr('aria-label')) {
fetch(request)
.then((response) => response.json())
.then((response) => {
setTimeout(() => {
const res = response.result[item];
$row.attr(
'aria-label',
vm.getTitleAuthors(res.title, res.authors)
);
}, 0);
});
}
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
@import url("~@/assets/bootstrap.css");
@import url("~@/assets/datatable.css");
@import url("~@/assets/tooltip.css");
/* Vue transition classes */
/* enter classes */
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
.main {
/*margin-left: 200px;*/
margin-left: 20px;
}
.shape {
border-radius: 50%;
}
h3 {
margin: 40px 0 0;
}
a {
color: #42b983;
}
#wrapper {
overflow-x: hidden;
}
#sidebar-wrapper {
min-height: 100vh;
margin-left: -15rem;
-webkit-transition: margin 0.25s ease-out;
-moz-transition: margin 0.25s ease-out;
-o-transition: margin 0.25s ease-out;
transition: margin 0.25s ease-out;
position: absolute;
z-index: 1; /* Stay on top */
left: 0;
}
#sidebar-wrapper .sidebar-heading {
padding: 0.875rem 1.25rem;
font-size: 1.2rem;
}
#sidebar-wrapper .list-group {
position: -webkit-sticky;
position: sticky;
top: 0;
width: 15rem;
}
#page-content-wrapper {
min-width: 100vw;
}
#wrapper.toggled #sidebar-wrapper {
margin-left: 0;
}
@media (min-width: 768px) {
#sidebar-wrapper {
margin-left: 0;
}
#page-content-wrapper {
min-width: 0;
width: 100%;
}
#wrapper.toggled #sidebar-wrapper {
margin-left: -15rem;
}
}
.uniprot-link {
font-weight: bold;
color: #0065b9;
}
.checked {
color: orange;
}
.d-flex {
display: -ms-flexbox !important;
display: flex !important;
}
.panel {
font-size: 1.2rem;
}
#more {
display: none;
}
#more.active {
display: table-row;
}
</style>