AddNovelCondensate.vue 24.85 KiB
<template>
<div class="flex flex-wrap">
<div class="w-5/6">
<form
autocomplete="off"
@submit.prevent="addCondensate()"
>
<div v-if="isLoading">
<base-spinner />
</div>
<div
class="
grid grid-cols-3 grid-flow-row-dense
items-center
gap-x-6
border border-gray-300
rounded-md
p-4
gap-y-4
"
>
<label
class="text-right"
for="condensate_is_experimental"
>Synthetic/Biomolecular</label>
<div class="col-span-2">
<input
id="condensate_is_experimental_true"
v-model="condensate.is_experimental"
type="radio"
name="condensate_is_experimental"
value="true"
>
<label
for="condensate_is_experimental_true"
class="ml-2 mr-3"
>Synthetic</label>
<input
id="condensate_is_experimental_false"
v-model="condensate.is_experimental"
type="radio"
name="condensate_is_experimental"
value="false"
>
<label
for="condensate_is_experimental_false"
class="ml-2 mr-3"
>Biomolecular</label>
</div>
<label
class="text-right"
for="condensate_name"
>Condensate Name</label>
<div class="col-span-2">
<input
id="condensate_name"
v-model.trim="condensate.name"
class="
bg-white
w-1/3
py-4
px-4
w-full
rounded-lg
text-gray-700
bg-transparent
border border-gray-500
hover:border-gray-700
"
type="text"
placeholder="Name"
>
<p
v-if="condensate.errors.name"
class="text-red-600 mt-4 font-bold"
>
{{ condensate.errorMsg }}
</p>
</div>
<label
class="text-right"
for="condensate_protein"
>Proteins</label>
<div>
<tags-input
v-model="proteinNameList"
@proteinNotFound="notFound"
/>
<p
v-if="searchProtein.errors"
class="text-red-500 font-bold"
>
{{ searchProtein.message }}
</p>
</div>
<button
id="addNewProtein"
class="
bg-blue-500
font-bold
rounded-lg
py-4
px-5
h-full
text-white
hover:bg-blue-700
"
type="button"
@click="showAddNewProtein = !showAddNewProtein"
>
Add New Protein
</button>
<div
v-if="showAddNewProtein"
class="col-span-3"
>
<div
class="
grid grid-cols-3
items-center
grid-flow-row-dense
gap-x-6 gap-y-4
p-4
border border-gray-300
rounded-md
"
>
<label
class="text-right"
for="uniprot_id"
>Uniprot ID *
<a
class="uniprot-link tooltipped tooltipped-e"
aria-label='The UniProt ID (accession) is the 6 to the 10-character-long name displayed on the heading of the protein page from Uniprot.
It is a unique identifier for a protein from the whole Uniprot database (https://www.uniprot.org/help/accession_numbers).
Please note that different proteins from the same gene will also have different Uniprot IDs.
For example, The Uniprot ID of "FUS Human" is P35637 (https://www.uniprot.org/uniprot/P35637).
It is usually the last part of the URI of the HTTPS link of the protein page.'
>
<span class="fa fa-info-circle" />
</a>
</label>
<div class="col-span-2">
<input
id="uniprot_id"
v-model.trim="newProtein.uniprot_id"
class="
bg-white
w-1/3
py-4
px-4
w-full
rounded-lg
text-gray-700
bg-transparent
border border-gray-500
hover:border-gray-700
"
type="text"
placeholder="Uniprot ID"
>
<p
v-if="newProtein.errors.uniprot_id"
class="text-red-600 mt-4 font-bold"
>
{{ newProtein.errorMsg }}
</p>
</div>
<label
class="text-right"
for="functional_type"
>Functional Type</label>
<div class="col-span-2">
<select
id="functional_type"
v-model="newProtein.functional_type"
class="
bg-white
px-4
py-5
rounded-lg
border border-gray-400
w-full
text-gray-700
outline-none
bg-transparent
border-b
hover:border-blue-700
"
>
<option value="">
Select Functional Type
</option>
<option value="client">
client
</option>
<option value="driver">
driver
</option>
<option value="null">
unknown
</option>
<option value="regulator">
regulator
</option>
</select>
<p
v-if="newProtein.errors.functional_type"
class="text-red-600 mt-4 font-bold"
>
{{ newProtein.errorMsg }}
</p>
</div>
<label
class="text-right"
for="pubmed_ids"
>PubMed IDs *</label>
<div class="col-span-2">
<input
id="pubmed_ids"
v-model.trim="newProtein.pubmed_ids"
class="
bg-white
w-1/3
py-4
px-4
w-full
rounded-lg
text-gray-700
bg-transparent
border border-gray-500
hover:border-gray-700
"
type="text"
placeholder="PubMed IDs (separated by comma)"
>
<p
v-if="newProtein.errors.pubmed_ids"
class="text-red-600 mt-4 font-bold"
>
{{ newProtein.errorMsg }}
</p>
</div>
<label
class="text-right"
for="driver_criterion"
>Driver Criterion</label>
<div class="col-span-2 space-x-4">
<input
id="self_ps"
v-model="newProtein.driver_criterion"
type="checkbox"
value="self_ps"
class="h-6 w-6"
>
<label
for="self_ps"
class="mx-3"
>Self-PS</label>
<input
id="induces_assembly"
v-model="newProtein.driver_criterion"
type="checkbox"
value="induces_assembly"
class="h-6 w-6"
>
<label
for="induces_assembly"
class="mx-3"
>Induces Assembly</label>
<input
id="essential_for_integrity"
v-model="newProtein.driver_criterion"
type="checkbox"
value="essential_for_integrity"
class="h-6 w-6"
>
<label
for="essential_for_integrity"
class="mx-3"
>Essential For Integrity</label>
<p
v-if="newProtein.errors.driver_criterion"
class="text-red-600 mt-4 font-bold"
>
{{ newProtein.errorMsg }}
</p>
</div>
<label
class="text-right"
for="experimental_evidences"
>Experimental Evidences</label>
<div class="col-span-2">
<input
id="in_vitro"
v-model="newProtein.experimental_evidences"
type="checkbox"
value="in_vitro"
class="h-6 w-6"
>
<label
for="in_vitro"
class="mx-3"
>In Vitro</label>
<input
id="in_vivo"
v-model="newProtein.experimental_evidences"
type="checkbox"
value="in_vivo"
class="h-6 w-6"
>
<label
for="in_vivo"
class="mx-3"
>In Vivo</label>
<input
id="in_cellulo"
v-model="newProtein.experimental_evidences"
type="checkbox"
value="in_cellulo"
class="h-6 w-6"
>
<label
for="in_cellulo"
class="mx-3"
>In Cellulo</label>
<input
id="mass_spectrometry"
v-model="newProtein.experimental_evidences"
type="checkbox"
value="mass_spectrometry"
class="h-6 w-6"
>
<label
for="mass_spectrometry"
class="mx-3"
>Mass Spectrometry</label><br>
<input
id="colocalization"
v-model="newProtein.experimental_evidences"
type="checkbox"
value="colocalization"
class="h-6 w-6"
>
<label
for="colocalization"
class="mx-3"
>Colocalization</label>
<input
id="frap"
v-model="newProtein.experimental_evidences"
type="checkbox"
value="frap"
class="h-6 w-6"
>
<label
for="frap"
class="mx-3"
>FRAP</label>
<input
id="others"
v-model="newProtein.experimental_evidences"
type="checkbox"
value="others"
class="h-6 w-6"
>
<label
for="others"
class="mx-3"
>Others</label>
<p
v-if="newProtein.errors.experimental_evidences"
class="text-red-600 mt-4 font-bold"
>
{{ newProtein.errorMsg }}
</p>
</div>
<label> </label>
<div class="col-span-2">
<div class="space-y-4 space-x-4">
<button
id="addNewProteinButton"
class="
bg-blue-500
font-bold
rounded-lg
py-4
px-5
w-32
text-white
hover:bg-blue-700
"
type="button"
@click="addNewProtein()"
>
Add
</button>
<button
id="cancelNewProtinButton"
class="
bg-white
hover:bg-gray-200
focus:ring-2 focus:ring-gray-300
rounded-lg
border border-gray-300
py-4
px-5
hover:text-gray-900
font-bold
"
type="button"
@click="cancelAddProtein"
>
Cancel
</button>
</div>
</div>
</div>
</div>
<label
class="text-right"
for="condensate_synonyms"
>Synonyms</label>
<div class="col-span-2">
<input
id="condensate_synonyms"
v-model.trim="condensate.synonyms"
class="
bg-white
w-1/3
py-4
px-4
w-full
rounded-lg
text-gray-700
bg-transparent
border border-gray-500
hover:border-gray-700
"
type="text"
placeholder="Synonyms (comma-separated)"
>
<p
v-if="condensate.errors.synonyms"
class="text-red-600 mt-4 font-bold"
>
{{ condensate.errorMsg }}
</p>
</div>
<label
class="text-right"
for="condensate_comments"
>Comments</label>
<div class="col-span-2">
<textarea
id="condensate_comments"
v-model.trim="condensate.comments"
class="
text-xl
outline-none
w-full
bg-transparent
px-4
py-5
rounded-lg
border border-gray-400
hover:border-gray-700
focus:border-blue-500
"
rows="5"
:placeholder="
getUserData === 'Maintainer' ? 'Optional.' : 'Mandatory.'
"
/>
<p
v-if="condensate.errors.comments"
class="text-red-600 mt-4 font-bold"
>
{{ condensate.errorMsg }}
</p>
</div>
<div class="col-start-2 col-end-3">
<div class="space-y-4 space-x-4">
<button
class="
bg-blue-500
font-bold
rounded-lg
py-6
px-5
text-white
hover:bg-blue-700
"
type="submit"
>
Add Condensate
</button>
<button
id="dropdownMenuButton"
class="
bg-white
hover:bg-gray-200
focus:ring-2 focus:ring-gray-300
rounded-lg
border border-gray-300
py-6
px-5
hover:text-gray-900
font-bold
"
type="button"
@click="close"
>
Cancel
</button>
</div>
</div>
</div>
<div>
<h3
v-if="fetchError"
class="text-red-500"
>
{{ fetchError }}
</h3>
</div>
</form>
</div>
</div>
</template>
<script>
// require modules
/* eslint-disable no-unused-vars */
import TagsInput from '@/components/TagsInput.vue';
import BaseSpinner from './UI/BaseSpinner.vue';
import { apikey } from '@/components/js/const';
const _ = require('lodash');
export default {
name: 'AddNovelCondensate',
components: {
TagsInput,
BaseSpinner,
},
props: [],
data() {
return {
showAddNewProtein: false,
searchProtein: {
errors: false,
message: '',
},
newProtein: {
uniprot_id: '',
functional_type: '',
pubmed_ids: '',
driver_criterion: [],
experimental_evidences: [],
errors: {
uniprot_id: false,
functional_type: false,
pubmed_ids: false,
driver_criterion: false,
experimental_evidences: false,
},
errorMsg: '',
},
condensate: {
name: '',
is_experimental: false,
proteins: [],
synonyms: '',
comments: '',
errors: {
name: false,
species: false,
synonyms: false,
comments: false,
},
errorMsg: '',
},
isLoading: false,
proteinList: this.$store.getters['Param/proteinList'],
fetchError: '',
isDev: process.env.NODE_ENV === 'development',
};
},
computed: {
jwt: function () {
return this.$store.getters['User/jwt'];
},
getUserData() {
const userRole = this.$store.getters['User/userRole'];
// console.log('role is', userRole);
return userRole;
},
proteinNameList: {
get() {
return _.map(this.proteinList, (d) => {
return { text: d.uniprot_id };
});
},
set(obj) {
const idx = this.proteinList.findIndex(
(d) => d.uniprot_id === obj.tag.text
);
this.$store.dispatch('Param/removeProtein', idx);
obj.deleteTag();
// console.log(this.$store.getters['Param/proteinList'])
},
},
},
mounted: function () {
const vm = this;
// vm.proteinNameList.push(vm.protein);
vm.$store.dispatch('Param/resetProteins');
},
methods: {
notFound(val, isEmpty) {
if (!val && !isEmpty) {
this.searchProtein.errors = true;
this.searchProtein.message =
'Protein not found. Try adding new protein.';
} else {
this.searchProtein.errors = false;
this.searchProtein.message = '';
}
},
close() {
this.condensate.name = '';
this.condensate.is_experimental = false;
this.condensate.species = '';
this.condensate.proteins = [];
this.condensate.synonyms = '';
this.condensate.comments = '';
this.condensate.errorMsg = '';
this.$router.push('/');
},
cancelAddProtein() {
this.newProtein.uniprot_id = '';
this.newProtein.functional_type = '';
this.newProtein.pubmed_ids = '';
this.newProtein.driver_criterion = [];
this.newProtein.experimental_evidences = [];
this.newProtein.errorMsg = '';
this.showAddNewProtein = false;
},
async addNewProtein() {
const vm = this;
let host = vm.isDev
? require('./js/const').devHost
: require('./js/const').host;
Object.keys(vm.newProtein.errors).forEach(
(v) => (vm.newProtein.errors[v] = false)
);
if (vm.newProtein.uniprot_id === '') {
vm.newProtein.errorMsg = 'Uniprot ID should not be empty!';
vm.newProtein.errors.uniprot_id = true;
return;
} else if (vm.newProtein.uniprot_id.length < 6) {
vm.newProtein.errorMsg = 'Uniprot ID should be minimum of 6 character.';
vm.newProtein.errors.uniprot_id = true;
return;
} else if (vm.newProtein.uniprot_id.length > 10) {
vm.newProtein.errorMsg =
'Uniprot ID should be maximum of 10 character.';
vm.newProtein.errors.uniprot_id = true;
return;
} else if (/(\s)/.test(vm.newProtein.uniprot_id)) {
vm.newProtein.errorMsg = 'Uniprot ID should not have space in between.';
vm.newProtein.errors.uniprot_id = true;
return;
} else {
let host = vm.isDev
? require('./js/const').devHost
: require('./js/const').host;
let url = `${host}/proteins?fields=uniprot_id,gene_name,name&query=${vm.newProtein.uniprot_id}`;
const ret = await fetch(url, {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
headers: {
Authorization: `Bearer ${apikey}`,
},
}).then((response) => response.json());
if (ret.count !== 0) {
vm.newProtein.errorMsg =
'Uniprot ID already exists in the database. Add the tag!';
vm.newProtein.errors.uniprot_id = true;
return;
}
}
if (vm.newProtein.pubmed_ids === '') {
vm.newProtein.errorMsg = 'Pubmed IDs should not be empty!';
vm.newProtein.errors.pubmed_ids = true;
return;
}
// if (vm.newProtein.driver_criterion === '') {
// vm.newProtein.errorMsg = 'Driver criterion should not be empty!';
// vm.newProtein.errors.driver_criterion = true;
// return;
// }
//
// if (vm.newProtein.experimental_evidences === '') {
// vm.newProtein.errorMsg = 'Experimental evidences should not be empty!';
// vm.newProtein.errors.experimental_evidences = true;
// return;
// }
vm.$store.dispatch('Param/addProtein', {
uniprot_id: vm.newProtein.uniprot_id,
functional_type: vm.newProtein.functional_type,
proteins: vm.newProtein.proteins,
pubmed_ids: vm.newProtein.pubmed_ids,
driver_criterion: vm.newProtein.driver_criterion,
experimental_evidences: vm.newProtein.experimental_evidences,
});
vm.newProtein.uniprot_id =
vm.newProtein.functional_type =
vm.newProtein.pubmed_ids = '';
vm.newProtein.driver_criterion = [];
vm.newProtein.experimental_evidences = [];
vm.showAddNewProtein = false;
},
async addCondensate() {
const vm = this;
Object.keys(vm.condensate.errors).forEach(
(v) => (vm.condensate.errors[v] = false)
);
if (vm.condensate.name === '') {
vm.condensate.errorMsg = 'Condensate name should not be empty!';
vm.condensate.errors.name = true;
return;
} else if (vm.proteinList.length === 0) {
vm.searchProtein.errors = true;
vm.searchProtein.message = 'Proteins field should not be empty.';
return;
}
let host = vm.isDev
? require('./js/const').devApiHost
: require('./js/const').apiHost;
let url = `${host}/api/novel-condensates`;
let data;
if (this.getUserData === 'Maintainer') {
data = {
Name: vm.condensate.name,
IsExperimental: vm.condensate.is_experimental,
Proteins: vm.proteinList,
Synonyms: vm.condensate.synonyms,
Status: 'accepted',
SubmissionComments:
'Maintainer do not need to provide a reason for such change at the moment!',
};
} else {
data = {
Name: vm.condensate.name,
IsExperimental: vm.condensate.is_experimental,
Proteins: vm.proteinList,
Synonyms: vm.condensate.synonyms,
Status: 'requested',
SubmissionComments: vm.condensate.comments,
};
}
vm.isLoading = true;
try {
await vm.axios.post(
url,
{ data: data },
{
headers: {
Authorization: `Bearer ${vm.jwt}`,
},
}
);
vm.isLoading = false;
vm.condensate.is_experimental = false;
vm.searchProtein.errors = false;
vm.condensate.name =
vm.condensate.species =
vm.condensate.synonyms =
vm.condensate.comments =
'';
vm.$store.dispatch('Param/resetProteins');
vm.$emit('showToaster', 'Condensate added successfully!');
setTimeout(() => {
vm.$emit('hideToaster');
}, 2000);
} catch (e) {
console.error(e);
vm.isLoading = false;
vm.fetchError =
e.message || 'Something went wrong, please try again later!';
vm.isSubmitted = true;
vm.error = true;
}
},
},
};
</script>
<style scoped>
@import url("~@/assets/bootstrap.css");
@import url("~@/assets/datatable.css");
@import url("~@/assets/tooltip.css");
.mainContent {
padding: 5px;
}
.uniprot-link {
font-weight: bold;
color: #ef0087 !important;
}
</style>