You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2020/05/12 22:45:30 UTC

[airavata-django-portal] 01/04: AIRAVATA-3324 Add AutocompleteInputEditor

This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch AIRAVATA-3324-custom-input-editor-autocomplete-input-editor
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 738ad5d027b1b42eb308f7a7cab10e22cf5f71dd
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Mon Apr 27 16:04:35 2020 -0400

    AIRAVATA-3324 Add AutocompleteInputEditor
---
 .../input-editors/AutocompleteInputEditor.vue      | 126 +++++++++++++++++++++
 .../input-editors/InputEditorContainer.vue         |   4 +-
 .../common/js/components/AutocompleteTextInput.vue |   9 +-
 3 files changed, 136 insertions(+), 3 deletions(-)

diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/AutocompleteInputEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/AutocompleteInputEditor.vue
new file mode 100644
index 0000000..067bb24
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/AutocompleteInputEditor.vue
@@ -0,0 +1,126 @@
+<template>
+  <!-- TODO: replace with better display and x to clear out selected value -->
+  <div v-if="value">
+    {{ text }}
+    <b-link @click="cancel">Cancel</b-link>
+  </div>
+  <div v-else>
+    <autocomplete-text-input
+      :suggestions="suggestions"
+      @selected="selected"
+      @search-changed="searchChanged"
+      :max-matches="10"
+    />
+  </div>
+</template>
+
+<script>
+import { utils } from "django-airavata-api";
+import { InputEditorMixin } from "django-airavata-workspace-plugin-api";
+import { components } from "django-airavata-common-ui";
+
+export default {
+  name: "autocomplete-input-editor",
+  mixins: [InputEditorMixin],
+  components: {
+    "autocomplete-text-input": components.AutocompleteTextInput
+  },
+  props: {
+    value: {
+      type: String
+    }
+  },
+  data() {
+    return {
+      text: null,
+      searchString: "",
+      searchResults: null,
+      lastUpdate: Date.now()
+    };
+  },
+  computed: {
+    suggestions() {
+      return this.searchResults
+        ? this.searchResults.results.map(r => {
+            return {
+              id: r.value,
+              name: r.text
+            };
+          })
+        : [];
+    },
+    autocompleteUrl() {
+      if (
+        this.experimentInput.editorConfig &&
+        "url" in this.experimentInput.editorConfig
+      ) {
+        return this.experimentInput.editorConfig.url;
+      } else {
+        // eslint-disable-next-line no-console
+        console.warn(
+          "editor config is missing 'url'. Make sure input " +
+            this.experimentInput.name +
+            " has metadata configuration something like:\n" +
+            JSON.stringify(
+              {
+                editor: {
+                  "ui-component-id": "autocomplete-input-editor",
+                  config: {
+                    url: "/some/custom/search/"
+                  }
+                }
+              },
+              null,
+              4
+            )
+        );
+        return null;
+      }
+    }
+  },
+  methods: {
+    loadTextForValue(value) {
+      if (this.autocompleteUrl) {
+        return utils.FetchUtils.get(this.autocompleteUrl, {
+          id: value
+        }).then(resp => resp.text);
+      } else {
+        return Promise.resolve(null);
+      }
+    },
+    cancel() {
+      this.data = null;
+      this.valueChanged();
+    },
+    selected(suggestion) {
+      this.data = suggestion.id;
+      this.text = suggestion.name;
+      this.valueChanged();
+    },
+    searchChanged(newValue) {
+      this.searchString = newValue;
+      const currentTime = Date.now();
+      if (this.autocompleteUrl) {
+        utils.FetchUtils.get(
+          this.autocompleteUrl,
+          {
+            search: this.searchString
+          },
+          { showSpinner: false }
+        ).then(resp => {
+          // Prevent older responses from overwriting newer ones
+          if (currentTime > this.lastUpdate) {
+            this.searchResults = resp;
+            this.lastUpdate = currentTime;
+          }
+        });
+      }
+    }
+  },
+  created() {
+    if (this.value) {
+      this.loadTextForValue(this.value).then(text => (this.text = text));
+    }
+  }
+};
+</script>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/InputEditorContainer.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/InputEditorContainer.vue
index 44b4489..afb7571 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/InputEditorContainer.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/InputEditorContainer.vue
@@ -17,6 +17,7 @@
 <script>
 
 import UserFileInputEditor from "./UserFileInputEditor.vue";
+import AutocompleteInputEditor from "./AutocompleteInputEditor";
 import CheckboxInputEditor from "./CheckboxInputEditor.vue";
 import FileInputEditor from './FileInputEditor.vue'
 import InputEditorFormGroup from './InputEditorFormGroup.vue'
@@ -43,8 +44,8 @@ export default {
         }
     },
     components: {
+        AutocompleteInputEditor,
         CheckboxInputEditor,
-        UserFileInputEditor,
         FileInputEditor,
         InputEditorFormGroup,
         MultiFileInputEditor,
@@ -52,6 +53,7 @@ export default {
         SelectInputEditor,
         StringInputEditor,
         TextareaInputEditor,
+        UserFileInputEditor,
     },
     created() {
       if (!this.show) {
diff --git a/django_airavata/static/common/js/components/AutocompleteTextInput.vue b/django_airavata/static/common/js/components/AutocompleteTextInput.vue
index 59071e6..5579af0 100644
--- a/django_airavata/static/common/js/components/AutocompleteTextInput.vue
+++ b/django_airavata/static/common/js/components/AutocompleteTextInput.vue
@@ -8,7 +8,7 @@
         @keydown.native.down='down' @keydown.native.up='up'></b-form-input>
     </b-input-group>
     <b-list-group class="autocomplete-suggestion-list" v-if="open">
-      <b-list-group-item v-for="(suggestion, index) in filtered.slice(0,5)" v-bind:class="{'active': isActive(index)}" href="#"
+      <b-list-group-item v-for="(suggestion, index) in filtered" v-bind:class="{'active': isActive(index)}" href="#"
         @click="suggestionClick(index)" v-bind:key="suggestion.id">
         <slot name="suggestion" :suggestion="suggestion">
           {{ suggestion.name }}
@@ -29,6 +29,10 @@ export default {
     placeholder: {
       type: String,
       default: "Type to get suggestions..."
+    },
+    maxMatches: {
+      type: Number,
+      default: 5
     }
   },
   data() {
@@ -46,7 +50,7 @@ export default {
         return (
           data.name.toLowerCase().indexOf(this.searchValue.toLowerCase()) >= 0
         );
-      }).slice(0,5);
+      }).slice(0,this.maxMatches);
     }
   },
   methods: {
@@ -59,6 +63,7 @@ export default {
         this.open = false;
       }
       this.searchValue = value;
+      this.$emit('search-changed', value);
     },
     enter() {
       if (this.filtered.length === 0) {