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 2018/11/16 22:00:14 UTC

[airavata-django-portal] 02/06: AIRAVATA-2907 Add new storage preference UI

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 523600110cf81f7cf1033c0380e5886439de3dca
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Thu Nov 15 12:11:36 2018 -0500

    AIRAVATA-2907 Add new storage preference UI
---
 .../GatewayResourceProfileEditorContainer.vue      |  9 +++-
 .../gatewayprofile/StoragePreferenceList.vue       | 62 ++++++++++++++++++++--
 .../gatewayprofile/StoragePreferenceListItem.vue   | 10 ----
 django_airavata/apps/api/serializers.py            | 17 ++++++
 .../api/static/django_airavata_api/js/index.js     |  2 +
 .../js/models/StorageResourceDescription.js        | 17 ++++++
 .../django_airavata_api/js/service_config.js       | 21 ++++++++
 django_airavata/apps/api/urls.py                   |  5 ++
 django_airavata/apps/api/views.py                  | 52 ++++++++++++++++++
 .../static/common/js/layouts/ListLayout.vue        |  5 ++
 10 files changed, 184 insertions(+), 16 deletions(-)

diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/GatewayResourceProfileEditorContainer.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/GatewayResourceProfileEditorContainer.vue
index f6aee83..303ab56 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/GatewayResourceProfileEditorContainer.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/GatewayResourceProfileEditorContainer.vue
@@ -14,7 +14,7 @@
         <div class="card">
           <div class="card-body">
             <storage-preference-list v-if="gatewayResourceProfile" :storagePreferences="gatewayResourceProfile.storagePreferences"
-              @updated="updatedStoragePreference" />
+              @updated="updatedStoragePreference" @added="addedStoragePreference" />
           </div>
         </div>
       </div>
@@ -80,6 +80,13 @@ export default {
         1,
         updatedStoragePreference
       );
+    },
+    addedStoragePreference(newStoragePreference) {
+      services.StoragePreferenceService.create({
+        data: newStoragePreference
+      }).then(sp => {
+        this.gatewayResourceProfile.storagePreferences.push(sp);
+      });
     }
   }
 };
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceList.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceList.vue
index 5a8a4d5..fd66c04 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceList.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceList.vue
@@ -1,6 +1,24 @@
 <template>
-  <list-layout @add-new-item="newStoragePreference" :items="decoratedStoragePreferences" title="Storage Preferences"
+  <list-layout @add-new-item="addNewStoragePreference" :items="decoratedStoragePreferences" title="Storage Preferences"
     new-item-button-text="New Storage Preference">
+    <template slot="new-item-editor">
+      <b-card v-if="showNewItemEditor" title="New Storage Preference">
+        <b-form-group label="Storage Resource" label-for="storage-resource">
+          <b-form-select id="storage-resource" v-model="newStoragePreference.storageResourceId" :options="storageResourceOptions" />
+        </b-form-group>
+        <storage-preference-editor v-model="newStoragePreference" />
+        <div class="row">
+          <div class="col">
+            <b-button variant="primary" @click="saveNewStoragePreference">
+              Save
+            </b-button>
+            <b-button variant="secondary" @click="cancelNewStoragePreference">
+              Cancel
+            </b-button>
+          </div>
+        </div>
+      </b-card>
+    </template>
     <template slot="item-list" slot-scope="slotProps">
 
       <b-table striped hover :fields="fields" :items="slotProps.items" sort-by="storageResourceId">
@@ -22,7 +40,7 @@
 </template>
 
 <script>
-import { models } from "django-airavata-api";
+import { models, services, utils } from "django-airavata-api";
 import { layouts } from "django-airavata-common-ui";
 import StoragePreferenceEditor from "./StoragePreferenceEditor.vue";
 
@@ -41,7 +59,10 @@ export default {
   data() {
     return {
       showingDetails: {},
-    }
+      showNewItemEditor: false,
+      newStoragePreference: null,
+      storageResourceNames: null
+    };
   },
   computed: {
     fields() {
@@ -78,8 +99,26 @@ export default {
         spClone._showDetails = this.showingDetails[spClone.storageResourceId];
         return spClone;
       });
+    },
+    storageResourceOptions() {
+      const options = [];
+      for (const key in this.storageResourceNames) {
+        if (this.storageResourceNames.hasOwnProperty(key)) {
+          const name = this.storageResourceNames[key];
+          options.push({
+            value: key,
+            text: name
+          });
+        }
+      }
+      return utils.StringUtils.sortIgnoreCase(options, a => a.text);
     }
   },
+  created() {
+    services.StorageResourceService.names().then(names => {
+      this.storageResourceNames = names;
+    });
+  },
   methods: {
     getStorageResourceName(storageResourceId) {
       // TODO: fetch storage resources
@@ -94,11 +133,24 @@ export default {
       return fileSystemRootLocation;
     },
     updatedStoragePreference(newValue) {
-      this.$emit('updated', newValue);
+      this.$emit("updated", newValue);
     },
     toggleDetails(row) {
       row.toggleDetails();
-      this.showingDetails[row.item.storageResourceId] = !this.showingDetails[row.item.storageResourceId];
+      this.showingDetails[row.item.storageResourceId] = !this.showingDetails[
+        row.item.storageResourceId
+      ];
+    },
+    addNewStoragePreference() {
+      this.newStoragePreference = new models.StoragePreference();
+      this.showNewItemEditor = true;
+    },
+    saveNewStoragePreference() {
+      this.$emit("added", this.newStoragePreference);
+      this.showNewItemEditor = false;
+    },
+    cancelNewStoragePreference() {
+      this.showNewItemEditor = false;
     }
   }
 };
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceListItem.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceListItem.vue
deleted file mode 100644
index 13818a9..0000000
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/gatewayprofile/StoragePreferenceListItem.vue
+++ /dev/null
@@ -1,10 +0,0 @@
-<template>
-
-</template>
-
-<script>
-export default {
-  name: "storage-preference-list-item"
-};
-</script>
-
diff --git a/django_airavata/apps/api/serializers.py b/django_airavata/apps/api/serializers.py
index e9bb617..d1bf697 100644
--- a/django_airavata/apps/api/serializers.py
+++ b/django_airavata/apps/api/serializers.py
@@ -29,6 +29,9 @@ from airavata.model.appcatalog.gatewayprofile.ttypes import (
 from airavata.model.appcatalog.groupresourceprofile.ttypes import (
     GroupResourceProfile
 )
+from airavata.model.appcatalog.storageresource.ttypes import (
+    StorageResourceDescription
+)
 from airavata.model.application.io.ttypes import InputDataObjectType
 from airavata.model.credential.store.ttypes import (
     CredentialSummary,
@@ -688,6 +691,10 @@ class CredentialSummarySerializer(
 
 class StoragePreferenceSerializer(
         thrift_utils.create_serializer_class(StoragePreference)):
+    url = FullyEncodedHyperlinkedIdentityField(
+        view_name='django_airavata_api:storage-preference-detail',
+        lookup_field='storageResourceId',
+        lookup_url_kwarg='storage_resource_id')
 
     def to_representation(self, instance):
         ret = super().to_representation(instance)
@@ -704,3 +711,13 @@ class GatewayResourceProfileSerializer(
         lookup_field='gatewayID',
         lookup_url_kwarg='gateway_id')
     storagePreferences = StoragePreferenceSerializer(many=True)
+
+
+class StorageResourceSerializer(
+        thrift_utils.create_serializer_class(StorageResourceDescription)):
+    url = FullyEncodedHyperlinkedIdentityField(
+        view_name='django_airavata_api:storage-resource-detail',
+        lookup_field='storageResourceId',
+        lookup_url_kwarg='storage_resource_id')
+    creationTime = UTCPosixTimestampDateTimeField()
+    updateTime = UTCPosixTimestampDateTimeField()
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 1ec0d71..9184f0e 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
@@ -108,6 +108,8 @@ exports.services = {
   ServiceFactory,
   SharedEntityService: ServiceFactory.service("SharedEntities"),
   SshJobSubmissionService,
+  StoragePreferenceService: ServiceFactory.service("StoragePreferences"),
+  StorageResourceService: ServiceFactory.service("StorageResources"),
   UnicoreDataMovementService,
   UnicoreJobSubmissionService,
   UserProfileService
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/StorageResourceDescription.js b/django_airavata/apps/api/static/django_airavata_api/js/models/StorageResourceDescription.js
new file mode 100644
index 0000000..554c543
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/StorageResourceDescription.js
@@ -0,0 +1,17 @@
+import BaseModel from "./BaseModel";
+
+const FIELDS = [
+  "storageResourceId",
+  "hostName",
+  "storageResourceDescription",
+  "enabled",
+  "dataMovementInterfaces",
+  "creationTime",
+  "updateTime"
+];
+
+export default class StorageResourceDescription extends BaseModel {
+  constructor(data = {}) {
+    super(FIELDS, data);
+  }
+}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/service_config.js b/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
index 7f22e29..138c870 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
@@ -6,6 +6,8 @@ import GatewayResourceProfile from "./models/GatewayResourceProfile";
 import Group from "./models/Group";
 import GroupResourceProfile from "./models/GroupResourceProfile";
 import SharedEntity from "./models/SharedEntity";
+import StoragePreference from "./models/StoragePreference";
+import StorageResourceDescription from "./models/StorageResourceDescription";
 import UserProfile from "./models/UserProfile";
 import ApplicationInterfaceDefinition from "./models/ApplicationInterfaceDefinition";
 import BatchQueue from "./models/BatchQueue";
@@ -239,6 +241,25 @@ export default {
     ],
     modelClass: SharedEntity
   },
+  StoragePreferences: {
+    url: "/api/storage-preferences/",
+    viewSet: true,
+    modelClass: StoragePreference
+  },
+  StorageResources: {
+    url: "/api/storage-resources",
+    viewSet: [
+      {
+        name: "retrieve"
+      },
+      {
+        name: "names",
+        url: "/api/storage-resources/all_names/",
+        requestType: "get"
+      }
+    ],
+    modelClass: StorageResourceDescription
+  },
   UserProfiles: {
     url: "/api/user-profiles",
     viewSet: [
diff --git a/django_airavata/apps/api/urls.py b/django_airavata/apps/api/urls.py
index b610aba..a8d6a8b 100644
--- a/django_airavata/apps/api/urls.py
+++ b/django_airavata/apps/api/urls.py
@@ -30,11 +30,16 @@ router.register(r'shared-entities', views.SharedEntityViewSet,
                 base_name='shared-entity')
 router.register(r'compute-resources', views.ComputeResourceViewSet,
                 base_name='compute-resource')
+router.register(r'storage-resources', views.StorageResourceViewSet,
+                base_name='storage-resource')
 router.register(r'credential-summaries', views.CredentialSummaryViewSet,
                 base_name='credential-summary')
 router.register(r'gateway-resource-profiles',
                 views.GatewayResourceProfileViewSet,
                 base_name='gateway-resource-profile')
+router.register(r'storage-preferences',
+                views.StoragePreferenceViewSet,
+                base_name='storage-preference')
 
 app_name = 'django_airavata_api'
 urlpatterns = [
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index 625667f..16c2ed0 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -955,3 +955,55 @@ class GetCurrentGatewayResourceProfile(APIView):
         serializer = serializers.GatewayResourceProfileSerializer(
             gateway_resource_profile, context={'request': request})
         return Response(serializer.data)
+
+
+class StorageResourceViewSet(mixins.RetrieveModelMixin,
+                             GenericAPIBackedViewSet):
+    serializer_class = serializers.StorageResourceSerializer
+    lookup_field = 'storage_resource_id'
+    lookup_value_regex = '[^/]+'
+
+    def get_instance(self, lookup_value, format=None):
+        return self.request.airavata_client.getStorageResource(
+            self.authz_token, lookup_value)
+
+    @list_route()
+    def all_names(self, request, format=None):
+        """Return a map of compute resource names keyed by resource id."""
+        return Response(
+            request.airavata_client.getAllStorageResourceNames(
+                request.authz_token))
+
+
+class StoragePreferenceViewSet(APIBackedViewSet):
+    serializer_class = serializers.StoragePreferenceSerializer
+    lookup_field = 'storage_resource_id'
+    lookup_value_regex = '[^/]+'
+
+    def get_list(self):
+        return self.request.airavata_client.getAllGatewayStoragePreferences(
+            self.authz_token, settings.GATEWAY_ID)
+
+    def get_instance(self, lookup_value):
+        return self.request.airavata_client.getGatewayStoragePreference(
+            self.authz_token, settings.GATEWAY_ID, lookup_value)
+
+    def perform_create(self, serializer):
+        storage_preference = serializer.save()
+        self.request.airavata_client.addGatewayStoragePreference(
+            self.authz_token,
+            settings.GATEWAY_ID,
+            storage_preference.storageResourceId,
+            storage_preference)
+
+    def perform_update(self, serializer):
+        storage_preference = serializer.save()
+        self.request.airavata_client.updateGatewayStoragePreference(
+            self.authz_token,
+            settings.GATEWAY_ID,
+            storage_preference.storageResourceId,
+            storage_preference)
+
+    def perform_destroy(self, instance):
+        self.request.airavata_client.deleteGatewayStoragePreference(
+            self.authz_token, settings.GATEWAY_ID, instance.storageResourceId)
diff --git a/django_airavata/static/common/js/layouts/ListLayout.vue b/django_airavata/static/common/js/layouts/ListLayout.vue
index 3a28b7d..ec27700 100644
--- a/django_airavata/static/common/js/layouts/ListLayout.vue
+++ b/django_airavata/static/common/js/layouts/ListLayout.vue
@@ -22,6 +22,11 @@
     </div>
     <div class="row">
       <div class="col">
+        <slot name="new-item-editor"></slot>
+      </div>
+    </div>
+    <div class="row">
+      <div class="col">
         <slot name="item-list" :items="itemsList">Item List goes here</slot>
         <pager v-if="itemsPaginator" :paginator="itemsPaginator" next="nextItems" v-on:previous="previousItems"></pager>
       </div>