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

machristie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 1c766b442bdb03b39deb6d10284bde5956b1bbb5
Author: Marcus Christie <machr...@iu.edu>
AuthorDate: Wed Jul 11 11:24:54 2018 -0400

    AIRAVATA-2835 AutocompleteTextInput factored out to display groups
---
 .../api/static/django_airavata_api/js/index.js     |   4 +
 .../js/models/GroupPermission.js                   |  18 ++++
 .../django_airavata_api/js/models/SharedEntity.js  |  33 +-----
 .../js/models/UserPermission.js                    |  18 ++++
 .../js/group_components/GroupEditor.vue            |   5 +-
 .../js/utils/Autocomplete.vue                      | 113 ---------------------
 .../static/common/js/components/Autocomplete.vue   |  66 ++----------
 .../common/js/components/AutocompleteTextInput.vue | 103 +++++++++++++++++++
 .../static/common/js/components/ShareButton.vue    |  44 +++++++-
 django_airavata/static/common/js/index.js          |   2 +
 10 files changed, 202 insertions(+), 204 deletions(-)

diff --git a/django_airavata/apps/api/static/django_airavata_api/js/index.js 
b/django_airavata/apps/api/static/django_airavata_api/js/index.js
index 5181ad9..12c643b 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/index.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/index.js
@@ -6,12 +6,14 @@ import Experiment from './models/Experiment'
 import ExperimentState from './models/ExperimentState'
 import FullExperiment from './models/FullExperiment'
 import Group from './models/Group'
+import GroupPermission from './models/GroupPermission'
 import GroupResourceProfile from './models/GroupResourceProfile'
 import InputDataObjectType from './models/InputDataObjectType'
 import OutputDataObjectType from './models/OutputDataObjectType'
 import Project from './models/Project'
 import ResourcePermissionType from './models/ResourcePermissionType'
 import SharedEntity from './models/SharedEntity'
+import UserPermission from './models/UserPermission'
 
 import ApplicationDeploymentService from 
'./services/ApplicationDeploymentService'
 import ApplicationInterfaceService from 
'./services/ApplicationInterfaceService'
@@ -44,12 +46,14 @@ exports.models = {
     ExperimentState,
     FullExperiment,
     Group,
+    GroupPermission,
     GroupResourceProfile,
     InputDataObjectType,
     OutputDataObjectType,
     Project,
     ResourcePermissionType,
     SharedEntity,
+    UserPermission,
 }
 
 exports.services = {
diff --git 
a/django_airavata/apps/api/static/django_airavata_api/js/models/GroupPermission.js
 
b/django_airavata/apps/api/static/django_airavata_api/js/models/GroupPermission.js
new file mode 100644
index 0000000..70e1e26
--- /dev/null
+++ 
b/django_airavata/apps/api/static/django_airavata_api/js/models/GroupPermission.js
@@ -0,0 +1,18 @@
+import BaseModel from './BaseModel';
+import Group from './Group';
+import ResourcePermissionType from './ResourcePermissionType';
+
+export default class GroupPermission extends BaseModel {
+    constructor(data = {}) {
+        super([
+            {
+                name: 'group',
+                type: Group,
+            },
+            {
+                name: 'permissionType',
+                type: ResourcePermissionType,
+            }
+        ], data);
+    }
+}
diff --git 
a/django_airavata/apps/api/static/django_airavata_api/js/models/SharedEntity.js 
b/django_airavata/apps/api/static/django_airavata_api/js/models/SharedEntity.js
index fd7744e..41e4d19 100644
--- 
a/django_airavata/apps/api/static/django_airavata_api/js/models/SharedEntity.js
+++ 
b/django_airavata/apps/api/static/django_airavata_api/js/models/SharedEntity.js
@@ -1,37 +1,8 @@
 import BaseModel from './BaseModel';
-import Group from './Group';
-import ResourcePermissionType from './ResourcePermissionType';
+import GroupPermission from './GroupPermission';
+import UserPermission from './UserPermission';
 import UserProfile from './UserProfile';
 
-class UserPermission extends BaseModel {
-    constructor(data = {}) {
-        super([
-            {
-                name: 'user',
-                type: UserProfile,
-            },
-            {
-                name: 'permissionType',
-                type: ResourcePermissionType,
-            }
-        ], data);
-    }
-}
-
-class GroupPermission extends BaseModel {
-    constructor(data = {}) {
-        super([
-            {
-                name: 'group',
-                type: Group,
-            },
-            {
-                name: 'permissionType',
-                type: ResourcePermissionType,
-            }
-        ], data);
-    }
-}
 
 const FIELDS = [
     'entityId',
diff --git 
a/django_airavata/apps/api/static/django_airavata_api/js/models/UserPermission.js
 
b/django_airavata/apps/api/static/django_airavata_api/js/models/UserPermission.js
new file mode 100644
index 0000000..3b35e37
--- /dev/null
+++ 
b/django_airavata/apps/api/static/django_airavata_api/js/models/UserPermission.js
@@ -0,0 +1,18 @@
+import BaseModel from './BaseModel';
+import ResourcePermissionType from './ResourcePermissionType';
+import UserProfile from './UserProfile';
+
+export default class UserPermission extends BaseModel {
+    constructor(data = {}) {
+        super([
+            {
+                name: 'user',
+                type: UserProfile,
+            },
+            {
+                name: 'permissionType',
+                type: ResourcePermissionType,
+            }
+        ], data);
+    }
+}
diff --git 
a/django_airavata/apps/groups/static/django_airavata_groups/js/group_components/GroupEditor.vue
 
b/django_airavata/apps/groups/static/django_airavata_groups/js/group_components/GroupEditor.vue
index 747a8ee..b573eb9 100644
--- 
a/django_airavata/apps/groups/static/django_airavata_groups/js/group_components/GroupEditor.vue
+++ 
b/django_airavata/apps/groups/static/django_airavata_groups/js/group_components/GroupEditor.vue
@@ -17,7 +17,7 @@
       </b-form-group>
 
       <b-form-group id="group3" label="Add Members:" label-for="members">
-        <autocomplete id="members" :suggestions="suggestions" 
v-model="localGroup.members"></autocomplete>
+        <autocomplete id="members" :suggestions="suggestions" 
v-model="localGroup.members"/>
       </b-form-group>
 
       <b-button @click="submitForm" variant="primary">Submit</b-button>
@@ -28,8 +28,9 @@
 <script>
 
 import { models, services } from 'django-airavata-api'
+import { components as comps } from 'django-airavata-common-ui'
 
-import Autocomplete from '../utils/Autocomplete.vue'
+const Autocomplete = comps.Autocomplete;
 
 export default {
     props: {
diff --git 
a/django_airavata/apps/groups/static/django_airavata_groups/js/utils/Autocomplete.vue
 
b/django_airavata/apps/groups/static/django_airavata_groups/js/utils/Autocomplete.vue
deleted file mode 100644
index 12e57cb..0000000
--- 
a/django_airavata/apps/groups/static/django_airavata_groups/js/utils/Autocomplete.vue
+++ /dev/null
@@ -1,113 +0,0 @@
-<template>
-    <div style="position:relative">
-        <span class="selected-cards" style="position:relative">
-          <b-button variant="warning" v-for="item in selected" 
v-bind:key="item.id" @click="removeClick(item)">
-             {{ item.name }} <b-badge variant="light"><a 
href="#">x</a></b-badge>
-          </b-button>
-        </span>
-        <hr>
-        <input class="form-control" type="text" :value="searchValue" 
placeholder="Type to get suggestions..." 
@input="updateSearchValue($event.target.value)"
-          @keydown.enter = 'enter'
-          @keydown.down = 'down'
-          @keydown.up = 'up'
-        >
-        <b-list-group style="width: 100%;" v-if="open">
-            <b-list-group-item v-for="(suggestion, index) in 
filtered.slice(0,5)" v-bind:class="{'active': isActive(index)}" href="#" 
@click="suggestionClick(index)" v-bind:key="suggestion.id">
-              {{ suggestion.name }}
-            </b-list-group-item>
-        </b-list-group>
-    </div>
-</template>
-
-<script>
-
-export default {
-
-  props: {
-    value: {
-      type: Array,
-      required: false
-    },
-
-    suggestions: {
-      type: Array,
-      required: true
-    }
-  },
-
-  data () {
-    return {
-      open: false,
-      current: 0,
-      localValue: this.value ? this.value.slice() : [],
-      searchValue: '',
-    }
-  },
-
-  computed: {
-    filtered () {
-      return this.suggestions.filter((data) => {
-        return data.name.indexOf(this.searchValue) >= 0
-      })
-    },
-    selected () {
-        return this.suggestions.filter((suggestion) => {
-            return this.localValue.indexOf(suggestion.id) >= 0;
-        });
-    }
-  },
-  methods: {
-    updateSearchValue (value) {
-      if (this.open === false) {
-        this.open = true
-        this.current = 0
-      }
-      if(value===''){
-        this.open = false;
-      }
-      this.searchValue = value;
-    },
-    enter () {
-      var index = this.suggestions.indexOf(this.filtered[this.current].name);
-      if(this.localValue.indexOf(this.filtered[this.current].id)==-1){
-        this.localValue.push(this.filtered[this.current].id);
-      }
-      this.$emit('input',this.localValue);
-      this.searchValue = '';
-      this.open = false
-    },
-    up () {
-      if (this.current > 0) {
-        this.current--
-      }
-    },
-    down () {
-      if (this.current < this.filtered.length - 1) {
-        this.current++
-      }
-    },
-    isActive (index) {
-      return index === this.current
-    },
-    suggestionClick (index) {
-      if(this.localValue.indexOf(this.filtered[index].id)==-1) {
-        this.localValue.push(this.filtered[index].id);
-      }
-      this.$emit('input',this.localValue);
-      this.searchValue = '';
-      this.open = false;
-    },
-    removeClick(data) {
-      var index = this.localValue.indexOf(data.id);
-      this.localValue.splice(index,1);
-      this.$emit('input',this.localValue);
-    }
-  }
-}
-
-</script>
-<style>
-.selected-cards > button + button {
-    margin-left: 10px;
-}
-</style>
diff --git a/django_airavata/static/common/js/components/Autocomplete.vue 
b/django_airavata/static/common/js/components/Autocomplete.vue
index 2e9b479..b5e74e0 100644
--- a/django_airavata/static/common/js/components/Autocomplete.vue
+++ b/django_airavata/static/common/js/components/Autocomplete.vue
@@ -6,23 +6,16 @@
           </b-button>
         </span>
         <hr>
-        <input class="form-control" type="text" :value="searchValue" 
placeholder="Type to get suggestions..." 
@input="updateSearchValue($event.target.value)"
-          @keydown.enter = 'enter'
-          @keydown.down = 'down'
-          @keydown.up = 'up'
-        >
-        <b-list-group style="width: 100%;" v-if="open">
-            <b-list-group-item v-for="(suggestion, index) in 
filtered.slice(0,5)" v-bind:class="{'active': isActive(index)}" href="#" 
@click="suggestionClick(index)" v-bind:key="suggestion.id">
-              {{ suggestion.name }}
-            </b-list-group-item>
-        </b-list-group>
+        <autocomplete-text-input :suggestions="suggestions" 
@selected="suggestionSelected"/>
     </div>
 </template>
 
 <script>
+import AutocompleteTextInput from './AutocompleteTextInput.vue'
 
 export default {
 
+  name: 'autocomplete',
   props: {
     value: {
       type: Array,
@@ -38,20 +31,13 @@ export default {
   data () {
       console.log("Value",this.value.length);
     return {
-      open: false,
-      current: 0,
       localValue: this.value,
-      searchValue: '',
     }
   },
-
+  components: {
+      AutocompleteTextInput,
+  },
   computed: {
-    filtered () {
-        console.log("local Value",this.localValue.length);
-      return this.suggestions.filter((data) => {
-        return data.name.indexOf(this.searchValue) >= 0
-      })
-    },
     selected () {
         console.log("local Value",this.localValue.length);
         return this.suggestions.filter((suggestion) => {
@@ -60,45 +46,11 @@ export default {
     }
   },
   methods: {
-    updateSearchValue (value) {
-      if (this.open === false) {
-        this.open = true
-        this.current = 0
-      }
-      if(value===''){
-        this.open = false;
-      }
-      this.searchValue = value;
-    },
-    enter () {
-      var index = this.suggestions.indexOf(this.filtered[this.current].name);
-      if(this.localValue.indexOf(this.filtered[this.current].id)==-1){
-        this.localValue.push(this.filtered[this.current].id);
-      }
-      this.$emit('input',this.localValue);
-      this.searchValue = '';
-      this.open = false
-    },
-    up () {
-      if (this.current > 0) {
-        this.current--
-      }
-    },
-    down () {
-      if (this.current < this.filtered.length - 1) {
-        this.current++
-      }
-    },
-    isActive (index) {
-      return index === this.current
-    },
-    suggestionClick (index) {
-      if(this.localValue.indexOf(this.filtered[index].id)==-1) {
-        this.localValue.push(this.filtered[index].id);
+    suggestionSelected (suggestion) {
+      if(this.localValue.indexOf(suggestion.id)==-1) {
+        this.localValue.push(suggestion.id);
       }
       this.$emit('input',this.localValue);
-      this.searchValue = '';
-      this.open = false;
     },
     removeClick(data) {
       var index = this.localValue.indexOf(data.id);
diff --git 
a/django_airavata/static/common/js/components/AutocompleteTextInput.vue 
b/django_airavata/static/common/js/components/AutocompleteTextInput.vue
new file mode 100644
index 0000000..ca8dd20
--- /dev/null
+++ b/django_airavata/static/common/js/components/AutocompleteTextInput.vue
@@ -0,0 +1,103 @@
+<template>
+    <div class="autocomplete-text-input">
+        <b-input-group>
+            <b-input-group-addon>
+                <i class="fa fa-search"></i>
+            </b-input-group-addon>
+            <b-form-input type="text" :value="searchValue" placeholder="Type 
to get suggestions..."
+              @input="updateSearchValue"
+              @keydown.enter = 'enter'
+              @keydown.down = 'down'
+              @keydown.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="#" @click="suggestionClick(index)" 
v-bind:key="suggestion.id">
+              <slot name="suggestion" :suggestion="suggestion">
+                  {{ suggestion.name }}
+              </slot>
+            </b-list-group-item>
+        </b-list-group>
+    </div>
+</template>
+
+<script>
+
+export default {
+
+  name: 'autocomplete-text-input',
+  props: {
+    suggestions: {
+      type: Array,
+      required: true
+    }
+  },
+  data () {
+    return {
+      open: false,
+      current: 0,
+      searchValue: '',
+    }
+  },
+
+  computed: {
+    filtered () {
+      return this.suggestions.filter((data) => {
+        return data.name.indexOf(this.searchValue) >= 0
+      })
+    },
+  },
+  methods: {
+    updateSearchValue (value) {
+      if (this.open === false) {
+        this.open = true
+        this.current = 0
+      }
+      if(value===''){
+        this.open = false;
+      }
+      this.searchValue = value;
+    },
+    enter () {
+      this.emitSelectedItem(index);
+      this.searchValue = '';
+      this.open = false
+    },
+    up () {
+      if (this.current > 0) {
+        this.current--
+      }
+    },
+    down () {
+      if (this.current < this.filtered.length - 1) {
+        this.current++
+      }
+    },
+    isActive (index) {
+      return index === this.current
+    },
+    suggestionClick (index) {
+      this.emitSelectedItem(index);
+      this.searchValue = '';
+      this.open = false;
+    },
+    emitSelectedItem(index) {
+        this.$emit('selected', this.filtered[index]);
+    }
+  },
+}
+
+</script>
+
+<style scoped>
+.autocomplete-text-input {
+    position: relative;
+}
+.autocomplete-suggestion-list {
+    width: 100%;
+    position: absolute;
+    z-index: 1;
+}
+</style>
diff --git a/django_airavata/static/common/js/components/ShareButton.vue 
b/django_airavata/static/common/js/components/ShareButton.vue
index 03b2928..494f003 100644
--- a/django_airavata/static/common/js/components/ShareButton.vue
+++ b/django_airavata/static/common/js/components/ShareButton.vue
@@ -5,6 +5,17 @@
             <b-badge>{{ totalCount }}</b-badge>
         </b-button>
         <b-modal id="modal-share-settings" title="Sharing Settings">
+            <b-form-group label="Search for groups" 
labelFor="user-groups-autocomplete">
+                <autocomplete-text-input id="user-groups-autocomplete"
+                    :suggestions="groupSuggestions"
+                    @selected="suggestionSelected">
+                    <template slot="suggestion" slot-scope="slotProps">
+                        <span v-if="slotProps.suggestion.type == 'group'">
+                            <i class="fa fa-users"></i> {{ 
slotProps.suggestion.name }}
+                        </span>
+                    </template>
+                </autocomplete-text-input>
+            </b-form-group>
             <h5>Currently Shared With</h5>
             <b-table id="modal-group-table" hover 
:items="sharedEntity.groupPermissions" :fields="groupFields">
                 <template slot="name" slot-scope="data">
@@ -22,7 +33,8 @@
 </template>
 
 <script>
-import { models } from 'django-airavata-api';
+import { models, services } from 'django-airavata-api';
+import AutocompleteTextInput from './AutocompleteTextInput.vue';
 
 export default {
     name: "share-button",
@@ -30,6 +42,9 @@ export default {
         value: models.SharedEntity,
         // TODO: add gatewayGroups
     },
+    components: {
+        AutocompleteTextInput,
+    },
     data: function() {
         return {
             sharedEntity: this.value ? this.value.clone() : new 
models.SharedEntity(),
@@ -38,6 +53,7 @@ export default {
                 {key: 'permission', label: 'Permission Settings'},
                 {key: 'remove', label: 'Remove'},
             ],
+            groups: [],
         }
     },
     computed: {
@@ -74,6 +90,19 @@ export default {
                     text: perm.name,
                 }
             })
+        },
+        groupSuggestions: function() {
+            // filter out already selected groups
+            const currentGroupIds = 
this.sharedEntity.groupPermissions.map(groupPerm => groupPerm.group.id);
+            return this.groups
+                .filter(group => currentGroupIds.indexOf(group.id) < 0)
+                .map(group => {
+                    return {
+                        id: group.id,
+                        name: group.name,
+                        type: 'group',
+                    }
+                });
         }
     },
     methods: {
@@ -87,7 +116,20 @@ export default {
         removeGroup: function(group) {
             this.sharedEntity.groupPermissions = 
this.sharedEntity.groupPermissions.filter(
                 groupPermission => groupPermission.group.id !== group.id);
+        },
+        suggestionSelected: function(suggestion) {
+            if (suggestion.type === 'group') {
+                const group = this.groups.find(group => group.id === 
suggestion.id);
+                this.sharedEntity.groupPermissions.push(new 
models.GroupPermission({
+                    'group': group,
+                    'permissionType': models.ResourcePermissionType.READ
+                }));
+            }
         }
+    },
+    mounted: function() {
+        // TODO: fetch all groups, not just the first page of them
+        services.GroupService.list().then(groups => this.groups = 
groups.results);
     }
 }
 </script>
diff --git a/django_airavata/static/common/js/index.js 
b/django_airavata/static/common/js/index.js
index b208677..cb87249 100644
--- a/django_airavata/static/common/js/index.js
+++ b/django_airavata/static/common/js/index.js
@@ -1,5 +1,6 @@
 import ApplicationCard from './components/ApplicationCard.vue'
 import Autocomplete from './components/Autocomplete.vue'
+import AutocompleteTextInput from './components/AutocompleteTextInput.vue'
 import Pager from './components/Pager.vue'
 import ShareButton from './components/ShareButton.vue'
 import * as utils from './utils'
@@ -8,6 +9,7 @@ exports.components = {
     Pager,
     ApplicationCard,
     Autocomplete,
+    AutocompleteTextInput,
     ShareButton,
 }
 

Reply via email to