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 2021/04/09 19:54:49 UTC

[airavata-django-portal] branch develop updated (4e39edd -> b81a41e)

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

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


    from 4e39edd  Merge branch 'common-ui-components-lib' into develop
     new 20a0f90  AIRAVATA-3362 Display exp data dir in experiment summary page
     new b81a41e  AIRAVATA-3362 Cleaning up unused code

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../statistics/ExperimentDetailsView.vue           |  19 ----
 django_airavata/apps/api/serializers.py            |  60 +++++-----
 .../api/static/django_airavata_api/js/index.js     |   1 +
 .../django_airavata_api/js/models/Experiment.js    |   1 -
 .../js/models/ExperimentStoragePath.js             |   4 +
 .../django_airavata_api/js/service_config.js       |  12 ++
 django_airavata/apps/api/urls.py                   |   4 +
 django_airavata/apps/api/views.py                  |  36 ++++++
 .../js/components/experiment/ExperimentSummary.vue |  28 ++---
 .../output-displays/DefaultOutputDisplay.vue       |  10 +-
 .../storage/ExperimentStoragePathViewer.vue        | 125 +++++++++++++++++++++
 .../storage/ExperimentStorageViewContainer.vue     |  48 ++++++++
 ...athBreadcrumb.vue => StoragePathBreadcrumb.vue} |   8 +-
 .../components/storage/UserStorageCreateView.vue   |  84 --------------
 .../storage/UserStorageFileSelectionContainer.vue  |   7 +-
 .../components/storage/UserStoragePathViewer.vue   |  36 +++---
 .../django_airavata_workspace/js/utils/urls.js     |   6 -
 17 files changed, 292 insertions(+), 197 deletions(-)
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStoragePath.js
 create mode 100644 django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/ExperimentStoragePathViewer.vue
 create mode 100644 django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/ExperimentStorageViewContainer.vue
 rename django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/{UserStoragePathBreadcrumb.vue => StoragePathBreadcrumb.vue} (81%)
 delete mode 100644 django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStorageCreateView.vue

[airavata-django-portal] 02/02: AIRAVATA-3362 Cleaning up unused code

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit b81a41ef13ef8840b6cbcf1987f57e11db1d80a8
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Fri Apr 9 15:54:19 2021 -0400

    AIRAVATA-3362 Cleaning up unused code
---
 .../statistics/ExperimentDetailsView.vue           | 21 --------------
 django_airavata/apps/api/serializers.py            | 32 ----------------------
 .../django_airavata_api/js/models/Experiment.js    |  1 -
 .../js/components/experiment/ExperimentSummary.vue |  7 -----
 .../django_airavata_workspace/js/utils/urls.js     |  6 ----
 5 files changed, 67 deletions(-)

diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentDetailsView.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentDetailsView.vue
index 319464d..acd8a19 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentDetailsView.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentDetailsView.vue
@@ -253,14 +253,6 @@
             </ul>
           </td>
         </tr>
-        <tr v-if="storageDirLink">
-          <th scope="row">Storage Directory</th>
-          <td>
-            <experiment-storage-view-container
-              :experimentId="experiment.experimentId"
-            />
-          </td>
-        </tr>
         <tr>
           <th scope="row">Errors</th>
           <td>
@@ -433,13 +425,6 @@ export default {
         moment(jobDetail.creationTime).fromNow()
       );
     },
-    storageDirLink() {
-      if (this.experiment.relativeExperimentDataDir) {
-        return this.storageDirectory(this.experiment.relativeExperimentDataDir);
-      } else {
-        return null;
-      }
-    },
     failedJobs() {
       if (this.fullExperiment && this.fullExperiment.jobDetails) {
         return this.fullExperiment.jobDetails.filter(
@@ -479,12 +464,6 @@ export default {
         ? dataProducts.filter((dp) => (dp ? true : false))
         : [];
     },
-    storageDirectory(relativePath) {
-      if (relativePath.startsWith("/")) {
-        relativePath = relativePath.substring(1);
-      }
-      return "/workspace/storage/~/" + relativePath;
-    },
   },
 };
 </script>
diff --git a/django_airavata/apps/api/serializers.py b/django_airavata/apps/api/serializers.py
index 9f370ee..04d81f6 100644
--- a/django_airavata/apps/api/serializers.py
+++ b/django_airavata/apps/api/serializers.py
@@ -442,7 +442,6 @@ class ExperimentSerializer(
     creationTime = UTCPosixTimestampDateTimeField(allow_null=True)
     experimentStatus = ExperimentStatusSerializer(many=True, allow_null=True)
     userHasWriteAccess = serializers.SerializerMethodField()
-    relativeExperimentDataDir = serializers.SerializerMethodField()
 
     def get_userHasWriteAccess(self, experiment):
         request = self.context['request']
@@ -450,37 +449,6 @@ class ExperimentSerializer(
             request.authz_token, experiment.experimentId,
             ResourcePermissionType.WRITE)
 
-    def get_relativeExperimentDataDir(self, experiment):
-        request = self.context['request']
-        if hasattr(user_storage, "get_rel_experiment_dir"):
-            return user_storage.get_rel_experiment_dir(request, experiment.experimentId)
-
-        # TODO: remove this older implementation
-        if (experiment.userConfigurationData and
-                experiment.userConfigurationData.experimentDataDir):
-            request = self.context['request']
-            data_dir = experiment.userConfigurationData.experimentDataDir
-            if getattr(
-                settings,
-                'GATEWAY_DATA_STORE_REMOTE_API',
-                    None) is not None:
-                # Load the relativeExperimentDataDir from the remote Django
-                # portal instance
-                headers = {
-                    'Authorization': f'Bearer {request.authz_token.accessToken}'}
-                r = requests.get(
-                    f'{settings.GATEWAY_DATA_STORE_REMOTE_API}/experiments/{quote(experiment.experimentId)}/',
-                    headers=headers,
-                )
-                r.raise_for_status()
-                return r.json()['relativeExperimentDataDir']
-            elif user_storage.dir_exists(request, data_dir):
-                return user_storage.get_rel_path(request, data_dir)
-            else:
-                return None
-        else:
-            return None
-
 
 class DataReplicaLocationSerializer(
         thrift_utils.create_serializer_class(DataReplicaLocationModel)):
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/Experiment.js b/django_airavata/apps/api/static/django_airavata_api/js/models/Experiment.js
index 9d2b12f..4e79c16 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/Experiment.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/Experiment.js
@@ -71,7 +71,6 @@ const FIELDS = [
     type: "boolean",
     default: true,
   },
-  "relativeExperimentDataDir",
 ];
 
 export default class Experiment extends BaseModel {
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue
index a5a6399..469441c 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue
@@ -383,13 +383,6 @@ export default {
     isCancelable() {
       return this.localFullExperiment.experiment.isCancelable;
     },
-    storageDirLink() {
-      if (this.experiment.relativeExperimentDataDir) {
-        return urls.storageDirectory(this.experiment.relativeExperimentDataDir);
-      } else {
-        return null;
-      }
-    },
   },
   methods: {
     loadExperiment: function () {
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/utils/urls.js b/django_airavata/apps/workspace/static/django_airavata_workspace/js/utils/urls.js
index e42cacf..9f8cbd2 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/utils/urls.js
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/utils/urls.js
@@ -47,10 +47,4 @@ export default {
   navigateToProjectsList() {
     window.location.assign(this.projectsList());
   },
-  storageDirectory(relativePath) {
-    if (relativePath.startsWith("/")) {
-      relativePath = relativePath.substring(1);
-    }
-    return "/workspace/storage/~/" + relativePath;
-  },
 };

[airavata-django-portal] 01/02: AIRAVATA-3362 Display exp data dir in experiment summary page

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 20a0f90ea3ff083f8097d4a5abb855d266758ee0
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Fri Apr 9 15:46:38 2021 -0400

    AIRAVATA-3362 Display exp data dir in experiment summary page
---
 .../statistics/ExperimentDetailsView.vue           |   4 +-
 django_airavata/apps/api/serializers.py            |  28 +++++
 .../api/static/django_airavata_api/js/index.js     |   1 +
 .../js/models/ExperimentStoragePath.js             |   4 +
 .../django_airavata_api/js/service_config.js       |  12 ++
 django_airavata/apps/api/urls.py                   |   4 +
 django_airavata/apps/api/views.py                  |  36 ++++++
 .../js/components/experiment/ExperimentSummary.vue |  21 ++--
 .../output-displays/DefaultOutputDisplay.vue       |  10 +-
 .../storage/ExperimentStoragePathViewer.vue        | 125 +++++++++++++++++++++
 .../storage/ExperimentStorageViewContainer.vue     |  48 ++++++++
 ...athBreadcrumb.vue => StoragePathBreadcrumb.vue} |   8 +-
 .../components/storage/UserStorageCreateView.vue   |  84 --------------
 .../storage/UserStorageFileSelectionContainer.vue  |   7 +-
 .../components/storage/UserStoragePathViewer.vue   |  36 +++---
 15 files changed, 295 insertions(+), 133 deletions(-)

diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentDetailsView.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentDetailsView.vue
index f786544..319464d 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentDetailsView.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/statistics/ExperimentDetailsView.vue
@@ -256,7 +256,9 @@
         <tr v-if="storageDirLink">
           <th scope="row">Storage Directory</th>
           <td>
-            <b-link :href="storageDirLink">Open</b-link>
+            <experiment-storage-view-container
+              :experimentId="experiment.experimentId"
+            />
           </td>
         </tr>
         <tr>
diff --git a/django_airavata/apps/api/serializers.py b/django_airavata/apps/api/serializers.py
index 02731a6..9f370ee 100644
--- a/django_airavata/apps/api/serializers.py
+++ b/django_airavata/apps/api/serializers.py
@@ -910,6 +910,34 @@ class UserStoragePathSerializer(serializers.Serializer):
     uploaded = DataProductSerializer(read_only=True)
 
 
+# Fields for ExperimentStorageFileSerializer are the same as UserStorageFileSerializer
+ExperimentStorageFileSerializer = UserStorageFileSerializer
+
+
+class ExperimentStorageDirectorySerializer(serializers.Serializer):
+    name = serializers.CharField()
+    path = serializers.CharField()
+    createdTime = serializers.DateTimeField(source='created_time')
+    size = serializers.IntegerField()
+    url = serializers.SerializerMethodField()
+
+    def get_url(self, dir):
+
+        request = self.context['request']
+        return request.build_absolute_uri(
+            reverse("django_airavata_api:experiment-storage-items", kwargs={
+                "experiment_id": dir['experiment_id'],
+                "path": dir['path']
+            }))
+
+
+class ExperimentStoragePathSerializer(serializers.Serializer):
+    isDir = serializers.BooleanField()
+    directories = ExperimentStorageDirectorySerializer(many=True)
+    files = ExperimentStorageFileSerializer(many=True)
+    parts = serializers.ListField(child=serializers.CharField())
+
+
 # ModelSerializers
 class ApplicationPreferencesSerializer(serializers.ModelSerializer):
     class Meta:
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 4e9e568..13d130f 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
@@ -110,6 +110,7 @@ const services = {
   ExperimentSearchService: ServiceFactory.service("ExperimentSearch"),
   ExperimentService: ServiceFactory.service("Experiments"),
   ExperimentStatisticsService: ServiceFactory.service("ExperimentStatistics"),
+  ExperimentStoragePathService: ServiceFactory.service("ExperimentStoragePaths"),
   FullExperimentService: ServiceFactory.service("FullExperiments"),
   GatewayResourceProfileService: ServiceFactory.service(
     "GatewayResourceProfile"
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStoragePath.js b/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStoragePath.js
new file mode 100644
index 0000000..965e702
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStoragePath.js
@@ -0,0 +1,4 @@
+import UserStoragePath from "./UserStoragePath";
+
+export default class ExperimentStoragePath extends UserStoragePath {
+}
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 6a4cca3..f607981 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
@@ -8,6 +8,7 @@ import DataProduct from "./models/DataProduct";
 import Experiment from "./models/Experiment";
 import ExperimentSearchFields from "./models/ExperimentSearchFields";
 import ExperimentStatistics from "./models/ExperimentStatistics";
+import ExperimentStoragePath from "./models/ExperimentStoragePath";
 import ExperimentSummary from "./models/ExperimentSummary";
 import FullExperiment from "./models/FullExperiment";
 import GatewayResourceProfile from "./models/GatewayResourceProfile";
@@ -221,6 +222,17 @@ export default {
       },
     },
   },
+  ExperimentStoragePaths: {
+    url: "/api/experiment-storage",
+    methods: {
+      get: {
+        url: "/api/experiment-storage/<experimentId>/<path>",
+        requestType: "get",
+        modelClass: ExperimentStoragePath,
+        encodePathParams: false,
+      },
+    },
+  },
   FullExperiments: {
     url: "/api/full-experiments",
     viewSet: [
diff --git a/django_airavata/apps/api/urls.py b/django_airavata/apps/api/urls.py
index 905c814..cc016f5 100644
--- a/django_airavata/apps/api/urls.py
+++ b/django_airavata/apps/api/urls.py
@@ -1,6 +1,7 @@
 import logging
 
 from django.conf.urls import url
+from django.urls import re_path
 from rest_framework import routers
 from rest_framework.urlpatterns import format_suffix_patterns
 
@@ -82,6 +83,9 @@ urlpatterns = [
     url(r'^user-storage/~/(?P<path>.*)$',
         views.UserStoragePathView.as_view(),
         name="user-storage-items"),
+    re_path(r'^experiment-storage/(?P<experiment_id>[^/]+)/(?P<path>.*)$',
+            views.ExperimentStoragePathView.as_view(),
+            name="experiment-storage-items"),
     url(r'^experiment-statistics',
         views.ExperimentStatisticsView.as_view(),
         name="experiment-statistics"),
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index 64aa780..dcfb209 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -1619,6 +1619,42 @@ class UserStoragePathView(APIView):
             return []
 
 
+class ExperimentStoragePathView(APIView):
+
+    serializer_class = serializers.ExperimentStoragePathSerializer
+
+    def get(self, request, experiment_id=None, path="", format=None):
+        return self._create_response(request, experiment_id, path)
+
+    def _create_response(self, request, experiment_id, path):
+        if user_storage.experiment_dir_exists(request, experiment_id, path):
+            directories, files = user_storage.list_experiment_dir(request, experiment_id, path)
+
+            def add_expid(d):
+                d['experiment_id'] = experiment_id
+                return d
+            data = {
+                'isDir': True,
+                'directories': map(add_expid, directories),
+                'files': map(add_expid, files)
+            }
+            data['parts'] = self._split_path(path)
+            serializer = self.serializer_class(
+                data, context={'request': request})
+            return Response(serializer.data)
+        else:
+            raise Http404(f"Path '{path}' does not exist for {experiment_id}")
+
+    def _split_path(self, path):
+        head, tail = os.path.split(path)
+        if head != "":
+            return self._split_path(head) + [tail]
+        elif tail != "":
+            return [tail]
+        else:
+            return []
+
+
 class WorkspacePreferencesView(APIView):
     serializer_class = serializers.WorkspacePreferencesSerializer
 
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue
index 84e9903..a5a6399 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue
@@ -44,11 +44,11 @@
         </div>
       </div>
     </template>
-    <div class="row" v-if="experiment.isFinished && storageDirLink">
+    <div class="row" v-if="experiment.isFinished">
       <div class="col">
-        <b-card header="Other Files">
-          <b-link :href="storageDirLink">Storage Directory</b-link>
-        </b-card>
+        <experiment-storage-view-container
+          :experimentId="experiment.experimentId"
+        />
       </div>
     </div>
     <div class="row">
@@ -247,12 +247,11 @@
                         <template v-if="input.type.isSimpleValueType">
                           <span class="text-break">{{ input.value }}</span>
                         </template>
-                        <user-storage-link
+                        <data-product-viewer
                           v-for="dp in inputDataProducts[input.name]"
                           v-else-if="input.type.isFileValueType"
-                          :data-product-uri="dp.productUri"
-                          :mime-type="dp.mimeType"
-                          :file-name="dp.productName"
+                          :data-product="dp"
+                          :input-file="true"
                           :key="dp.productUri"
                         />
                       </li>
@@ -287,7 +286,8 @@ import OutputDisplayContainer from "./output-displays/OutputDisplayContainer";
 import urls from "../../utils/urls";
 
 import moment from "moment";
-import UserStorageLink from "../storage/storage-edit/UserStorageLink";
+import ExperimentStorageViewContainer from "../storage/ExperimentStorageViewContainer.vue";
+import DataProductViewer from "django-airavata-common-ui/js/components/DataProductViewer.vue";
 
 export default {
   name: "experiment-summary",
@@ -307,10 +307,11 @@ export default {
     };
   },
   components: {
-    UserStorageLink,
     "clipboard-copy-link": components.ClipboardCopyLink,
     "share-button": components.ShareButton,
     OutputDisplayContainer,
+    ExperimentStorageViewContainer,
+    DataProductViewer,
   },
   computed: {
     inputDataProducts() {
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/DefaultOutputDisplay.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/DefaultOutputDisplay.vue
index dabea5d..383676c 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/DefaultOutputDisplay.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/DefaultOutputDisplay.vue
@@ -6,18 +6,14 @@
         class="image-preview rounded"
         :src="dp.downloadURL"
       />
-      <user-storage-link
-        :data-product-uri="dp.productUri"
-        :mime-type="fileMimeType"
-        :file-name="dp.filename"
-      />
+      <data-product-viewer :data-product="dp" :mime-type="fileMimeType" />
     </div>
   </div>
 </template>
 
 <script>
 import { models } from "django-airavata-api";
-import UserStorageLink from "../../storage/storage-edit/UserStorageLink";
+import DataProductViewer from "django-airavata-common-ui/js/components/DataProductViewer.vue";
 
 export default {
   name: "default-output-viewer",
@@ -32,7 +28,7 @@ export default {
     },
   },
   components: {
-    UserStorageLink
+    DataProductViewer,
   },
   computed: {
     fileMimeType() {
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/ExperimentStoragePathViewer.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/ExperimentStoragePathViewer.vue
new file mode 100644
index 0000000..31f5a44
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/ExperimentStoragePathViewer.vue
@@ -0,0 +1,125 @@
+<template>
+  <div>
+    <storage-path-breadcrumb
+      v-if="experimentStoragePath"
+      :parts="experimentStoragePath.parts"
+      rootName="Exp Data Dir"
+      @directory-selected="$emit('directory-selected', $event)"
+    />
+
+    <b-table
+      v-if="experimentStoragePath"
+      :fields="fields"
+      :items="items"
+      sort-by="name"
+    >
+      <template slot="name" slot-scope="data">
+        <b-link
+          v-if="data.item.type === 'dir'"
+          @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">
+          {{ data.item.name }}</b-link
+        >
+      </template>
+      <template slot="createdTimestamp" slot-scope="data">
+        <human-date :date="data.item.createdTime" />
+      </template>
+    </b-table>
+  </div>
+</template>
+<script>
+import StoragePathBreadcrumb from "./StoragePathBreadcrumb.vue";
+import { components } from "django-airavata-common-ui";
+
+export default {
+  name: "user-storage-path-viewer",
+  props: {
+    experimentStoragePath: {
+      required: true,
+    },
+    downloadInNewWindow: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  components: {
+    "human-date": components.HumanDate,
+    StoragePathBreadcrumb,
+  },
+  computed: {
+    fields() {
+      return [
+        {
+          label: "Name",
+          key: "name",
+          sortable: true,
+        },
+        {
+          label: "Size",
+          key: "size",
+          sortable: true,
+          formatter: (value) => this.getFormattedSize(value),
+        },
+        {
+          label: "Created Time",
+          key: "createdTimestamp",
+          sortable: true,
+        },
+      ];
+    },
+    items() {
+      if (this.experimentStoragePath) {
+        const dirs = this.experimentStoragePath.directories
+          .filter((d) => !d.hidden)
+          .map((d) => {
+            return {
+              name: d.name,
+              path: d.path,
+              type: "dir",
+              createdTime: d.createdTime,
+              createdTimestamp: d.createdTime.getTime(), // for sorting
+              size: d.size,
+            };
+          });
+        const files = this.experimentStoragePath.files.map((f) => {
+          return {
+            name: f.name,
+            mimeType: f.mimeType,
+            type: "file",
+            dataProductURI: f.dataProductURI,
+            downloadURL: f.downloadURL,
+            createdTime: f.createdTime,
+            createdTimestamp: f.createdTime.getTime(), // for sorting
+            size: f.size,
+          };
+        });
+        return dirs.concat(files);
+      } else {
+        return [];
+      }
+    },
+    downloadTarget() {
+      return this.downloadInNewWindow ? "_blank" : "_self";
+    },
+  },
+  methods: {
+    getFormattedSize(size) {
+      if (size > Math.pow(2, 30)) {
+        return Math.round(size / Math.pow(2, 30)) + " GB";
+      } else if (size > Math.pow(2, 20)) {
+        return Math.round(size / Math.pow(2, 20)) + " MB";
+      } else if (size > Math.pow(2, 10)) {
+        return Math.round(size / Math.pow(2, 10)) + " KB";
+      } else {
+        return size + " bytes";
+      }
+    },
+    directorySelected(item) {
+      this.$emit("directory-selected", item.path);
+    },
+  },
+};
+</script>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/ExperimentStorageViewContainer.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/ExperimentStorageViewContainer.vue
new file mode 100644
index 0000000..f940102
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/ExperimentStorageViewContainer.vue
@@ -0,0 +1,48 @@
+<template>
+  <b-card header="Experiment Data Directory">
+    <experiment-storage-path-viewer
+      v-if="experimentStoragePath"
+      :experiment-storage-path="experimentStoragePath"
+      @directory-selected="directorySelected"
+      :download-in-new-window="true"
+    ></experiment-storage-path-viewer>
+  </b-card>
+</template>
+
+<script>
+import { services } from "django-airavata-api";
+import ExperimentStoragePathViewer from "./ExperimentStoragePathViewer.vue";
+
+export default {
+  name: "experiment-storage-view-container",
+  computed: {},
+  props: {
+    experimentId: {
+      type: String,
+      required: true,
+    },
+  },
+  data() {
+    return {
+      experimentStoragePath: null,
+    };
+  },
+  components: {
+    ExperimentStoragePathViewer,
+  },
+  created() {
+    return this.loadExperimentStoragePath("");
+  },
+  methods: {
+    loadExperimentStoragePath(path) {
+      return services.ExperimentStoragePathService.get({
+        experimentId: this.experimentId,
+        path,
+      }).then((result) => (this.experimentStoragePath = result));
+    },
+    directorySelected(path) {
+      return this.loadExperimentStoragePath(path);
+    },
+  },
+};
+</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/StoragePathBreadcrumb.vue
similarity index 81%
rename from django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStoragePathBreadcrumb.vue
rename to django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/StoragePathBreadcrumb.vue
index 5c6e9bc..182ada7 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/StoragePathBreadcrumb.vue
@@ -12,12 +12,16 @@
 
 <script>
 export default {
-  name: "user-storage-path-breadcrumb",
+  name: "storage-path-breadcrumb",
   props: {
     parts: {
       type: Array,
       required: true,
     },
+    rootName: {
+      type: String,
+      default: "Home",
+    },
   },
   computed: {
     items() {
@@ -31,7 +35,7 @@ export default {
         };
       });
       return [
-        { text: "Home", path: "", active: this.parts.length === 0 },
+        { text: this.rootName, path: "", active: this.parts.length === 0 },
       ].concat(partsItems);
     },
   },
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStorageCreateView.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStorageCreateView.vue
deleted file mode 100644
index 6844f3e..0000000
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/storage/UserStorageCreateView.vue
+++ /dev/null
@@ -1,84 +0,0 @@
-<template>
-  <div>
-    <div class="row">
-      <div class="col">
-        <h1 class="h4">Storage</h1>
-        <p>
-          <small class="text-muted"
-            ><i class="fa fa-folder-open"></i> {{ username }}</small
-          >
-        </p>
-      </div>
-    </div>
-    <div class="row">
-      <div class="col">
-        <uppy
-          class="mb-1"
-          ref="file-upload"
-          :xhr-upload-endpoint="uploadEndpoint"
-          :tus-upload-finish-endpoint="uploadEndpoint"
-          @upload-success="uploadSuccess"
-          multiple
-        />
-      </div>
-      <div class="col">
-        <b-input-group>
-          <b-form-input
-            v-model="dirName"
-            placeholder="New directory name"
-            @keydown.native.enter="addDirectory"
-          ></b-form-input>
-          <b-input-group-append>
-            <b-button @click="addDirectory" :disabled="!this.dirName"
-              >Add directory
-            </b-button>
-          </b-input-group-append>
-        </b-input-group>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script>
-import { components } from "django-airavata-common-ui";
-import { session } from "django-airavata-api";
-
-export default {
-  name: "user-storage-create-view",
-  components: {
-    uppy: components.Uppy,
-  },
-  computed: {
-    uploadEndpoint() {
-      // This endpoint can handle XHR upload or a TUS uploadURL
-      return "/api/user-storage/" + this.storagePath;
-    },
-    username() {
-      return session.Session.username;
-    },
-  },
-  data() {
-    return {
-      dirName: null,
-    };
-  },
-  props: {
-    userStoragePath: {
-      required: true,
-    },
-    storagePath: {
-      required: true,
-    },
-  },
-  methods: {
-    uploadSuccess() {
-      this.$refs["file-upload"].reset();
-      this.$emit("upload-success");
-    },
-    addDirectory() {
-      this.$emit("add-directory", this.dirName);
-      this.dirName = null;
-    },
-  },
-};
-</script>
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
index 1193a41..44e4771 100644
--- 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
@@ -3,7 +3,6 @@
     <user-storage-path-viewer
       v-if="userStoragePath"
       :user-storage-path="userStoragePath"
-      :storage-path="storagePath"
       @directory-selected="directorySelected"
       @file-selected="fileSelected"
       :include-delete-action="false"
@@ -31,11 +30,7 @@ let mostRecentPath = "~";
 
 export default {
   name: "user-storage-file-selection-container",
-  computed: {
-    storagePath() {
-      return ["~"].concat(this.userStoragePath.parts).join("/") + "/";
-    },
-  },
+  computed: {},
   props: {
     selectedDataProductUris: {
       type: Array,
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 7f42867..d1aa85c 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
@@ -1,12 +1,5 @@
 <template>
   <div>
-    <user-storage-create-view
-      v-if="includeCreateFileAction && userStoragePath && isDir"
-      :user-storage-path="userStoragePath"
-      :storage-path="storagePath"
-      @upload-success="$emit('upload-success')"
-      @add-directory="(dirName) => $emit('add-directory', dirName)"
-    />
     <user-storage-path-breadcrumb
       v-if="userStoragePath && isDir"
       :parts="userStoragePath.parts"
@@ -36,11 +29,16 @@
         >
           <i class="fa fa-folder-open"></i> {{ data.item.name }}
         </b-link>
-        <user-storage-link v-else :data-product-uri="data.item.dataProductURI" :mime-type="data.item.mimeType"
-                           :file-name="data.item.name" :allow-preview="allowPreview"/>
+        <user-storage-link
+          v-else
+          :data-product-uri="data.item.dataProductURI"
+          :mime-type="data.item.mimeType"
+          :file-name="data.item.name"
+          :allow-preview="allowPreview"
+        />
       </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">
         <b-button
@@ -55,16 +53,16 @@
           v-if="includeDeleteAction"
           @delete="deleteItem(data.item)"
         >
-          Are you sure you want to delete <strong>{{ data.item.name }}</strong>?
+          Are you sure you want to delete <strong>{{ data.item.name }}</strong
+          >?
         </delete-button>
       </template>
     </b-table>
   </div>
 </template>
 <script>
-import UserStoragePathBreadcrumb from "./UserStoragePathBreadcrumb.vue";
-import {components} from "django-airavata-common-ui";
-import UserStorageCreateView from "./UserStorageCreateView";
+import UserStoragePathBreadcrumb from "./StoragePathBreadcrumb.vue";
+import { components } from "django-airavata-common-ui";
 import UserStorageEditViewer from "./storage-edit/UserStorageEditViewer";
 import UserStorageLink from "./storage-edit/UserStorageLink";
 
@@ -73,14 +71,11 @@ export default {
   props: {
     allowPreview: {
       default: true,
-      required: false
+      required: false,
     },
     userStoragePath: {
       required: true,
     },
-    storagePath: {
-      required: true,
-    },
     includeDeleteAction: {
       type: Boolean,
       default: true,
@@ -107,7 +102,6 @@ export default {
     "delete-button": components.DeleteButton,
     "human-date": components.HumanDate,
     UserStoragePathBreadcrumb,
-    UserStorageCreateView,
     UserStorageEditViewer,
   },
   computed: {
@@ -211,10 +205,6 @@ export default {
         ) !== undefined
       );
     },
-    storageFileViewRouteUrl(item) {
-      // This endpoint can handle XHR upload or a TUS uploadURL
-      return `/workspace/storage/${this.storagePath}${item.name}`;
-    },
   },
 };
 </script>