From 05184414860a7e3b055a059c2b29da51a0ef3454 Mon Sep 17 00:00:00 2001
From: HongKee Moon <moon@mpi-cbg.de>
Date: Thu, 12 May 2022 16:32:44 +0200
Subject: [PATCH] dd-code-team/dd-code-web#69: UI for data input and post to
 the server

---
 web/src/components/AddNovelCondensate.vue | 657 ++++++++++++++++++++++
 web/src/components/LandingPage.vue        |   4 +-
 web/src/components/Links.vue              |   9 +
 web/src/components/ProteinDetailPage.vue  | 299 +---------
 web/src/components/TagsInput.vue          |  94 ++++
 web/src/router/index.js                   |   5 +
 web/src/store/modules/Param.js            |  46 ++
 7 files changed, 824 insertions(+), 290 deletions(-)
 create mode 100644 web/src/components/AddNovelCondensate.vue
 create mode 100644 web/src/components/TagsInput.vue
 create mode 100644 web/src/store/modules/Param.js

diff --git a/web/src/components/AddNovelCondensate.vue b/web/src/components/AddNovelCondensate.vue
new file mode 100644
index 0000000..b324c2e
--- /dev/null
+++ b/web/src/components/AddNovelCondensate.vue
@@ -0,0 +1,657 @@
+<template>
+  <div class="mainContent">
+    <div class="panel-body">
+      <div class="container-fluid col-md-12">
+        <form
+          class="form-horizontal"
+          autocomplete="off"
+          @submit.prevent="addCondensate()"
+        >
+          <div v-if="isLoading">
+            <base-spinner />
+          </div>
+          <div class="form-group">
+            <label
+              class="control-label col-sm-2"
+              for="condensate_is_experimental"
+            >Synthetic?</label>
+            <div class="col-sm-4 pt-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"
+              >Yes</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"
+              >No</label>
+            </div>
+          </div>
+          <div class="form-group">
+            <label
+              class="control-label col-sm-2"
+              for="condensate_name"
+            >Condensate Name</label>
+            <div class="col-sm-4">
+              <input
+                id="condensate_name"
+                v-model.trim="condensate.name"
+                class="form-control input-sm"
+                type="text"
+                placeholder="Name"
+              >
+            </div>
+            <p
+              v-if="condensate.errors.name"
+              class="text-red-600 mt-4 font-bold"
+            >
+              {{ condensate.errorMsg }}
+            </p>
+          </div>
+          <div class="form-group">
+            <label
+              class="control-label col-sm-2"
+              for="condensate_species"
+            >Species</label>
+            <div class="col-sm-4">
+              <input
+                id="condensate_species"
+                v-model.trim="condensate.species"
+                class="form-control input-sm"
+                type="text"
+                placeholder="Species (NCBI taxonomy ID)"
+              >
+            </div>
+            <p
+              v-if="condensate.errors.species"
+              class="text-red-600 mt-4 font-bold"
+            >
+              {{ condensate.errorMsg }}
+            </p>
+          </div>
+          <div class="form-group">
+            <label
+              class="control-label col-sm-2"
+              for="condensate_protein"
+            >Proteins</label>
+            <div class="col-sm-4">
+              <tags-input v-model="proteinNameList" />
+            </div>
+            <div class="col-sm-2">
+              <button
+                id="addNewProtein"
+                class="
+                  text-white
+                  bg-indigo-500
+                  hover:bg-indigo-700
+                  focus:ring-2 focus:ring-blue-300
+                  rounded-lg
+                  inline-flex
+                  items-center
+                  px-3
+                  py-2
+                  text-center
+                  font-bold
+                "
+                type="button"
+                @click="showAddNewProtein = !showAddNewProtein"
+              >
+                Add New Protein
+              </button>
+            </div>
+          </div>
+
+          <div
+            v-if="showAddNewProtein"
+            class="panel panel-default mt-4"
+          >
+            <div class="panel-body">
+              <div class="container-fluid">
+                <div v-if="isLoading">
+                  <base-spinner />
+                </div>
+
+                <div class="form-group">
+                  <label
+                    class="control-label col-sm-2"
+                    for="uniprot_id"
+                  >Uniprot ID</label>
+                  <div class="col-sm-4">
+                    <input
+                      id="uniprot_id"
+                      v-model.trim="newProtein.uniprot_id"
+                      class="form-control input-sm"
+                      type="text"
+                      placeholder="Uniprot ID"
+                    >
+                  </div>
+                  <p
+                    v-if="newProtein.errors.uniprot_id"
+                    class="text-red-600 mt-4 font-bold"
+                  >
+                    {{ newProtein.errorMsg }}
+                  </p>
+                </div>
+                <div class="form-group">
+                  <label
+                    class="control-label col-sm-2"
+                    for="functional_type"
+                  >Functional Type</label>
+                  <div class="col-sm-4">
+
+                    <select id="functional_type"
+                            class="form-control input-sm"
+                            v-model="newProtein.functional_type">
+                      <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>
+                  </div>
+                  <p
+                    v-if="newProtein.errors.functional_type"
+                    class="text-red-600 mt-4 font-bold"
+                  >
+                    {{ newProtein.errorMsg }}
+                  </p>
+                </div>
+                <div class="form-group">
+                  <label
+                    class="control-label col-sm-2"
+                    for="pubmed_ids"
+                  >PubMed IDs</label>
+                  <div class="col-sm-4">
+                    <input
+                      id="pubmed_ids"
+                      v-model.trim="newProtein.pubmed_ids"
+                      class="form-control input-sm"
+                      type="text"
+                      placeholder="PubMed IDs (separated by comma)"
+                    >
+                  </div>
+                  <p
+                    v-if="newProtein.errors.pubmed_ids"
+                    class="text-red-600 mt-4 font-bold"
+                  >
+                    {{ newProtein.errorMsg }}
+                  </p>
+                </div>
+                <div class="form-group">
+                  <label
+                    class="control-label col-sm-2"
+                    for="driver_criterion"
+                  >Driver Criterion</label>
+                  <div class="col-sm-4">
+                    <input
+                      id="driver_criterion"
+                      v-model.trim="newProtein.driver_criterion"
+                      class="form-control input-sm"
+                      type="text"
+                      placeholder="Driver Criterion"
+                    >
+                  </div>
+                  <p
+                    v-if="newProtein.errors.driver_criterion"
+                    class="text-red-600 mt-4 font-bold"
+                  >
+                    {{ newProtein.errorMsg }}
+                  </p>
+                </div>
+                <div class="form-group">
+                  <label
+                    class="control-label col-sm-2"
+                    for="experimental_evidences"
+                  >Experimental Evidences</label>
+                  <div class="col-sm-4">
+                    <input
+                      id="experimental_evidences"
+                      v-model.trim="newProtein.experimental_evidences"
+                      class="form-control input-sm"
+                      type="text"
+                      placeholder="Experimental Evidences"
+                    >
+                  </div>
+                  <p
+                    v-if="newProtein.errors.experimental_evidences"
+                    class="text-red-600 mt-4 font-bold"
+                  >
+                    {{ newProtein.errorMsg }}
+                  </p>
+
+                  <div class="flex space-x-4">
+                    <button
+                      id="addNewProteinButton"
+                      class="
+                        text-white
+                        bg-indigo-500
+                        hover:bg-indigo-700
+                        focus:ring-2 focus:ring-blue-300
+                        rounded-lg
+                        inline-flex
+                        items-center
+                        px-5
+                        py-2.5
+                        text-center
+                        font-bold
+                                "
+                      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
+                        px-5
+                        py-2.5
+                        hover:text-gray-900
+                        font-bold
+                                "
+                      type="button"
+                      @click="showAddNewProtein = !showAddNewProtein"
+                    >
+                      Cancel
+                    </button>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+
+
+
+          <div class="form-group">
+            <label
+              class="control-label col-sm-2"
+              for="condensate_synonyms"
+            >Synonyms</label>
+            <div class="col-sm-4">
+              <input
+                id="condensate_synonyms"
+                v-model.trim="condensate.synonyms"
+                class="form-control input-sm"
+                type="text"
+                placeholder="Synonyms (comma-separated)"
+              >
+            </div>
+            <p
+              v-if="condensate.errors.synonyms"
+              class="text-red-600 mt-4 font-bold"
+            >
+              {{ condensate.errorMsg }}
+            </p>
+          </div>
+          <div class="form-group">
+            <label
+              class="control-label col-sm-2"
+              for="condensate_comments"
+            >Comments</label>
+            <div class="col-sm-4">
+              <textarea
+                id="condensate_comments"
+                v-model.trim="condensate.comments"
+                class="
+                  form-control
+                  block
+                  px-3
+                  py-1.5
+                  text-base
+                  font-normal
+                  text-gray-700
+                  bg-white bg-clip-padding
+                  border border-solid border-gray-300
+                  rounded
+                  transition
+                  ease-in-out
+                  m-0
+                  focus:text-gray-700
+                  focus:bg-white
+                  focus:border-blue-600
+                  focus:outline-none
+                "
+                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 class="flex space-x-4">
+                <button
+                  id="dropdownMenuButton"
+                  class="
+                    text-white
+                    bg-blue-500
+                    hover:bg-blue-700
+                    focus:ring-2 focus:ring-blue-300
+                    rounded-lg
+                    inline-flex
+                    items-center
+                    px-5
+                    py-2.5
+                    text-center
+                    font-bold
+                  "
+                  type="submit"
+                >
+                  Add
+                </button>
+                <button
+                  id="dropdownMenuButton"
+                  class="
+                    bg-white
+                    hover:bg-gray-200
+                    focus:ring-2 focus:ring-gray-300
+                    rounded-lg
+                    border border-gray-300
+                    px-5
+                    py-2.5
+                    hover:text-gray-900
+                    font-bold
+                  "
+                  type="button"
+                  @click="$emit('hide')"
+                >
+                  Cancel
+                </button>
+              </div>
+            </div>
+          </div>
+          <div>
+            <h3
+              v-if="fetchError"
+              class="text-red-500"
+            >
+              {{ fetchError }}
+            </h3>
+          </div>
+        </form>
+      </div>
+    </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: ['proteinId', 'hide'],
+  data() {
+    return {
+      showAddNewProtein: false,
+      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,
+        species: '',
+        proteins: [],
+        synonyms: [],
+        comments: '',
+        errors: {
+          name: false,
+          species: false,
+          synonyms: false,
+          comments: false,
+        },
+        errorMsg: ''
+      },
+      isLoading: false,
+      proteinList: this.$store.getters['Param/proteinList'],
+      protein: this.$route.params.protein
+        ? this.$route.params.protein
+        : this.proteinId,
+      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/addProtein', { uniprot_id: vm.protein });
+  },
+  methods: {
+    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.functional_type === '') {
+        vm.newProtein.errorMsg = 'Functional type should not be empty!';
+        vm.newProtein.errors.functional_type = 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.condensate.species === '') {
+        vm.condensate.errorMsg = 'Species should not be empty!';
+        vm.condensate.errors.species = true;
+        return;
+      } else if (!/^\d+$/.test(vm.condensate.species)) {
+        vm.condensate.errorMsg = 'Species should be numbers!';
+        vm.condensate.errors.species = true;
+        return;
+      } else if (vm.condensate.synonyms === '') {
+        vm.condensate.errorMsg =
+          'Synonyms should not be empty! (Separate with comma)';
+        vm.condensate.errors.synonyms = true;
+        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,
+          SpeciesTaxId: vm.condensate.species,
+          Proteins: vm.proteinList,
+          Synonyms: vm.condensate.synonyms,
+          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,
+          SpeciesTaxId: vm.condensate.species,
+          Proteins: vm.proteinList,
+          Synonyms: vm.condensate.synonyms,
+          SubmissionComments: vm.condensate.comments,
+        };
+      }
+      vm.isLoading = true;
+      try {
+        await vm.axios.post(
+          url,
+          { data: data },
+          {
+            headers: {
+              Authorization: `Bearer ${vm.jwt}`,
+            },
+          }
+        );
+
+        vm.isLoading = false;
+        vm.toasterIsOpen = true;
+        vm.toasterMessage = 'Condensate added successfully!';
+        vm.condensate.is_experimental = false;
+        vm.condensate.name = vm.condensate.species = vm.condensate.synonyms = vm.condensate.comments = '';
+        vm.$emit('hide')
+
+        setTimeout(() => {
+          vm.toasterIsOpen = false;
+        }, 2000);
+      } catch (e) {
+        console.error(e);
+        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');
+
+.mainContent {
+  padding: 20px;
+}
+</style>
\ No newline at end of file
diff --git a/web/src/components/LandingPage.vue b/web/src/components/LandingPage.vue
index 7a13d55..ca0b50d 100644
--- a/web/src/components/LandingPage.vue
+++ b/web/src/components/LandingPage.vue
@@ -220,12 +220,12 @@ export default {
     proteinNameList: {
       get() {
         return _.map(this.proteinList, (d) => {
-          return { text: d.proteinName };
+          return { text: d.uniprot_id };
         });
       },
       set(obj) {
         const idx = this.proteinList.findIndex(
-          (d) => d.proteinName === obj.tag.text
+          (d) => d.uniprot_id === obj.tag.text
         );
         this.$store.dispatch('Param/removeProtein', idx);
         obj.deleteTag();
diff --git a/web/src/components/Links.vue b/web/src/components/Links.vue
index 8b0f8ad..a6ef11c 100644
--- a/web/src/components/Links.vue
+++ b/web/src/components/Links.vue
@@ -247,6 +247,15 @@
         <span class="text-2xl">Help</span>
       </router-link>
     </li>
+<!--    <li-->
+<!--      role="presentation"-->
+<!--      :class="{ active: $route.name === 'test' }"-->
+<!--      @mouseover="openCondensateSubMenu = false"-->
+<!--    >-->
+<!--      <router-link to="/test/P62750">-->
+<!--        <span class="text-2xl">Test</span>-->
+<!--      </router-link>-->
+<!--    </li>-->
     <li
       v-show="userData !== null"
       role="presentation"
diff --git a/web/src/components/ProteinDetailPage.vue b/web/src/components/ProteinDetailPage.vue
index 52d26ca..b2a4ee2 100644
--- a/web/src/components/ProteinDetailPage.vue
+++ b/web/src/components/ProteinDetailPage.vue
@@ -419,177 +419,7 @@
                   v-if="showAddCondensate"
                   class="panel panel-default mt-4"
                 >
-                  <div class="panel-body">
-                    <div class="container-fluid col-md-12">
-                      <form
-                        class="form-horizontal"
-                        autocomplete="off"
-                        @submit.prevent="addCondensate(response)"
-                      >
-                        <div v-if="isLoading">
-                          <base-spinner />
-                        </div>
-                        <div class="form-group">
-                          <label
-                            class="control-label col-sm-2"
-                            for="condensate_is_experimental"
-                          >Synthetic?</label>
-                          <div class="col-sm-4 pt-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"
-                            >Yes</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"
-                            >No</label>
-                          </div>
-                        </div>
-                        <div class="form-group">
-                          <label
-                            class="control-label col-sm-2"
-                            for="condensate_name"
-                          >Condensate Name</label>
-                          <div class="col-sm-4">
-                            <input
-                              id="condensate_name"
-                              v-model.trim="condensate.name"
-                              class="form-control input-sm"
-                              type="text"
-                              placeholder="Name"
-                            >
-                          </div>
-                          <p
-                            v-if="isUniProtIdError"
-                            class="text-red-600 mt-4 font-bold"
-                          >
-                            {{ uniprotIdErrorMsg }}
-                          </p>
-                        </div>
-                        <div class="form-group">
-                          <label
-                            class="control-label col-sm-2"
-                            for="condensate_species"
-                          >Species</label>
-                          <div class="col-sm-4">
-                            <input
-                              id="condensate_species"
-                              v-model.trim="condensate.species"
-                              class="form-control input-sm"
-                              type="text"
-                              placeholder="Species (NCBI taxonomy ID)"
-                            >
-                          </div>
-                        </div>
-                        <div class="form-group">
-                          <label
-                            class="control-label col-sm-2"
-                            for="condensate_synonyms"
-                          >Synonyms</label>
-                          <div class="col-sm-4">
-                            <input
-                              id="condensate_synonyms"
-                              v-model.trim="condensate.synonyms"
-                              class="form-control input-sm"
-                              type="text"
-                              placeholder="Synonyms (comma-separated)"
-                            >
-                          </div>
-                        </div>
-                        <div class="form-group">
-                          <label
-                            class="control-label col-sm-2"
-                            for="condensate_comments"
-                          >Comments</label>
-                          <div class="col-sm-8">
-                            <textarea
-                              id="condensate_comments"
-                              v-model.trim="condensate.comments"
-                              class="
-                                form-control
-                                block
-                                px-3
-                                py-1.5
-                                text-base
-                                font-normal
-                                text-gray-700
-                                bg-white bg-clip-padding
-                                border border-solid border-gray-300
-                                rounded
-                                transition
-                                ease-in-out
-                                m-0
-                                focus:text-gray-700
-                                focus:bg-white
-                                focus:border-blue-600
-                                focus:outline-none
-                              "
-                              rows="5"
-                              :placeholder="
-                                getUserData === 'Maintainer'
-                                  ? 'Optional.'
-                                  : 'Mandatory.'
-                              "
-                            />
-
-                            <div class="flex space-x-4">
-                              <button
-                                id="dropdownMenuButton"
-                                class="
-                                    text-white
-                                    bg-blue-500
-                                    hover:bg-blue-700
-                                    focus:ring-2 focus:ring-blue-300
-                                    rounded-lg
-                                    inline-flex
-                                    items-center
-                                    px-5
-                                    py-2.5
-                                    text-center
-                                    font-bold
-                                  "
-                                type="submit"
-                              >
-                                Add
-                              </button>
-                              <button
-                                id="dropdownMenuButton"
-                                class="
-                                    bg-white
-                                    hover:bg-gray-200
-                                    focus:ring-2 focus:ring-gray-300
-                                    rounded-lg
-                                    border border-gray-300
-                                    px-5
-                                    py-2.5
-                                    hover:text-gray-900
-                                    font-bold
-                                  "
-                                type="button"
-                                @click="showAddCondensate = !showAddCondensate"
-                              >
-                                Cancel
-                              </button>
-                            </div>
-                          </div>
-                        </div>
-                      </form>
-                    </div>
-                  </div>
+                  <add-novel-condensate :protein="response.data.uniprot_id" @hide="showAddCondensate = false"/>
                 </div>
                 <div class="panel panel-default">
                   <table class="csi table table-hover table-responsive">
@@ -655,6 +485,7 @@ import AddDeletePubmed from './CMS/addDeletePubmed.vue';
 //import FetchUserSpecificUpdateItems from './CMS/fetchUserSpecificUpdateItems.vue';
 import ProteinUpdateItemTable from './ProteinUpdateItemTable.vue';
 import BaseSpinner from './UI/BaseSpinner.vue';
+import AddNovelCondensate  from "@/components/AddNovelCondensate";
 import {apiHost as host} from '@/components/js/const';
 //import BaseToaster from "./UI/BaseToaster.vue";
 
@@ -673,6 +504,7 @@ export default {
 
     ProteinUpdateItemTable,
     BaseSpinner,
+    AddNovelCondensate
     
   },
   props: ['proteinId'],
@@ -684,8 +516,16 @@ export default {
         name: '',
         is_experimental: false,
         species: '',
+        protein: '',
         synonyms: [],
         comments: '',
+        errors: {
+          name: false,
+          species: false,
+          synonyms: false,
+          comments: false,
+        },
+        errorMsg: ''
       },
       showUpdateFunctionType: false,
       showAddOrDeletePubmedId: false,
@@ -782,123 +622,6 @@ export default {
           });
       }
     },
-    async addCondensate(response) {
-      if (this.condensate.name === '') {
-        this.uniprotIdErrorMsg = 'Condensate name should not be empty!';
-        this.isUniProtIdError = true;
-        return;
-      } else if (this.uniprotId.length < 6) {
-        this.uniprotIdErrorMsg = 'Uniprot ID should be minimum of 6 character.';
-        this.isUniProtIdError = true;
-        return;
-      } else if (this.uniprotId.length > 10) {
-        this.uniprotIdErrorMsg =
-          'Uniprot ID should be maximum of 10 character.';
-        this.isUniProtIdError = true;
-        return;
-      } else if (this.whitespaceRegex.test(this.uniprotId)) {
-        this.uniprotIdErrorMsg = 'Uniprot ID should not have space in between.';
-        this.isUniProtIdError = true;
-        return;
-      }
-
-      const findUniprotId = response.data.proteins.find(
-        (u) => u.uniprot_id === this.uniprotId
-      );
-      if (findUniprotId) {
-        this.message = '';
-        this.uniprotIdErrorMsg = 'The Uniprot ID already exists!';
-        this.isUniProtIdError = true;
-        return;
-      }
-
-      this.isError = false;
-      if (this.isDev) {
-        host = require('./js/const').devApiHost;
-      }
-      let url = `${host}/api/update-items`;
-      let data;
-      if (this.getUserData === 'Maintainer') {
-        data = {
-          Entity: 'condensate',
-          EntityId: response.data.canonical_id,
-          ChangeOperation: 'add',
-          Attribute: 'proteins',
-          Value: this.uniprotId,
-          SubmissionComments:
-            'Maintainer do not need to provide a reason for such change at the moment!',
-          Status: 'accepted',
-        };
-      } else {
-        if (this.proteinComment === '' || this.proteinComment.length < 50) {
-          this.proteinCommentErr = true;
-          this.commentErrorMsg =
-            'Reason should not be empty or less than 50 characters!';
-
-          return;
-        }
-        data = {
-          Entity: 'condensate',
-          EntityId: response.data.canonical_id,
-          ChangeOperation: 'add',
-          Attribute: 'proteins',
-          Value: this.uniprotId,
-          SubmissionComments: this.proteinComment,
-          Status: 'requested',
-        };
-      }
-      this.isLoading = true;
-      try {
-        await this.axios.post(
-          url,
-          { data: data },
-          {
-            headers: {
-              Authorization: `Bearer ${this.jwt}`,
-            },
-          }
-        );
-
-        this.isLoading = false;
-        this.toasterIsOpen = true;
-
-        this.error = false;
-        this.isSubmitted = true;
-        this.uniprotId = '';
-        this.comment = '';
-        this.proteinCommentErr = false;
-        this.commentErrorMsg = '';
-        this.updatedKey += 1;
-        setTimeout(() => {
-          this.toasterIsOpen = false;
-        }, 2000);
-      } catch (e) {
-        console.error(e);
-        this.message =
-          e.message || 'Something went wrong, please try again later!';
-        this.isSubmitted = true;
-        this.error = true;
-      }
-
-      //       try {
-      //         const res=await this.axios.get(
-      //           `${host}
-      // /api/update-item/findCondensate/${response.data.canonical_id}`,
-
-      //           {
-      //             headers: {
-      //               Authorization: `Bearer ${this.jwt}`,
-      //             },
-      //           }
-      //         );
-
-      //       console.log(await res)
-
-      //       } catch (e) {
-      //         console.error(e);
-
-      //       }
-    },
   },
 };
 </script>
diff --git a/web/src/components/TagsInput.vue b/web/src/components/TagsInput.vue
new file mode 100644
index 0000000..c5ed0b7
--- /dev/null
+++ b/web/src/components/TagsInput.vue
@@ -0,0 +1,94 @@
+<template>
+  <vue-tags-input
+    v-model="labelTag"
+    placeholder=""
+    :tags="value"
+    :autocomplete-items="autocompleteItems"
+    :add-only-from-autocomplete="true"
+    :disabled="false"
+    @before-adding-tag="obj => addObj(obj)"
+    @before-deleting-tag="obj => removeObj(obj)"
+  />
+</template>
+
+<script>
+import VueTagsInput from '@johmun/vue-tags-input';
+import _ from 'lodash';
+const apikey = require('./js/const').apikey;
+
+export default {
+  name: 'TagsInput',
+  components: {
+    VueTagsInput,
+  },
+  props: {
+    value: { required: true },
+  },
+  data() {
+    return {
+      labelTag: '',
+      autocompleteItems: [],
+      isDev: process.env.NODE_ENV === 'development',
+    };
+  },
+  computed: {
+  },
+  watch: {
+    labelTag: function (newVal, oldVal) {
+      const vm = this;
+      vm.search(newVal);
+    }
+  },
+  methods: {
+    addObj(obj) {
+      const vm = this;
+      this.$store.dispatch('Param/addProtein', { proteinName: obj.tag.proteinName });
+      vm.labelTag = '';
+    },
+    removeObj(obj) {
+      this.$emit('input', obj);
+    },
+    search(query) {
+      const vm = this
+
+      let host = vm.isDev
+        ? require('./js/const').devHost
+        : require('./js/const').host;
+
+      let url = `${host}/proteins?fields=uniprot_id,gene_name,name&query=${query}&size=10000`;
+
+      fetch(url, {
+        method: 'GET',
+        mode: 'cors',
+        cache: 'no-cache',
+        headers: {
+          Authorization: `Bearer ${apikey}`,
+        },
+      })
+        .then((response) => response.json())
+        .then((json) => {
+          vm.autocompleteItems = [];
+          vm.autocompleteItems = _.uniq(_.map(json.data, (c) => {
+            return {'text': c.uniprot_id, 'name': c.name, 'gene_name': c.gene_name, 'proteinName': c.uniprot_id}
+          }), 'text')
+        })
+    },
+  },
+};
+</script>
+
+<style>
+.vue-tags-input .ti-input {
+  border: none;
+  border-bottom: 1px solid #a4b1b6;
+  padding: 4px;
+}
+
+.ti-new-tag-input-wrapper[data-v-61d92e31] {
+  display: flex;
+  flex: 1 0 auto;
+  padding: 0px;
+  margin: 2px;
+  font-size: .85em;
+}
+</style>
\ No newline at end of file
diff --git a/web/src/router/index.js b/web/src/router/index.js
index 99d51cf..54a71e4 100644
--- a/web/src/router/index.js
+++ b/web/src/router/index.js
@@ -132,6 +132,11 @@ export default new Router({
       name: 'updateUser',
       component: () => import('@/views/UpdateUser'),
     },
+    // {
+    //   path: '/test/:protein',
+    //   name: 'test',
+    //   component: () => import('@/components/AddNovelCondensate'),
+    // },
     // { path: '/user/:id', component: User },
     // {
     //   path: '*',
diff --git a/web/src/store/modules/Param.js b/web/src/store/modules/Param.js
new file mode 100644
index 0000000..5457583
--- /dev/null
+++ b/web/src/store/modules/Param.js
@@ -0,0 +1,46 @@
+const namespaced = true
+
+const state = {
+  proteinList: [],
+}
+
+const mutations = {
+  ADD_PROTEIN (state, protein) {
+    if(state.proteinList.findIndex(d => d.uniprot_id === protein.uniprot_id) < 0) {
+      state.proteinList.push({uniprot_id: protein.uniprot_id,
+        functional_type: protein.functional_type,
+        proteins: protein.proteins,
+        pubmed_ids: protein.pubmed_ids,
+        driver_criterion: protein.driver_criterion,
+        experimental_evidences: protein.experimental_evidences,
+      })
+    }
+  },
+  REMOVE_PROTEIN (state, proteinIdx) {
+    state.proteinList.splice(proteinIdx, 1);
+  },
+}
+
+const getters = {
+  proteinList: state => state.proteinList,
+}
+
+const actions = {
+  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
+}
-- 
GitLab