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 2019/06/10 15:32:23 UTC

[airavata-django-portal] 01/08: AIRAVATA-3057 Initial file selector in FileInputEditor

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 f11790facea481be8b86a4e3eef22206a79327bf
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Sun Jun 9 17:43:59 2019 -0400

    AIRAVATA-3057 Initial file selector in FileInputEditor
---
 .../components/users/UserGroupMembershipEditor.vue |  4 +-
 .../experiment/input-editors/FileInputEditor.vue   | 37 ++++++++++++-----
 .../input-editors/InputEditorContainer.vue         |  2 +-
 .../input-editors/InputEditorFormGroup.vue         |  5 ++-
 .../experiment/input-editors/StringInputEditor.vue |  1 -
 .../input-editors/TextareaInputEditor.vue          |  1 -
 .../storage/UserStorageFileSelectionContainer.vue  | 48 ++++++++++++++++++++++
 .../storage/UserStoragePathBreadcrumb.vue          | 46 ++++++++++++---------
 .../components/storage/UserStoragePathViewer.vue   | 40 +++++++++++++++---
 .../js/containers/UserStorageContainer.vue         |  4 ++
 10 files changed, 146 insertions(+), 42 deletions(-)

diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserGroupMembershipEditor.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserGroupMembershipEditor.vue
index 37bee7c..a8572cf 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserGroupMembershipEditor.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/UserGroupMembershipEditor.vue
@@ -116,9 +116,7 @@ export default {
       return {
         text: group.name,
         value: group.id,
-        disabled:
-          !group.userHasWriteAccess ||
-          group.ownerId === this.airavataInternalUserId
+        disabled: !group.userHasWriteAccess || group.ownerId === this.airavataInternalUserId
       };
     }
   }
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue
index 4c1eb24..01b1d7e 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/FileInputEditor.vue
@@ -28,14 +28,22 @@
         ></i>
       </b-link>
     </div>
-    <b-form-file
-      :id="id"
-      v-model="file"
-      v-if="!isDataProductURI"
-      :placeholder="experimentInput.userFriendlyDescription"
-      :state="componentValidState"
-      @input="fileChanged"
-    />
+    <div v-if="isSelectingFile">
+      <!-- TODO: handle @cancel -->
+      <user-storage-file-selection-container @file-selected="fileSelected"/>
+    </div>
+    <div class="d-flex" v-if="!isSelectingFile && !isDataProductURI">
+      <!-- TODO: fix layout -->
+      <b-button @click="isSelectingFile=true">Select user file</b-button>
+      <span class="text-muted">OR</span>
+      <b-form-file
+        :id="id"
+        v-model="file"
+        v-if="!isDataProductURI"
+        :state="componentValidState"
+        @input="fileChanged"
+      />
+    </div>
   </div>
 </template>
 
@@ -44,13 +52,15 @@ import { models, services, utils } from "django-airavata-api";
 import { InputEditorMixin } from "django-airavata-workspace-plugin-api";
 import DataProductViewer from "../DataProductViewer.vue";
 import { components } from "django-airavata-common-ui";
+import UserStorageFileSelectionContainer from "../../storage/UserStorageFileSelectionContainer";
 
 export default {
   name: "file-input-editor",
   mixins: [InputEditorMixin],
   components: {
     DataProductViewer,
-    "delete-link": components.DeleteLink
+    "delete-link": components.DeleteLink,
+    UserStorageFileSelectionContainer
   },
   computed: {
     isDataProductURI() {
@@ -61,7 +71,8 @@ export default {
   data() {
     return {
       dataProduct: null,
-      file: null
+      file: null,
+      isSelectingFile: false
     };
   },
   created() {
@@ -114,6 +125,12 @@ export default {
       this.file = null;
       this.data = null;
       this.valueChanged();
+    },
+    fileSelected(dataProductURI) {
+      this.data = dataProductURI;
+      this.isSelectingFile = false;
+      this.loadDataProduct(dataProductURI);
+      this.valueChanged();
     }
   }
 };
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 2de4ccb..44b4489 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
@@ -1,6 +1,6 @@
 <template>
     <input-editor-form-group :label="experimentInput.name" :label-for="inputEditorComponentId"
-        :state="validationState" :feedback-messages="validationFeedback">
+        :state="validationState" :feedback-messages="validationFeedback" :description="experimentInput.userFriendlyDescription">
         <component :is="inputEditorComponentName"
             :id="inputEditorComponentId"
             :experiment-input="experimentInput"
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/InputEditorFormGroup.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/InputEditorFormGroup.vue
index 592214e..e1d40fc 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/InputEditorFormGroup.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/InputEditorFormGroup.vue
@@ -1,5 +1,5 @@
 <template>
-    <b-form-group :label="label" :label-for="labelFor" :state="state">
+    <b-form-group :label="label" :label-for="labelFor" :state="state" :description="description">
         <slot></slot>
         <template slot="invalid-feedback">
             <ul v-if="feedbackMessages && feedbackMessages.length > 1">
@@ -31,6 +31,9 @@ export default {
         feedbackMessages: {
             type: Array,
         },
+        description: {
+          type: String,
+        }
     },
 }
 </script>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue
index 04ab99d..538f070 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/StringInputEditor.vue
@@ -1,6 +1,5 @@
 <template>
     <b-form-input :id="id" type="text" v-model="data"
-        :placeholder="experimentInput.userFriendlyDescription"
         :state="componentValidState"
         @input="valueChanged"/>
 </template>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/TextareaInputEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/TextareaInputEditor.vue
index 2361fbc..35fd33e 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/TextareaInputEditor.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/input-editors/TextareaInputEditor.vue
@@ -1,7 +1,6 @@
 <template>
     <b-form-textarea :id="id" v-model="data"
         :rows="rows"
-        :placeholder="experimentInput.userFriendlyDescription"
         :state="componentValidState"
         @input="valueChanged"/>
 </template>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStorageFileSelectionContainer.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStorageFileSelectionContainer.vue
new file mode 100644
index 0000000..51588aa
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStorageFileSelectionContainer.vue
@@ -0,0 +1,48 @@
+<template>
+  <b-card header="Select a file">
+    <user-storage-path-viewer
+      :user-storage-path="userStoragePath"
+      @directory-selected="directorySelected"
+      @file-selected="fileSelected"
+      :include-delete-action="false"
+      :include-select-file-action="true"
+      :download-in-new-window="true"
+    />
+    <!-- TODO: push this right? -->
+    <b-link class="card-link">Cancel</b-link>
+  </b-card>
+</template>
+
+<script>
+import { services } from "django-airavata-api";
+import UserStoragePathViewer from "./UserStoragePathViewer";
+
+export default {
+  name: "user-storage-file-selection-container",
+  data() {
+    return {
+      userStoragePath: null
+    };
+  },
+  components: {
+    UserStoragePathViewer
+  },
+  created() {
+    return this.loadUserStoragePath("~");
+  },
+  methods: {
+    loadUserStoragePath(path) {
+      return services.UserStoragePathService.get({
+        path
+      }).then(result => (this.userStoragePath = result));
+    },
+    directorySelected(path) {
+      return this.loadUserStoragePath("~/" + path);
+    },
+    fileSelected(file) {
+      this.$emit('file-selected', file.dataProductURI);
+    }
+  }
+};
+</script>
+
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStoragePathBreadcrumb.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStoragePathBreadcrumb.vue
index 0860a83..27d4ba3 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStoragePathBreadcrumb.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStoragePathBreadcrumb.vue
@@ -1,5 +1,13 @@
 <template>
-  <b-breadcrumb :items="items"></b-breadcrumb>
+  <b-breadcrumb>
+    <b-breadcrumb-item
+      v-for="item in items"
+      :key="item.path"
+      :text="item.text"
+      :active="item.active"
+      @click="directorySelected(item.path)"
+    />
+  </b-breadcrumb>
 </template>
 
 <script>
@@ -13,25 +21,23 @@ export default {
   },
   computed: {
     items() {
-      const homeItem = [
-        {
-          text: "Home",
-          to: { path: "/~/" }
-        }
-      ];
-      if (this.parts) {
-        const subparts = [];
-        const partsItems = this.parts.map(part => {
-          subparts.push(part);
-          return {
-            text: part,
-            to: { path: "/~/" + subparts.join("/") + "/" }
-          };
-        });
-        return homeItem.concat(partsItems);
-      } else {
-        return homeItem;
-      }
+      const subparts = [];
+      const partsItems = this.parts.map((part, index) => {
+        subparts.push(part);
+        return {
+          text: part,
+          path: subparts.join("/"),
+          active: index === this.parts.length - 1
+        };
+      });
+      return [
+        { text: "Home", path: "", active: this.parts.length === 0 }
+      ].concat(partsItems);
+    }
+  },
+  methods: {
+    directorySelected(path) {
+      this.$emit("directory-selected", path);
     }
   }
 };
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStoragePathViewer.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStoragePathViewer.vue
index 2e9a418..61cd61b 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStoragePathViewer.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStoragePathViewer.vue
@@ -3,6 +3,7 @@
     <user-storage-path-breadcrumb
       v-if="userStoragePath"
       :parts="userStoragePath.parts"
+      @directory-selected="$emit('directory-selected', $event)"
     />
     <b-table
       :fields="fields"
@@ -13,26 +14,37 @@
         slot="name"
         slot-scope="data"
       >
-        <router-link
+        <b-link
           v-if="data.item.type === 'dir'"
-          :to="'/~/' + data.item.path"
-        > <i class="fa fa-folder-open"></i> {{ data.item.name }}</router-link>
+          @click="directorySelected(data.item)"
+        > <i class="fa fa-folder-open"></i> {{ data.item.name }}</b-link>
         <b-link
           v-else
           :href="data.item.downloadURL"
+          :target="downloadTarget"
         > <i class="fa fa-download"></i> {{ data.item.name }}</b-link>
       </template>
       <template
         slot="createdTimestamp"
         slot-scope="data"
       >
-        <human-date :date="data.item.createdTime"/>
+        <human-date :date="data.item.createdTime" />
       </template>
       <template
         slot="actions"
         slot-scope="data"
       >
-        <delete-button @delete="deleteItem(data.item)">
+        <b-button
+          v-if="includeSelectFileAction && data.item.type === 'file'"
+          @click="$emit('file-selected', data.item)"
+          variant="primary"
+        >
+          Select
+        </b-button>
+        <delete-button
+          v-if="includeDeleteAction"
+          @delete="deleteItem(data.item)"
+        >
           Are you sure you want to delete {{ data.item.name }}?
         </delete-button>
       </template>
@@ -48,6 +60,18 @@ export default {
   props: {
     userStoragePath: {
       required: true
+    },
+    includeDeleteAction: {
+      type: Boolean,
+      default: true
+    },
+    includeSelectFileAction: {
+      type: Boolean,
+      default: false
+    },
+    downloadInNewWindow: {
+      type: Boolean,
+      default: false
     }
   },
   components: {
@@ -109,6 +133,9 @@ export default {
       } else {
         return [];
       }
+    },
+    downloadTarget() {
+      return this.downloadInNewWindow ? '_blank' : '_self';
     }
   },
   methods: {
@@ -129,6 +156,9 @@ export default {
       } else if (item.type === "file") {
         this.$emit("delete-file", item.dataProductURI);
       }
+    },
+    directorySelected(item) {
+      this.$emit("directory-selected", item.path);
     }
   }
 };
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/UserStorageContainer.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/UserStorageContainer.vue
index 03e5f03..7e39fd2 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/UserStorageContainer.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/UserStorageContainer.vue
@@ -42,6 +42,7 @@
           <router-view
             :user-storage-path="userStoragePath"
             @delete-dir="deleteDir"
+            @directory-selected="directorySelected"
             @delete-file="deleteFile"
           ></router-view>
         </b-card>
@@ -144,6 +145,9 @@ export default {
       ).then(() => {
         this.loadUserStoragePath(this.storagePath);
       });
+    },
+    directorySelected(path) {
+      this.$router.push("/~/" + path);
     }
   },
   created() {