diff --git a/web/src/components/AboutPage.vue b/web/src/components/AboutPage.vue index 0264c6d020c3e400061529e393d6c7ff5214b209..088fc3829815f23be747d0e99fca14f5a5bf28ec 100644 --- a/web/src/components/AboutPage.vue +++ b/web/src/components/AboutPage.vue @@ -1,108 +1,151 @@ <template> - <div id="page-content-wrapper" class="flex flex-wrap justify-center"> + <div + id="page-content-wrapper" + class="flex flex-wrap justify-center" + > <div class="w-5/6"> - <h2>DD-Code</h2> - <p> - DD-CODE is a comprehensive, manually curated database for - <a href="/encyclopedia" class="hover:no-underline hover:text-green-600">biomolecular condensates</a> and their constituents as well as - an <a href="/encyclopedia" class="hover:no-underline hover:text-green-600">encyclopedia</a> for the scientific terms used to describe - them. Biomolecular condensates are cellular structures that are formed by - <a href="/encyclopedia" class="hover:no-underline hover:text-green-600">phase separation</a>. In cells, phase separation is driven by <a href="/encyclopedia" class="hover:text-green-600 hover:no-underline">driver</a> - proteins/nucleic acid, which in turn recruit <a href="/encyclopedia" class="hover:no-underline hover:text-green-600">client</a> molecules into the - condensate. It is important to note that a particular protein/nucleic acid - may be a driver in one condensate but the client in another. Moreover, the - formation of condensates might be regulated by <a href="/encyclopedia" class="hover:no-underline hover:text-green-600">regulator</a> proteins through - specific biochemical activities, but they do not necessarily need to be a - part of the condensate. - </p> - <p> - DD-CODE is aimed at becoming a valuable resource for the phase separation - and condensate community by providing 1) a reliable literature mined - database on all biomolecular condensates and their constituents; 2) an - encyclopedia and ontology of the scientific terms and definitions used in - the field of phase separation and condensate biology and 3) a standardised - list of terminologyes in the field. All data here are manually curated and - experimental details and references are provided; this provides the basis - of our <a href="/encyclopedia" class="hover:no-underline hover:text-green-600">scoring system</a>. - </p> - <p> - Protein definition: Proteins on DD-CODE are divided three groups. -</p> - <p> - <b>Drivers:</b> Proteins which have at least one of the following features. - <ul class="list-decimal list-inside px-8"> - <li v-for="items in driversList" :key="items"> - {{items}} - </li> - -</ul> - </p> - <p> - <b>Clients:</b> Proteins which are part of a condensate, but driven into it by driver proteins. - </p> - <p> - <b>Regulators:</b> Proteins which biochemically/enzymatically regulate the formation of a condensate, but are structurally not part of it. - </p> - <p> - <b>Scoring system on DD-CODE:</b> At DD-CODE is having three-fold scoring system (evidence stars) - <ol class="list-decimal list-inside px-8"> - <li v-for="items in scoringSysList" :key="items"> - {{items}} - </li> - </ol> - </p> - <div> - <p class="underline"> - Evidence of a protein being in a condensate: - - </p> - <p> - DD-CODE initially started off as an aggregation of - existing protein-phase-separation databases namely - <a href="http://llps.biocuckoo.cn/" class="hover:no-underline hover:text-green-600">http://llps.biocuckoo.cn/</a> (dr_llps), <a href="http://bio-comp.org.cn/llpsdb/home.html " class="hover:no-underline hover:text-green-600">http://bio-comp.org.cn/llpsdb/home.html </a> (llps_db), <a href="http://db.phasep.pro/" class="hover:no-underline hover:text-green-600">http://db.phasep.pro/</a> (phase_pro) and <a href="https://phasepro.elte.hu/" class="hover:no-underline hover:text-green-600"></a> (phase_hu). Within these four source databases, we were also able to find publications (via text mining) stating localization of these phase-separating proteins into biomolecular condensates. - </p> - </div> + <h2 class="text-uppercase"> + DD-Code + </h2> + <p> + DD-CODE is a comprehensive, manually curated database for + <a + href="https://wiki.ddcode.org/Membraneless_compartments" + class="hover:no-underline hover:text-green-600" + >biomolecular condensates</a> and their constituents as well as + an <a + href="https://wiki.ddcode.org/" + class="hover:no-underline hover:text-green-600" + >encyclopedia</a> for the scientific terms used to describe + them. Biomolecular condensates are cellular structures that are formed by + <a + href="https://wiki.ddcode.org/Membraneless_compartments" + class="hover:no-underline hover:text-green-600" + >phase separation</a>. In cells, phase separation is driven by <a + href="https://wiki.ddcode.org/Scaffolds_and_Clients" + class="hover:text-green-600 hover:no-underline" + >driver</a> + proteins/nucleic acid, which in turn recruit <a + href="https://wiki.ddcode.org/Scaffolds_and_Clients" + class="hover:no-underline hover:text-green-600" + >client</a> molecules into the + condensate. It is important to note that a particular protein/nucleic acid + may be a driver in one condensate but the client in another. Moreover, the + formation of condensates might be regulated by <a + href="https://wiki.ddcode.org/Scaffolds_and_Clients" + class="hover:no-underline hover:text-green-600" + >regulator</a> proteins through + specific biochemical activities, but they do not necessarily need to be a + part of the condensate. + </p> + <p> + DD-CODE is aimed at becoming a valuable resource for the phase separation + and condensate community by providing 1) a reliable literature mined + database on all biomolecular condensates and their constituents; 2) an + encyclopedia and ontology of the scientific terms and definitions used in + the field of phase separation and condensate biology and 3) a standardised + list of terminologyes in the field. All data here are manually curated and + experimental details and references are provided; this provides the basis + of our scoring system. + </p> + <p> + Protein definition: Proteins on DD-CODE are divided three groups. + </p> + <p> + <b>Drivers:</b> Proteins which have at least one of the following features. + <ul class="list-decimal list-inside px-8"> + <li + v-for="items in driversList" + :key="items" + > + {{ items }} + </li> + </ul> + </p> + <p> + <b>Clients:</b> Proteins which are part of a condensate, but driven into it by driver proteins. + </p> + <p> + <b>Regulators:</b> Proteins which biochemically/enzymatically regulate the formation of a condensate, but are structurally not part of it. + </p> + <p> + <b>Scoring system on DD-CODE:</b> At DD-CODE is having three-fold scoring system (evidence stars) + <ol class="list-decimal list-inside px-8"> + <li + v-for="items in scoringSysList" + :key="items" + > + {{ items }} + </li> + </ol> + </p> + <div> + <p class="underline"> + Evidence of a protein being in a condensate: + </p> + <p> + DD-CODE initially started off as an aggregation of + existing protein-phase-separation databases namely - <a + href="http://llps.biocuckoo.cn/" + class="hover:no-underline hover:text-green-600" + >http://llps.biocuckoo.cn/</a> (dr_llps), <a + href="http://bio-comp.org.cn/llpsdb/home.html " + class="hover:no-underline hover:text-green-600" + >http://bio-comp.org.cn/llpsdb/home.html </a> (llps_db), <a + href="http://db.phasep.pro/" + class="hover:no-underline hover:text-green-600" + >http://db.phasep.pro/</a> (phase_pro) and <a + href="https://phasepro.elte.hu/" + class="hover:no-underline hover:text-green-600" + /> (phase_hu). Within these four source databases, we were also able to find publications (via text mining) stating localization of these phase-separating proteins into biomolecular condensates. + </p> + </div> - <div> - <p> - Using the above two datapoints (source database annotations and publications), we devised a rule-based mechanism to rate the evidence of a protein being a condensate, which goes as follow: - <ul class="list-disc list-inside px-8"> - <li v-for="items in evidenceProteinRateList" :key="items" v-html="items"> - - </li> - </ul> - </p> - <p> - Besides these initial ratings, it is also possible for a contributor to modify these ratings. - </p> - </div> + <div> + <p> + Using the above two datapoints (source database annotations and publications), we devised a rule-based mechanism to rate the evidence of a protein being a condensate, which goes as follow: + <ul class="list-disc list-inside px-8"> + <li + v-for="items in evidenceProteinRateList" + :key="items" + v-html="items" + /> + </ul> + </p> + <p> + Besides these initial ratings, it is also possible for a contributor to modify these ratings. + </p> + </div> - <div> - <p class="undeline"> - Evidence of the existence of a condensate along with its proteome: - - </p> - <p> - Using the above ratings of a protein existing in a condensate, and computing the median of these scores, we provide a rating to the existence of the condensate as a whole. - </p> - <p> - This rating, unlike the previous one though is not editable, and is always recomputed after a round of contributions are accepted and synced. - </p> - </div> - - <div> - <p> - <span class="underline">Evidence for a protein being a driver:</span> Having any of the below-mentioned features provide a star for a protein being a driver. - <ul class="list-decimal list-inside px-8"> - <li v-for="items in proteinFeaturesList" :key="items"> - {{items}} - </li> - </ul> - </p> - <p> - This provides maximum three starts (***) for a protein which is confidently a driver. - </p> - </div> + <div> + <p class="undeline"> + Evidence of the existence of a condensate along with its proteome: + </p> + <p> + Using the above ratings of a protein existing in a condensate, and computing the median of these scores, we provide a rating to the existence of the condensate as a whole. + </p> + <p> + This rating, unlike the previous one though is not editable, and is always recomputed after a round of contributions are accepted and synced. + </p> + </div> + + <div> + <p> + <span class="underline">Evidence for a protein being a driver:</span> Having any of the below-mentioned features provide a star for a protein being a driver. + <ul class="list-decimal list-inside px-8"> + <li + v-for="items in proteinFeaturesList" + :key="items" + > + {{ items }} + </li> + </ul> + </p> + <p> + This provides maximum three starts (***) for a protein which is confidently a driver. + </p> + </div> @@ -116,15 +159,14 @@ <li><a href="/about">Evidence stars</a></li> </ul> --> </div> - </div> </template> <script> -const _ = require("lodash"); +const _ = require('lodash'); export default { - name: "LandingPage", + name: 'LandingPage', components: {}, props: { msg: String, @@ -132,25 +174,25 @@ export default { data() { return { driversList: [ - "Undergo phase separation or self-assembly into liquid droplets independent of other proteins.", - "Induce the formation of a condensate.", - "Are essential for the integrity of a condensate.", + 'Undergo phase separation or self-assembly into liquid droplets independent of other proteins.', + 'Induce the formation of a condensate.', + 'Are essential for the integrity of a condensate.', ], scoringSysList: [ - "A protein being present in a condensate (Rated out of 5)", - "The existence of a condensate along with its proteome as a whole (Rated out of 5)", - "A protein being present as a driver in the condensate (Rated out of 3)", + 'A protein being present in a condensate (Rated out of 5)', + 'The existence of a condensate along with its proteome as a whole (Rated out of 5)', + 'A protein being present as a driver in the condensate (Rated out of 3)', ], evidenceProteinRateList: [ - "Having source database as <b>dr_llps</b> or <b>llps_db</b>: 1/5", - "Having source database as <b>phase_pro</b> (high-throughput-exp): 2/5", - "Having source database as <b>phase_pro</b> or <b>phase_hu</b>: 4/5", - "Having a publication: 4/5", + 'Having source database as <b>dr_llps</b> or <b>llps_db</b>: 1/5', + 'Having source database as <b>phase_pro</b> (high-throughput-exp): 2/5', + 'Having source database as <b>phase_pro</b> or <b>phase_hu</b>: 4/5', + 'Having a publication: 4/5', ], proteinFeaturesList: [ - "Undergo phase separation or self-assembly into liquid droplets independent of other proteins (*).", - "Induce the formation of a condensate (*).", - "Are essential for the integrity of a condensate (*)", + 'Undergo phase separation or self-assembly into liquid droplets independent of other proteins (*).', + 'Induce the formation of a condensate (*).', + 'Are essential for the integrity of a condensate (*)', ], }; }, diff --git a/web/src/components/CMS/fetchProfile.vue b/web/src/components/CMS/fetchProfile.vue index 4193e8eee9760a888523d3f8af0588acbff4fc17..c64793d4e21d8cd576006d3b26c85a1ef4cf418f 100644 --- a/web/src/components/CMS/fetchProfile.vue +++ b/web/src/components/CMS/fetchProfile.vue @@ -39,13 +39,14 @@ export default { const vm = this; // console.log(host) - + console.log('is dev?',vm.isDev); if (vm.isDev) { host = require('../js/const').devApiHost; } // console.log(vm.isExperimental) let url = `${host}/api/users/me`; + console.log('url is',url); const jwt = vm.jwt; if (jwt === null) { diff --git a/web/src/components/CMS/updateFunctionalType.vue b/web/src/components/CMS/updateFunctionalType.vue index 6d3b8a0421909143b2c65a767b503cc226510678..94acfa82442ec2edd067055d6ebafa323bda3dc0 100644 --- a/web/src/components/CMS/updateFunctionalType.vue +++ b/web/src/components/CMS/updateFunctionalType.vue @@ -1,6 +1,9 @@ <template> <div> - <base-toaster :open="toasterIsOpen" @close="hideDialog"> + <base-toaster + :open="toasterIsOpen" + @close="hideDialog" + > <div class="flex justify-between items-center"> <font-awesome-icon class="ml-3" @@ -9,8 +12,14 @@ /> <h4>Request submitted successfully!</h4> - <button class="btn btn-outline" @click="hideDialog"> - <font-awesome-icon icon="fa-regular fa-circle-xmark" size="2x" /> + <button + class="btn btn-outline" + @click="hideDialog" + > + <font-awesome-icon + icon="fa-regular fa-circle-xmark" + size="2x" + /> </button> </div> </base-toaster> @@ -25,9 +34,10 @@ <base-spinner /> </div> <div class="form-group"> - <label class="control-label col-sm-4" for="FuncType" - >Choose a functional type</label - > + <label + class="control-label col-sm-4" + for="FuncType" + >Choose a functional type</label> <div class="col-sm-8"> <div> <select @@ -52,9 +62,10 @@ </div> </div> <div class="form-group"> - <label class="control-label col-sm-4" for="funComment" - >Reason</label - > + <label + class="control-label col-sm-4" + for="funComment" + >Reason</label> <div class="col-sm-8"> <textarea @@ -84,7 +95,10 @@ @keyup="validateComment" /> - <p v-if="!isValid" class="text-danger mt-4 font-bold"> + <p + v-if="!isValid" + class="text-danger mt-4 font-bold" + > {{ error }} </p> <p @@ -144,27 +158,27 @@ </template> <script> -import BaseSpinner from "../UI/BaseSpinner.vue"; -import BaseToaster from "../UI/BaseToaster.vue"; -const _ = require("lodash"); -let host = require("../js/const").apiHost; +import BaseSpinner from '../UI/BaseSpinner.vue'; +import BaseToaster from '../UI/BaseToaster.vue'; +const _ = require('lodash'); +let host = require('../js/const').apiHost; export default { components: { BaseSpinner, BaseToaster }, - props: ["type", "data"], + props: ['type', 'data'], data() { return { - isDev: process.env.NODE_ENV === "development", + isDev: process.env.NODE_ENV === 'development', functionalOptions: [ - { id: "1", type: "client" }, - { id: "2", type: "driver" }, - { id: "3", type: "regulator" }, + { id: '1', type: 'client' }, + { id: '2', type: 'driver' }, + { id: '3', type: 'regulator' }, ], functionalType: this.data.functional_type, - error: "", + error: '', isValid: false, - message: "", + message: '', serverError: false, - comment: "", + comment: '', isLoading: false, showToast: false, toasterIsOpen: false, @@ -172,10 +186,10 @@ export default { }, computed: { jwt: function () { - return this.$store.getters["User/jwt"]; + return this.$store.getters['User/jwt']; }, role: function () { - return this.$store.getters["User/userRole"]; + return this.$store.getters['User/userRole']; }, }, @@ -188,13 +202,13 @@ export default { }, validateComment() { this.isValid = true; - this.error = ""; - this.message = ""; + this.error = ''; + this.message = ''; }, selectValue() { this.isValid = true; - this.error = ""; - this.message = ""; + this.error = ''; + this.message = ''; }, async updateFuctionalType() { const vm = this; @@ -202,53 +216,53 @@ export default { // console.log(host) if (vm.isDev) { - host = require("../js/const").devApiHost; + host = require('../js/const').devApiHost; } let url = `${host}/api/update-items`; if (!this.functionalType) { this.isValid = false; - this.message = ""; - this.error = "Select a functional type to update!"; + this.message = ''; + this.error = 'Select a functional type to update!'; return; } else if (this.data.functional_type === this.functionalType) { this.isValid = false; - this.message = ""; + this.message = ''; this.error = `The selected functional type is already ${this.functionalType}. Please select a different functional type from the list.`; return; } let data; this.isValid = true; - this.error = ""; - if (this.role === "Maintainer") { + this.error = ''; + if (this.role === 'Maintainer') { data = { - Entity: "protein", + Entity: 'protein', EntityId: this.data.uniprot_id, - ChangeOperation: "update", - Attribute: "functional_type", + ChangeOperation: 'update', + Attribute: 'functional_type', SubmissionComments: - "Maintainer do not need to provide a reason for such change at the moment!", + 'Maintainer do not need to provide a reason for such change at the moment!', Value: this.functionalType, - Status: "accepted", + Status: 'accepted', }; } else { - if (this.comment === "" || this.comment.length < 50) { + if (this.comment === '' || this.comment.length < 50) { this.isValid = false; - this.message = ""; - this.error = "Reason should not be empty or less than 50 character!"; + this.message = ''; + this.error = 'Reason should not be empty or less than 50 character!'; return; } data = { - Entity: "protein", + Entity: 'protein', EntityId: this.data.uniprot_id, - ChangeOperation: "update", - Attribute: "functional_type", + ChangeOperation: 'update', + Attribute: 'functional_type', SubmissionComments: this.comment, Value: this.functionalType, - Status: "requested", + Status: 'requested', }; } this.isLoading = true; @@ -265,11 +279,11 @@ export default { this.isLoading = false; this.toasterIsOpen = true; this.functionalType = this.data.functional_type; - this.comment = ""; + this.comment = ''; this.isValid = true; - this.error = ""; + this.error = ''; this.serverError = false; - this.$emit("update-key"); + this.$emit('update-key'); setTimeout(() => { this.toasterIsOpen = false; }, 2000); @@ -278,11 +292,11 @@ export default { this.isLoading = false; this.serverError = true; this.message = - e.message || "Something went wrong, please try again later!"; + e.message || 'Something went wrong, please try again later!'; } }, close() { - this.$emit("close"); + this.$emit('close'); }, }, }; diff --git a/web/src/components/CondensateDetailPage.vue b/web/src/components/CondensateDetailPage.vue index 090ab4f357053619047fd7c4c137a92d0b11c40f..7fdee687cf44e7c7601c79942b13cdfa43339fd8 100644 --- a/web/src/components/CondensateDetailPage.vue +++ b/web/src/components/CondensateDetailPage.vue @@ -40,18 +40,27 @@ <div class="w-5/6"> <fetch-condensate :condensate="condensate"> - <template slot-scope="{ response, loading }"> + <template slot-scope="{ response, loading, fetchError }"> <slot :response="response" :loading="loading" + :fetchError="fetchError" > <div v-if="loading || response === null"> <base-spinner /> </div> + <div> + <h2 + v-if="fetchError" + class="text-red-500" + > + {{ fetchError }} + </h2> + </div> <!-- <div v-if="loading"> <base-spinner></base-spinner> </div> --> - <div v-else> + <div v-if="response"> <div class="flex space-x-4"> <h2>{{ response.data.name }}</h2> @@ -747,13 +756,13 @@ :pubmed="response.data.protein_pubmed_ids" :db-tags="response.data.protein_source_db_tags" :protein-driver-criterion=" - response.data.protein_driver_criterion + testProteinDriverCriterion " :protein-experimental-evidence=" - response.data.protein_exp_evidence + testProteinExpEvidence " :protein-functional-type=" - response.data.protein_functional_type + testProteinFuntionalType " @update-key="updatedKey += 1" /> @@ -877,24 +886,24 @@ export default { data() { return { // test data - // testProteinFuntionalType: { - // A0A178VY62: "client", - // A0A178W3G2: "driver", - // A0A1I9LN21: "regulator", - // A0A1I9LRM4: "driver", - // }, - // testProteinDriverCriterion: { - // A0A178VY62: ["self_ps"], - // A0A178W3G2: ["induce_formation"], - // A0A1I9LN21: ["self_ps"], - // A0A1I9LRM4: ["intergrity_essential", "self_ps", "induce_formation"], - // }, - // testProteinExpEvidence: { - // A0A178VY62: ["in_vivo"], - // A0A178W3G2: ["in_tergrity_essential_cellulo"], - // A0A1I9LN21: ["in_vitro"], - // A0A1I9LRM4: ["in_vivo", "in_vitro", "frap"], - // }, + testProteinFuntionalType: { + A0A178VY62: 'client', + A0A178W3G2: 'driver', + A0A1I9LN21: 'regulator', + A0A1I9LRM4: 'driver', + }, + testProteinDriverCriterion: { + A0A178VY62: ['self_ps'], + A0A178W3G2: ['induce_formation'], + A0A1I9LN21: ['self_ps'], + A0A1I9LRM4: ['intergrity_essential', 'self_ps', 'induce_formation'], + }, + testProteinExpEvidence: { + A0A178VY62: ['in_vivo'], + A0A178W3G2: ['in_tergrity_essential_cellulo'], + A0A1I9LN21: ['in_vitro'], + A0A1I9LRM4: ['in_vivo', 'in_vitro', 'frap'], + }, condensate: this.$route.params.condensate ? this.$route.params.condensate : this.condensateId, diff --git a/web/src/components/CondensateUpdateItemsTable.vue b/web/src/components/CondensateUpdateItemsTable.vue index d1903183fa261ba1e4735cc63cba97c8a216fdda..f27be93901bed206c5a3ba6012d815960a5d5466 100644 --- a/web/src/components/CondensateUpdateItemsTable.vue +++ b/web/src/components/CondensateUpdateItemsTable.vue @@ -90,6 +90,28 @@ export default { { title: 'Value', data: 'attributes.Value', + render: function (data, type, row, meta) { + + if(data==='frap'){ + return data.toUpperCase(); + }else if(data === 'self_ps'){ + return 'Self-PS' + }else{ + return _.startCase(data) + } + // console.log(_.flatMap(row.condensates, c => c.data_sources)) + // if (!vm.proteinDriverCriterion) { + // return; + // } + // let dat = vm.proteinDriverCriterion[row.uniprot_id]; + // if (dat) { + + // const val= dat.map(i=> i==='self_ps'? dat[i]='Self-PS': _.startCase(i)) + + // return val.join(', '); + // } + // return ''; + }, }, { title: 'Change Operation', diff --git a/web/src/components/DDCODE/fetchCondensate.vue b/web/src/components/DDCODE/fetchCondensate.vue index fcacf1aa4bd5166b5ace8f135e1ecefc2da45399..022257b13a4e927e2dd80ce17d44024c685270a2 100644 --- a/web/src/components/DDCODE/fetchCondensate.vue +++ b/web/src/components/DDCODE/fetchCondensate.vue @@ -3,6 +3,7 @@ <slot :response="response" :loading="loading" + :fetchError="fetchError" /> </div> </template> @@ -22,6 +23,7 @@ import LoginVue from '../../views/Login.vue'; return { response: null, loading: false, + fetchError:'', isDev: process.env.NODE_ENV === 'development' } }, @@ -32,7 +34,7 @@ import LoginVue from '../../views/Login.vue'; vm.getItems(); }, methods: { - getItems() { + async getItems() { const vm = this // /* eslint-disable no-console */ @@ -46,10 +48,12 @@ import LoginVue from '../../views/Login.vue'; let url = `${host}/condensates/${vm.condensate}`; - // console.log('url is', url); + console.log('url is', url); if (vm.condensate && !_.isEmpty(vm.condensate)) { - fetch(url, { + console.log('True'); + try{ + const res = await fetch(url, { method: 'GET', mode: 'cors', cache: 'no-cache', @@ -57,12 +61,17 @@ import LoginVue from '../../views/Login.vue'; Authorization: `Bearer ${apikey}` } }) - .then(response => response.json()) - .then((response) => { - /* eslint-disable no-console */ - // console.log(response); - - setTimeout(() => { + + + if(!res.ok){ + vm.loading = false; + vm.response = '' + vm.fetchError = `${res.status} Internal Error, please write a mail to DDCode Admin.` + return; + } + vm.fetchError= ''; + const response = await res.json(); + setTimeout(() => { vm.loading = false; vm.response = response @@ -71,7 +80,30 @@ import LoginVue from '../../views/Login.vue'; // this.response = _.flatMap(response, (n) => [{ text: n.name, style: 'background-color: ' + n.color }]); // } }, 10); - }); + + + // .then(response => response.json()) + // .then((response) => { + // /* eslint-disable no-console */ + // console.log(response); + + // setTimeout(() => { + // vm.loading = false; + // vm.response = response + + // // console.log(response); + // // if (response && !_.isEmpty(response)) { + // // this.response = _.flatMap(response, (n) => [{ text: n.name, style: 'background-color: ' + n.color }]); + // // } + // }, 10); + // }); + }catch(err){ + console.log('in catch',err.message); + vm.loading = false; + vm.response = '' + vm.fetchError = `${err.message} Internal Error, please write a mail to DDCode Admin.` + } + } else { vm.loading = false; vm.response = '' diff --git a/web/src/components/DDCODE/fetchProtein.vue b/web/src/components/DDCODE/fetchProtein.vue index 5e355cd198dfd0b8d9f0cde3f2758ab10901761d..b67835e6b90fac84da20a2facfcefc404e1007a3 100644 --- a/web/src/components/DDCODE/fetchProtein.vue +++ b/web/src/components/DDCODE/fetchProtein.vue @@ -3,6 +3,7 @@ <slot :response="response" :loading="loading" + :fetchError="fetchError" /> </div> </template> @@ -21,6 +22,7 @@ export default { return { response: null, loading: false, + fetchError:'', isDev: process.env.NODE_ENV === 'development', }; }, @@ -36,7 +38,7 @@ export default { vm.getItems(); }, methods: { - getItems() { + async getItems() { const vm = this // /* eslint-disable no-console */ @@ -51,7 +53,8 @@ export default { let url = `${host}/proteins/${vm.protein}`; if (vm.protein && !_.isEmpty(vm.protein)) { - fetch(url, { + try{ + const res = await fetch(url, { method: 'GET', mode: 'cors', cache: 'no-cache', @@ -59,21 +62,44 @@ export default { Authorization: `Bearer ${apikey}` } }) - .then(response => response.json()) - .then((response) => { - // /* eslint-disable no-console */ - // console.log(response); - - setTimeout(() => { + console.log('protein res', res); + if(!res.ok){ + vm.loading = false; + vm.response = '' + vm.fetchError = `${res.status} Internal Error, please write a mail to DDCode Admin.` + return; + } + vm.fetchError= ''; + const response = await res.json(); + setTimeout(() => { vm.loading = false; vm.response = response; - // console.log(response); // if (response && !_.isEmpty(response)) { // this.response = _.flatMap(response, (n) => [{ text: n.name, style: 'background-color: ' + n.color }]); // } }, 10); - }); + // .then(response => response.json()) + // .then((response) => { + // // /* eslint-disable no-console */ + // // console.log(response); + + // setTimeout(() => { + // vm.loading = false; + // vm.response = response; + + // // console.log(response); + // // if (response && !_.isEmpty(response)) { + // // this.response = _.flatMap(response, (n) => [{ text: n.name, style: 'background-color: ' + n.color }]); + // // } + // }, 10); + // }); + }catch(err){ + vm.loading = false; + vm.response = '' + vm.fetchError = `${err.message} Internal Error, please write a mail to DDCode Admin.` + } + } else { vm.loading = false; vm.response = '' diff --git a/web/src/components/DDCODE/fetchStats.vue b/web/src/components/DDCODE/fetchStats.vue index 296b0d4a4d2129ea04c3f6f40aa5921671bc5455..b7514e8dea8f5e4c69f0e67bf6ef784392619a51 100644 --- a/web/src/components/DDCODE/fetchStats.vue +++ b/web/src/components/DDCODE/fetchStats.vue @@ -3,6 +3,7 @@ <slot :response="response" :loading="loading" + :fetchError="fetchError" /> </div> </template> @@ -19,6 +20,7 @@ export default { return { loading: true, response: '', + fetchError:'', isDev: process.env.NODE_ENV === 'development' } }, @@ -29,7 +31,7 @@ export default { vm.getItems(); }, methods: { - getItems() { + async getItems() { const vm = this; // console.log(host) @@ -39,8 +41,8 @@ export default { } let url = `${host}/statistics`; - - fetch(url, { + try{ + const res = await fetch(url, { method: 'GET', mode: 'cors', cache: 'no-cache', @@ -48,13 +50,35 @@ export default { Authorization: `Bearer ${apikey}` } }) - .then(response => response.json()) - .then((response) => { + if(!res.ok){ + vm.loading = false; + vm.response = '' + vm.fetchError = `${res.status} Internal Error, please write a mail to DDCode Admin.` + return; + } + vm.fetchError= ''; + + const response = await res.json(); + console.log('stat response', response); setTimeout(() => { this.loading = false; this.response = response }, 10); - }); + // .then(response => response.json()) + // .then((response) => { + // setTimeout(() => { + // this.loading = false; + // this.response = response + // }, 10); + // }); + + }catch(error){ + console.log('true'); + vm.loading = false; + vm.response = '' + vm.fetchError = `${error.message} Internal Error, please write a mail to DDCode Admin.` + } + } }, } diff --git a/web/src/components/Datatable/CondensateDataTable.vue b/web/src/components/Datatable/CondensateDataTable.vue index 5ee97b195e84f10230e5251ea539570377a2ddf0..ef5fcc36007385e7dde3b5763a669180f6828e36 100644 --- a/web/src/components/Datatable/CondensateDataTable.vue +++ b/web/src/components/Datatable/CondensateDataTable.vue @@ -1,11 +1,19 @@ <template> <div> - <a ref="download" /> - <table - :id="id" - class="table table-striped table-bordered table-hover" - width="100%" - /> + <h2 + v-if="error" + class="text-red-500" + > + {{ errorMsg }} + </h2> + <div v-if="!error"> + <a ref="download" /> + <table + :id="id" + class="table table-striped table-bordered table-hover" + width="100%" + /> + </div> </div> </template> @@ -47,6 +55,8 @@ export default { header: [], total: 0, downloadUrl: '', + error: false, + errorMsg:'', isDev: process.env.NODE_ENV === 'development', }; }, @@ -231,7 +241,14 @@ export default { Authorization: `Bearer ${apikey}` } }); - + + if(res.statusText !=='OK'){ + this.error = true + this.errorMsg = `${res.status} Internal Error, please write a mail to DDCode Admin.` + return; + } + this.error= false; + this.errorMsg= ''; if(res.data) { // vm.meta = res.meta; // vm.data = res.data; @@ -245,9 +262,9 @@ export default { fnCallback(dat) } } catch(error) { - // console.error(error) + console.log('error',error) this.error = true - this.errorMsg = 'You are not authorized to access this item.' + this.errorMsg = 'Internal Error, please write a mail to DDCode Admin.' } }, async downloadCsv() { diff --git a/web/src/components/Datatable/ProteinDataTable.vue b/web/src/components/Datatable/ProteinDataTable.vue index a89df3a8680886b7c0103b06c3963952f878a069..08888d3a5b87f9fd57b5a8ce0bd1d8b0000c3fa7 100644 --- a/web/src/components/Datatable/ProteinDataTable.vue +++ b/web/src/components/Datatable/ProteinDataTable.vue @@ -1,11 +1,19 @@ <template> <div> - <a ref="download" /> - <table - :id="id" - class="table table-striped table-bordered table-hover" - width="100%" - /> + <h2 + v-if="error" + class="text-red-500" + > + {{ errorMsg }} + </h2> + <div v-if="!error"> + <a ref="download" /> + <table + :id="id" + class="table table-striped table-bordered table-hover" + width="100%" + /> + </div> </div> </template> @@ -27,6 +35,8 @@ export default { rows: [], header: [], total: 0, + error: false, + errorMsg: '', downloadUrl: '', isDev: process.env.NODE_ENV === 'development', }; @@ -231,7 +241,11 @@ export default { Authorization: `Bearer ${apikey}` } }); - + if(res.statusText !=='OK'){ + this.error = true + this.errorMsg = `${res.status} Internal Error, please write a mail to DDCode Admin.` + return; + } if(res.data) { // vm.meta = res.meta; // vm.data = res.data; @@ -247,7 +261,7 @@ export default { } catch(error) { // console.error(error) this.error = true - this.errorMsg = 'You are not authorized to access this item.' + this.errorMsg = 'Internal Error, please write a mail to DDCode Admin.' } }, async downloadCsv() { diff --git a/web/src/components/LandingPage.vue b/web/src/components/LandingPage.vue index 0a87541aee709879e631118e4447ad957d3b8799..b180d2dcf0c4b55c135dc806be1dcee324671d71 100644 --- a/web/src/components/LandingPage.vue +++ b/web/src/components/LandingPage.vue @@ -3,20 +3,20 @@ id="page-content-wrapper" class="flex flex-wrap justify-center" > - <div class="w-5/6"> - <h2> - Dresden Condensate Database and Encyclopedia - {{ isDev ? "(Dev version)" : "" }} - </h2> - <p> - <b> - DD-CODE is a comprehensive, manually curated database of biomolecular - condensates and an encyclopedia of the scientific terms used to describe - and characterize those condensates. - </b> - <br> - <br> - </p> + <div class="w-5/6"> + <h2> + <strong>Dresden</strong> Condensate Database and Encyclopedia + {{ isDev ? "(Dev version)" : "" }} + </h2> + <p> + <b> + DD-CODE is a comprehensive, manually curated database of biomolecular + condensates and an encyclopedia of the scientific terms used to describe + and characterize those condensates. + </b> + <br> + <br> + </p> <form class="form-horizontal" @@ -173,7 +173,6 @@ </Search> </div> </div> - </div> </template> @@ -412,7 +411,7 @@ export default { </script> <!-- Add "scoped" attribute to limit CSS to this component only --> -<style> +<style scoped> @import url("~@/assets/bootstrap.css"); @import url("~@/assets/datatable.css"); @import url("~@/assets/vue-simple-suggest-styles.css"); @@ -424,6 +423,9 @@ export default { h3 { margin: 40px 0 0; } +h2 { + font-family: 'Open Sans', sans-serif; +} a { color: #42b983; diff --git a/web/src/components/Links.vue b/web/src/components/Links.vue index c6e4591fce447c758d99b37d923b74f2a3b6a3a0..9da15d61c1510743328419a8b1a0694cac6dfc4f 100644 --- a/web/src/components/Links.vue +++ b/web/src/components/Links.vue @@ -5,7 +5,10 @@ :class="{ active: $route.name === 'home' }" @mouseover="openCondensateSubMenu = false" > - <router-link to="/" exact> + <router-link + to="/" + exact + > <span class="text-2xl">Home</span> </router-link> </li> @@ -210,7 +213,10 @@ <span class="text-2xl">Statistics</span> </router-link> </li> - <li role="presentation" @mouseover="openCondensateSubMenu = false"> + <li + role="presentation" + @mouseover="openCondensateSubMenu = false" + > <a href="https://wiki.ddcode.org"> <span class="text-2xl">Encyclopedia</span> </a> @@ -218,7 +224,7 @@ <li v-show=" userData !== null && - (userRole === 'Contributor' || userRole === 'Maintainer') + (userRole === 'Contributor' || userRole === 'Maintainer') " role="presentation" :class="{ active: $route.name === 'updateItems' }" @@ -256,7 +262,10 @@ role="presentation" @mouseover="openCondensateSubMenu = false" > - <router-link to="/login" @click.native="signOut"> + <router-link + to="/login" + @click.native="signOut" + > <span class="fa fa-sign-out" /> </router-link> </li> @@ -275,7 +284,7 @@ <script> export default { - name: "Links", + name: 'Links', data() { return { // userData: this.$store.getters['User/userData'] @@ -284,10 +293,10 @@ export default { }, computed: { userData: function () { - return this.$store.getters["User/userData"]; + return this.$store.getters['User/userData']; }, userRole: function () { - return this.$store.getters["User/userRole"]; + return this.$store.getters['User/userRole']; }, }, mounted: function () { @@ -305,11 +314,11 @@ export default { }, signOut() { const vm = this; - window.localStorage.removeItem("jwt"); - window.localStorage.removeItem("userData"); - window.localStorage.removeItem("roleName"); - vm.$store.dispatch("User/logOut"); - vm.$router.push("/login"); + window.localStorage.removeItem('jwt'); + window.localStorage.removeItem('userData'); + window.localStorage.removeItem('roleName'); + vm.$store.dispatch('User/logOut'); + vm.$router.push('/login'); }, }, }; diff --git a/web/src/components/LlpsTable.vue b/web/src/components/LlpsTable.vue index fac8a7c87807fa6e20dcbe745b37e5cc32d60412..02817eb46c2e89e919392c5c1469ce8cb719156a 100644 --- a/web/src/components/LlpsTable.vue +++ b/web/src/components/LlpsTable.vue @@ -521,7 +521,7 @@ export default { title: 'Functional Type', data: 'protein_functional_type', className: 'whitespace-nowrap', - defaultContent: '<i>No data</i>', + render: function (data, type, row, meta) { // console.log(_.flatMap(row.condensates, c => c.data_sources)) if (!vm.proteinFunctionalType) { @@ -529,17 +529,17 @@ export default { } let dat = vm.proteinFunctionalType[row.uniprot_id]; if (dat) { - return dat; + return _.startCase(dat); } else { - return 'No data'; + return ''; } }, }, { title: 'Experimental Evidence', data: 'protein_exp_evidence', - className: 'whitespace-nowrap', - defaultContent: '<i>No data</i>', + className: 'whitespace-normal', + render: function (data, type, row, meta) { // console.log(_.flatMap(row.condensates, c => c.data_sources)) if (!vm.proteinExperimentalEvidence) { @@ -548,16 +548,18 @@ export default { let dat = vm.proteinExperimentalEvidence[row.uniprot_id]; if (dat) { - return dat.join(', '); + const val= dat.map(i=> i==='frap'? dat[i]=i.toUpperCase() : _.startCase(i)) + + return val.join(', '); } - return 'No data'; + return ''; }, }, { title: 'Driver Criterion', data: 'driver_criterion', - className: 'whitespace-nowrap', - defaultContent: '<i>No data</i>', + className: 'whitespace-normal', + render: function (data, type, row, meta) { // console.log(_.flatMap(row.condensates, c => c.data_sources)) if (!vm.proteinDriverCriterion) { @@ -565,9 +567,12 @@ export default { } let dat = vm.proteinDriverCriterion[row.uniprot_id]; if (dat) { - return dat.join(', '); + + const val= dat.map(i=> i==='self_ps'? dat[i]='Self-PS': _.startCase(i)) + + return val.join(', '); } - return 'No data'; + return ''; }, }, { diff --git a/web/src/components/ProteinDetailPage.vue b/web/src/components/ProteinDetailPage.vue index c16e75ce94e9cc043078cf65617a9eb0b7e327ad..3c08a7d04ada9cc8354d928230cf4e60afb52047 100644 --- a/web/src/components/ProteinDetailPage.vue +++ b/web/src/components/ProteinDetailPage.vue @@ -27,14 +27,20 @@ <fetch-protein :protein="protein"> - <template slot-scope="{ response, loading }"> + <template slot-scope="{ response, loading, fetchError }"> <slot :response="response" :loading="loading" + :fetchError="fetchError" > <div v-if="loading"> <base-spinner v-if="loading" /> </div> + <div v-if="fetchError"> + <h2 class="text-red-500"> + {{ fetchError }} + </h2> + </div> <div v-else-if="response !== null"> <h2>{{ response.data.gene_name }}</h2> <h4 class="round"> diff --git a/web/src/components/ProteinUpdateItemTable.vue b/web/src/components/ProteinUpdateItemTable.vue index 23a83e15b4fffe37db5956e78acfed5c93fa2476..7ef72075678d829bcf58a6876164d79fb61c7deb 100644 --- a/web/src/components/ProteinUpdateItemTable.vue +++ b/web/src/components/ProteinUpdateItemTable.vue @@ -65,6 +65,15 @@ export default { { title: 'Value', data: 'attributes.Value', + render: function (data, type, row, meta) { + + if(data){ + return _.startCase(data) + + }else{ + return '' + } + } }, { title: 'Change Operation', diff --git a/web/src/components/StatPage.vue b/web/src/components/StatPage.vue index 5009599638b0da3f850efdea9b80da35b8448ef5..2cd3da4d70b6beefcea5c14449b19d95180f7fc1 100644 --- a/web/src/components/StatPage.vue +++ b/web/src/components/StatPage.vue @@ -1,30 +1,38 @@ <template> <div id="page-content-wrapper" - class="main" + class="flex flex-wrap justify-center" > - <h2>Statistics</h2> + <div class="w-5/6"> + <h2>Statistics</h2> - <fetch-stats> - <template slot-scope="{response, loading}"> - <slot - :response="response" - :loading="loading" - > - <div v-if="loading"> - <base-spinner /> - </div> - <div v-else-if="response !== null"> - <species-chart - :condensate="response.species_wise_condensates" - :protein="response.species_wise_proteins" - /> - <!--<evidence-chart :evidence-list="response.evidence_list_data" :evidence="response.evidence_data"></evidence-chart>--> - <histograms :condensate="response.condensate_proteome_histogram" /> - </div> - </slot> - </template> - </fetch-stats> + <fetch-stats> + <template slot-scope="{response, loading, fetchError}"> + <slot + :response="response" + :loading="loading" + :fetchError="fetchError" + > + <div v-if="loading || response === null"> + <base-spinner /> + </div> + <div v-if="fetchError"> + <h2 class="text-red-500"> + {{ fetchError }} + </h2> + </div> + <div v-if="response"> + <species-chart + :condensate="response.species_wise_condensates" + :protein="response.species_wise_proteins" + /> + <!--<evidence-chart :evidence-list="response.evidence_list_data" :evidence="response.evidence_data"></evidence-chart>--> + <histograms :condensate="response.condensate_proteome_histogram" /> + </div> + </slot> + </template> + </fetch-stats> + </div> </div> </template> diff --git a/web/src/components/UpdateItemTable.vue b/web/src/components/UpdateItemTable.vue index ef08a8b472b1aa812c0af7cf577bc59aaf286897..83f0ce0aadbc7f347a424942d2573b3af2a76389 100644 --- a/web/src/components/UpdateItemTable.vue +++ b/web/src/components/UpdateItemTable.vue @@ -80,6 +80,16 @@ export default { { title: 'Value', data: 'attributes.Value', + render: function (data, type, row, meta) { + console.log('all changes now', data); + if(data==='frap'){ + return data.toUpperCase(); + }else if(data === 'self_ps'){ + return 'Self-PS' + }else{ + return _.startCase(data) + } + } }, { title: 'Change Operation', diff --git a/web/src/components/js/datatable.js b/web/src/components/js/datatable.js index f70755b5b2faa5e4c2044d43aefc3821e4c73dae..2fabce83c6bd8a3062b5fc6f92d2db1eca23e644 100644 --- a/web/src/components/js/datatable.js +++ b/web/src/components/js/datatable.js @@ -6,9 +6,9 @@ const DataTable = $.fn.dataTable; /* Set the defaults for DataTables initialisation */ $.extend(true, DataTable.defaults, { dom: - "<'row'<'col-sm-6'l><'col-sm-6'f>>" - + "<'row'<'col-sm-12'tr>>" - + "<'row'<'col-sm-5'i><'col-sm-7'p>>", + '<\'row\'<\'col-sm-6\'l><\'col-sm-6\'f>>' + + '<\'row\'<\'col-sm-12\'tr>>' + + '<\'row\'<\'col-sm-5\'i><\'col-sm-7\'p>>', renderer: 'bootstrap', }); diff --git a/web/src/views/ForgotPassword.vue b/web/src/views/ForgotPassword.vue index 46c627b796cd65ac928c6f1f3e0a355867b76693..1d2563edb87d64fcc5aa5c4facfcb760f5d5c597 100644 --- a/web/src/views/ForgotPassword.vue +++ b/web/src/views/ForgotPassword.vue @@ -46,6 +46,9 @@ </p> --> <form @submit="forgotPassword"> + <div v-if="isLoading"> + <base-spinner /> + </div> <div class="my-4"> <h1 class=" @@ -90,9 +93,7 @@ {{ errorMsg }} </p> </div> - <div v-if="isLoading"> - <base-spinner /> - </div> + <button type="submit" class=" @@ -175,8 +176,8 @@ export default { // const res= this.axios.post(`${host}/api/auth/forgot-password`, { // email: this.email.val // }) - - const res = await fetch(`${host}/api/auth/forgot-password`, { + try{ + const res = await fetch(`${host}/api/auth/forgot-password`, { method: 'POST', mode: 'cors', // no-cors, *cors, same-origin cache: 'no-cache', // *default, no-cache, reload, force-cache, @@ -188,6 +189,13 @@ export default { email: this.email.val, }), }); + if(!res.ok){ + this.isLoading = false; + this.error = true; + this.errorMsg = `${res.status} Internal Error, please write a mail to DDCode Admin`; + + return; + } if (!res.ok && res.status === 500) { this.isLoading = false; this.error = true; @@ -220,6 +228,13 @@ export default { this.isLoading = false; this.error= false; this.toasterIsOpen = true; + }catch(err){ + console.log(err); + this.isLoading = false; + this.error = true; + this.errorMsg = `Internal Error, please write a mail to DDCode Admin`; + } + }, }, }; diff --git a/web/src/views/Help.vue b/web/src/views/Help.vue index 9b09137e9cd4f6ebc8529bd7285b5405b5339345..248fc2322869f3ab0b55c3950691c18407a181c6 100644 --- a/web/src/views/Help.vue +++ b/web/src/views/Help.vue @@ -2,7 +2,9 @@ <div class="flex flex-wrap justify-center"> <div class="w-5/6"> <h2>Help</h2> - <p class="text-3xl">Content of this page coming soon..</p> + <p class="text-3xl"> + Content of this page coming soon.. + </p> </div> </div> </template> diff --git a/web/src/views/Login.vue b/web/src/views/Login.vue index e8e2cfc503ed387a7b27a1c1d21f85ec1addb7eb..8af1df9acd26764cab58934012de1fb19bade9a4 100644 --- a/web/src/views/Login.vue +++ b/web/src/views/Login.vue @@ -213,8 +213,8 @@ export default { host = require('@/components/js/const').devApiHost; } this.isLoading = true; - - const res = await fetch(`${host}/api/auth/local`, { + try{ + const res = await fetch(`${host}/api/auth/local`, { method: 'POST', mode: 'cors', // no-cors, *cors, same-origin cache: 'no-cache', // *default, no-cache, reload, force-cache, @@ -227,6 +227,15 @@ export default { password: this.password.val, }), }); + console.log('response is',res); + + if(!res.ok){ + this.isLoading = false; + this.error = true; + this.errorMsg = `${res.status} Internal Error, please write a mail to DDCode Admin`; + + return; + } if (!res.ok && res.status === 500) { this.isLoading = false; @@ -262,6 +271,16 @@ export default { this.isLoading = false; this.error = false; this.$router.push('/profile'); + }catch(err){ + console.log('catch error',err); + this.isLoading = false; + this.error = true; + this.errorMsg = `${err.message} Internal Error, please write a mail to DDCode Admin`; + + } + + + // const res = await this.axios.post(`${host}/api/auth/local`, { // identifier: this.email.val, diff --git a/web/src/views/Profile.vue b/web/src/views/Profile.vue index 285ed391e238d16dfc5a06f1d39b4a3e01bac1f9..e5b4bf4aa92517e771fb1f2f9e228c0ba7b7a081 100644 --- a/web/src/views/Profile.vue +++ b/web/src/views/Profile.vue @@ -28,42 +28,42 @@ </base-toaster> <div class="w-5/6"> <fetch-profile - v-if="userData !== null" - :key="updatedKey" - > - <template slot-scope="{ response, loading, error : profile_error }"> - <slot - :response="response" - :loading="loading" - :error="profile_error" - > - <div v-if="loading"> - <base-spinner /> - </div> - <div v-else-if="!loading && profile_error"> - <p class="text-red-500 text-2xl"> - {{ response }} - </p> - </div> - <div v-else> - <!-- {{response}}--> - <h4 class="round"> - User Profile - </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"> - User ID - </div> - <div class="col-sm-9"> - <div class="flex justify-between"> - <b>{{ response.username }}</b> - <div class="relative"> - <button - type="button" - class=" + v-if="userData !== null" + :key="updatedKey" + > + <template slot-scope="{ response, loading, error : profile_error }"> + <slot + :response="response" + :loading="loading" + :error="profile_error" + > + <div v-if="loading"> + <base-spinner /> + </div> + <div v-else-if="!loading && profile_error"> + <p class="text-red-500 text-2xl"> + {{ response }} + </p> + </div> + <div v-else> + <!-- {{response}}--> + <h4 class="round"> + User Profile + </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"> + User ID + </div> + <div class="col-sm-9"> + <div class="flex justify-between"> + <b>{{ response.username }}</b> + <div class="relative"> + <button + type="button" + class=" text-white bg-blue-600 hover:bg-blue-700 @@ -78,17 +78,17 @@ mr-2 font-bold " - @click="isOpen = !isOpen" - > - Edit - <font-awesome-icon - class="ml-2" - icon="fa-solid fa-user-pen" - /> - </button> - <div - v-if="isOpen" - class=" + @click="isOpen = !isOpen" + > + Edit + <font-awesome-icon + class="ml-2" + icon="fa-solid fa-user-pen" + /> + </button> + <div + v-if="isOpen" + class=" mt-2 absolute z-50 @@ -99,11 +99,11 @@ shadow-lg bg-white " - > - <!-- Active: "bg-gray-100 text-gray-900", Not Active: "text-gray-700" --> - <a - href="#" - class=" + > + <!-- Active: "bg-gray-100 text-gray-900", Not Active: "text-gray-700" --> + <a + href="#" + class=" text-gray-700 rounded-lg block @@ -114,11 +114,11 @@ hover:text-white hover:no-underline " - @click="openScientificDisciplineEdit" - >Scientific Discipline</a> - <a - href="#" - class=" + @click="openScientificDisciplineEdit" + >Scientific Discipline</a> + <a + href="#" + class=" text-gray-700 block px-6 @@ -129,11 +129,11 @@ hover:text-white hover:no-underline " - @click="openProfileLinkEdit" - >Profile Link</a> - <a - href="#" - class="text-gray-700 + @click="openProfileLinkEdit" + >Profile Link</a> + <a + href="#" + class="text-gray-700 text-gray-700 block px-6 @@ -143,169 +143,169 @@ hover:bg-gray-400 hover:text-white hover:no-underline" - @click="openChangePassword" - >Password</a> + @click="openChangePassword" + >Password</a> + </div> </div> </div> </div> </div> - </div> - <div class="row"> - <div class="text col-sm-3"> - Full Name - </div> - <div class="col-sm-9"> - <b>{{ response.full_name }}</b> - </div> - </div> - <div class="row"> - <div class="text col-sm-3"> - Email - </div> - <div class="col-sm-9"> - {{ response.email }} - </div> - </div> - <div class="row"> - <div class="text col-sm-3"> - Role - </div> - <div class="col-sm-9"> - {{ setRole(response.role.name) }} - </div> - </div> - <div class="row"> - <div class="text col-sm-3"> - Current role - </div> - <div class="col-sm-9"> - <div> - {{ response.current_role.replace(/_/g, ' ') }} + <div class="row"> + <div class="text col-sm-3"> + Full Name + </div> + <div class="col-sm-9"> + <b>{{ response.full_name }}</b> </div> </div> - </div> - <div class="row"> - <div class="text col-sm-3"> - Scientific Discipline - </div> - <div class="col-sm-9"> - <div> - {{ response.scientific_discipline.join(', ') }} + <div class="row"> + <div class="text col-sm-3"> + Email + </div> + <div class="col-sm-9"> + {{ response.email }} </div> </div> - </div> - <div class="row"> - <div class="text col-sm-3"> - Motivation + <div class="row"> + <div class="text col-sm-3"> + Role + </div> + <div class="col-sm-9"> + {{ setRole(response.role.name) }} + </div> </div> - <div class="col-sm-9"> - <p> - {{ response.motivation_text }} - </p> + <div class="row"> + <div class="text col-sm-3"> + Current role + </div> + <div class="col-sm-9"> + <div> + {{ response.current_role.replace(/_/g, ' ') }} + </div> + </div> </div> - </div> - <div class="row"> - <div class="text col-sm-3"> - Affiliation + <div class="row"> + <div class="text col-sm-3"> + Scientific Discipline + </div> + <div class="col-sm-9"> + <div> + {{ response.scientific_discipline.join(', ') }} + </div> + </div> </div> - <div class="col-sm-9"> - <div> - {{ response.current_affiliation }} + <div class="row"> + <div class="text col-sm-3"> + Motivation + </div> + <div class="col-sm-9"> + <p> + {{ response.motivation_text }} + </p> </div> </div> - </div> - <div class="row"> - <div class="text col-sm-3"> - Profile Link + <div class="row"> + <div class="text col-sm-3"> + Affiliation + </div> + <div class="col-sm-9"> + <div> + {{ response.current_affiliation }} + </div> + </div> </div> - <div class="col-sm-9"> - <a - :href="response.profile_link" - target="_blank" - > - {{ response.profile_link }} - </a> + <div class="row"> + <div class="text col-sm-3"> + Profile Link + </div> + <div class="col-sm-9"> + <a + :href="response.profile_link" + target="_blank" + > + {{ response.profile_link }} + </a> + </div> </div> - </div> - <div class="row"> - <div class="text col-sm-3"> - Joined - </div> - <div class="col-sm-9"> - {{ response.createdAt }} - </div> - </div> - <div class="row"> - <div class="text col-sm-3"> - Updated + <div class="row"> + <div class="text col-sm-3"> + Joined + </div> + <div class="col-sm-9"> + {{ response.createdAt }} + </div> </div> - <div class="col-sm-9"> - {{ response.updatedAt }} + <div class="row"> + <div class="text col-sm-3"> + Updated + </div> + <div class="col-sm-9"> + {{ response.updatedAt }} + </div> </div> </div> </div> </div> - </div> - <div - v-if="editMode" - class="panel panel-default" - > - <div class="panel-body"> - <div class="container-fluid col-md-12"> - <div v-if="showEditScientificDis"> - <h3 class="mb-6 border-b"> - Update Scientific Discipline - </h3> - <div class="row"> - <div class="text col-sm-3 p-4"> - Scientific Discipline - </div> - <div class="col-sm-9 p-4"> - <div - v-for="options in scientificDisciplineOptions" - :key="options.id" - > - <input - :id="options.id" - v-model="selected" - type="checkbox" - class="h-6 w-6" - :name="options" - :value="options.discipline" - > - <label - class="mx-3" - :for="options.id" - >{{ - options.discipline - }}</label> + <div + v-if="editMode" + class="panel panel-default" + > + <div class="panel-body"> + <div class="container-fluid col-md-12"> + <div v-if="showEditScientificDis"> + <h3 class="mb-6 border-b"> + Update Scientific Discipline + </h3> + <div class="row"> + <div class="text col-sm-3 p-4"> + Scientific Discipline </div> + <div class="col-sm-9 p-4"> + <div + v-for="options in scientificDisciplineOptions" + :key="options.id" + > + <input + :id="options.id" + v-model="selected" + type="checkbox" + class="h-6 w-6" + :name="options" + :value="options.discipline" + > + <label + class="mx-3" + :for="options.id" + >{{ + options.discipline + }}</label> + </div> - <p - v-if="profile_error && scientificErrMsg" - class="text-red-500 font-bold mt-2" - > - {{ scientificErrMsg }} - </p> + <p + v-if="profile_error && scientificErrMsg" + class="text-red-500 font-bold mt-2" + > + {{ scientificErrMsg }} + </p> + </div> </div> </div> - </div> - <div v-if="showEditProfileLink"> - <h3 class="mb-6 border-b"> - Change Profile Link - </h3> - <div class="row"> - <div class="text col-sm-3 p-4"> - Profile Link - </div> + <div v-if="showEditProfileLink"> + <h3 class="mb-6 border-b"> + Change Profile Link + </h3> + <div class="row"> + <div class="text col-sm-3 p-4"> + Profile Link + </div> - <div class="col-sm-9 p-4"> - <input - id="inline-profile-link" - v-model.trim="profile_link" - class=" + <div class="col-sm-9 p-4"> + <input + id="inline-profile-link" + v-model.trim="profile_link" + class=" bg-white w-1/3 py-4 @@ -316,31 +316,31 @@ border border-gray-500 hover:border-gray-700 " - type="text" - placeholder="Enter profile link." - > - <p - v-if="profile_error && profileLinkErrMsg" - class="text-red-500 font-bold mt-2" - > - {{ profileLinkErrMsg }} - </p> + type="text" + placeholder="Enter profile link." + > + <p + v-if="profile_error && profileLinkErrMsg" + class="text-red-500 font-bold mt-2" + > + {{ profileLinkErrMsg }} + </p> + </div> </div> </div> - </div> - <div v-if="showChangePassword"> - <h3 class="mb-6 border-b"> - Change Password - </h3> - <div class="row"> - <div class="text col-sm-3 p-4"> - Current password - </div> - <div class="col-sm-9 p-4"> - <input - id="current-password" - v-model.trim="currentPassword" - class=" + <div v-if="showChangePassword"> + <h3 class="mb-6 border-b"> + Change Password + </h3> + <div class="row"> + <div class="text col-sm-3 p-4"> + Current password + </div> + <div class="col-sm-9 p-4"> + <input + id="current-password" + v-model.trim="currentPassword" + class=" bg-white w-1/3 py-4 @@ -351,19 +351,19 @@ border border-gray-500 hover:border-gray-700 " - type="password" - > - </div> - </div> - <div class="row"> - <div class="text col-sm-3 p-4"> - New Password + type="password" + > + </div> </div> - <div class="col-sm-9 p-4"> - <input - id="inline-password" - v-model.trim="newPassword" - class=" + <div class="row"> + <div class="text col-sm-3 p-4"> + New Password + </div> + <div class="col-sm-9 p-4"> + <input + id="inline-password" + v-model.trim="newPassword" + class=" bg-white w-1/3 py-4 @@ -374,19 +374,19 @@ border border-gray-500 hover:border-gray-700 " - type="password" - > - </div> - </div> - <div class="row"> - <div class="text col-sm-3 p-4"> - Confirm New Password + type="password" + > + </div> </div> - <div class="col-sm-9 p-4"> - <input - id="confirm-password" - v-model.trim="confirmPassword" - class=" + <div class="row"> + <div class="text col-sm-3 p-4"> + Confirm New Password + </div> + <div class="col-sm-9 p-4"> + <input + id="confirm-password" + v-model.trim="confirmPassword" + class=" bg-white w-1/3 py-4 @@ -397,21 +397,21 @@ border border-gray-500 hover:border-gray-700 " - type="password" - > - <p - v-if="profile_error && passwordErrMsg" - class="text-red-500 font-bold mt-2" - > - {{ passwordErrMsg }} - </p> + type="password" + > + <p + v-if="profile_error && passwordErrMsg" + class="text-red-500 font-bold mt-2" + > + {{ passwordErrMsg }} + </p> + </div> </div> </div> - </div> - <div class="flex space-x-4 mt-2"> - <button - class=" + <div class="flex space-x-4 mt-2"> + <button + class=" bg-blue-500 text-xl font-bold @@ -421,12 +421,12 @@ text-white hover:bg-blue-700 " - @click="update(response)" - > - Update Profile - </button> - <button - class=" + @click="update(response)" + > + Update Profile + </button> + <button + class=" bg-gray-500 text-xl font-bold @@ -436,51 +436,50 @@ text-white hover:bg-gray-700 " - @click="close" - > - Cancel - </button> + @click="close" + > + Cancel + </button> + </div> </div> </div> + <p + v-if="profile_error && errorMsg" + class="text-red-500 font-bold mt-2" + > + {{ errorMsg }} + </p> </div> - <p - v-if="profile_error && errorMsg" - class="text-red-500 font-bold mt-2" - > - {{ errorMsg }} - </p> - </div> <!-- <button v-if="userData !== null && (getRole === 'Contributor' || getRole === 'Maintainer')" class="btn btn-primary" @click="$router.push('/updateitem/new')"> Create new Update Item </button> --> - </div> - </slot> - </template> - </fetch-profile> + </div> + </slot> + </template> + </fetch-profile> - <fetch-users v-if="getRole === 'Administrator'"> - <template slot-scope="{ response, loading }"> - <slot - :response="response" - :loading="loading" - > - <div v-if="loading || response === null" /> - <div v-else> - <h4 class="round"> - User List - </h4> - <user-table - id="usersTable" - :data="response" - /> - </div> - </slot> - </template> - </fetch-users> + <fetch-users v-if="getRole === 'Administrator'"> + <template slot-scope="{ response, loading }"> + <slot + :response="response" + :loading="loading" + > + <div v-if="loading || response === null" /> + <div v-else> + <h4 class="round"> + User List + </h4> + <user-table + id="usersTable" + :data="response" + /> + </div> + </slot> + </template> + </fetch-users> </div> - </div> </template>