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/01/25 22:09:33 UTC

[airavata-django-portal] branch master updated (b5df490 -> 9ba962d)

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

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


    from b5df490  AIRAVATA-2647 Refreshing token when access token expires
     new 264845e  AIRAVATA-2615 WIP Experiment Summary view
     new f805d3f  AIRAVATA-2615 Experiment summary: additional fields
     new 664f935  AIRAVATA-2615: FullExperiment model
     new 73b380c  AIRAVATA-2615 Implementing ExperimentState as an enum
     new f32c54f  AIRAVATA-2615 poll for updates to experiment
     new 9ba962d  AIRAVATA-2615 Stop polling if experiment no longer progressing

The 6 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:
 django_airavata/apps/api/package-lock.json         |  19 +++
 django_airavata/apps/api/package.json              |   4 +-
 django_airavata/apps/api/serializers.py            |  62 +++++++-
 .../api/static/django_airavata_api/js/index.js     |   8 +-
 .../django_airavata_api/js/models/BaseEnum.js      |  25 +++
 .../django_airavata_api/js/models/BaseModel.js     |  15 +-
 .../js/models/ComputeResourceDescription.js        |  42 +++++
 .../django_airavata_api/js/models/DataProduct.js   |  50 ++++++
 .../js/models/DataReplicaLocation.js               |  31 ++++
 .../django_airavata_api/js/models/Experiment.js    |  11 ++
 .../js/models/ExperimentState.js                   |  15 ++
 .../js/models/ExperimentStatus.js                  |   7 +-
 .../js/models/FullExperiment.js                    |  64 ++++++++
 .../js/services/ExperimentService.js               |  12 +-
 .../js/services/FullExperimentService.js           |  18 +++
 .../js/services/ProjectService.js                  |  10 +-
 django_airavata/apps/api/urls.py                   |   1 +
 django_airavata/apps/api/views.py                  |  59 ++++++-
 .../js/components/experiment/ExperimentSummary.vue | 176 +++++++++++++++++++++
 .../js/containers/ViewExperimentContainer.vue      |  37 +++++
 .../js/entry-view-experiment.js                    |  25 +++
 ...create_experiment.html => view_experiment.html} |   6 +-
 django_airavata/apps/workspace/urls.py             |   2 +
 django_airavata/apps/workspace/views.py            |  15 ++
 django_airavata/apps/workspace/webpack.config.js   |   1 +
 25 files changed, 695 insertions(+), 20 deletions(-)
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/models/BaseEnum.js
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourceDescription.js
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/models/DataProduct.js
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/models/DataReplicaLocation.js
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentState.js
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/services/FullExperimentService.js
 create mode 100644 django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue
 create mode 100644 django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/ViewExperimentContainer.vue
 create mode 100644 django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-view-experiment.js
 copy django_airavata/apps/workspace/templates/django_airavata_workspace/{create_experiment.html => view_experiment.html} (54%)

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.

[airavata-django-portal] 04/06: AIRAVATA-2615 Implementing ExperimentState as an enum

Posted by ma...@apache.org.
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 73b380cd3b3b420e43124e0cd1939d32ecc09c94
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Thu Jan 25 10:57:01 2018 -0500

    AIRAVATA-2615 Implementing ExperimentState as an enum
---
 .../django_airavata_api/js/models/BaseEnum.js      | 25 ++++++++++++++++++++++
 .../django_airavata_api/js/models/BaseModel.js     | 10 ++++++++-
 .../js/models/ExperimentState.js                   | 15 +++++++++++++
 .../js/models/ExperimentStatus.js                  | 23 +++++---------------
 .../js/models/FullExperiment.js                    |  2 +-
 5 files changed, 55 insertions(+), 20 deletions(-)

diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/BaseEnum.js b/django_airavata/apps/api/static/django_airavata_api/js/models/BaseEnum.js
new file mode 100644
index 0000000..bb11276
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/BaseEnum.js
@@ -0,0 +1,25 @@
+
+export default class BaseEnum {
+    constructor(name, value) {
+        this.name = name;
+        this.value = value;
+        // immutable
+        Object.freeze(this);
+    }
+    toJSON() {
+        return this.value;
+    }
+    static byName(name) {
+        return this.values.find(x => x.name === name);
+    }
+    static byValue(value) {
+        return this.values.find(x => x.value === value);
+    }
+    // This must be called to initialize static methods on the Enum subclass
+    static init(names) {
+        const enums = names.map((name, index) => new this(name, index));
+        Object.freeze(enums);
+        Object.defineProperty(this, 'values', {get: function() { return enums;}});
+        this.values.forEach(v => this[v.name] = v);
+    }
+}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js b/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
index 49f773b..8b5679f 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
@@ -1,3 +1,4 @@
+import BaseEnum from './BaseEnum'
 
 export default class BaseModel {
 
@@ -51,7 +52,14 @@ export default class BaseModel {
     }
 
     convertModelField(modelClass, fieldValue, fieldDefault) {
-        return typeof fieldValue !== 'undefined' ? new modelClass(fieldValue) : fieldDefault;
+        if (typeof fieldValue !== 'undefined') {
+            if (modelClass.prototype instanceof BaseEnum) {
+                return modelClass.byValue(fieldValue);
+            } else {
+                return new modelClass(fieldValue);
+            }
+        }
+        return fieldDefault;
     }
 
     getDefaultValue(fieldDefault) {
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentState.js b/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentState.js
new file mode 100644
index 0000000..ab3a626
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentState.js
@@ -0,0 +1,15 @@
+import BaseEnum from './BaseEnum'
+
+export default class ExperimentState extends BaseEnum {
+}
+ExperimentState.init([
+    'CREATED',
+    'VALIDATED',
+    'SCHEDULED',
+    'LAUNCHED',
+    'EXECUTING',
+    'CANCELING',
+    'CANCELED',
+    'COMPLETED',
+    'FAILED'
+]);
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatus.js b/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatus.js
index 2b5efc7..2660cf3 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatus.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatus.js
@@ -1,8 +1,11 @@
 import BaseModel from './BaseModel';
+import ExperimentState from './ExperimentState';
 
 const FIELDS = [
-    // TODO: state is an enum field
-     'state',
+     {
+         name: 'state',
+         type: ExperimentState,
+     },
      {
          name: 'timeOfStateChange',
          type: 'date',
@@ -10,24 +13,8 @@ const FIELDS = [
      'reason',
 ];
 
-const STATE_NAMES = {
-    0: "CREATED",
-    1: "VALIDATED",
-    2: "SCHEDULED",
-    3: "LAUNCHED",
-    4: "EXECUTING",
-    5: "CANCELING",
-    6: "CANCELED",
-    7: "COMPLETED",
-    8: "FAILED",
-}
-
 export default class ExperimentStatus extends BaseModel {
     constructor(data = {}) {
         super(FIELDS, data);
     }
-
-    get stateName() {
-        return STATE_NAMES[this.state];
-    }
 }
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js b/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js
index 34e8d65..6059b2a 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js
@@ -59,6 +59,6 @@ export default class FullExperiment extends BaseModel {
     }
 
     get experimentStatusName() {
-        return this.experimentStatus ? this.experimentStatus.stateName : null;
+        return this.experimentStatus ? this.experimentStatus.state.name : null;
     }
 }

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.

[airavata-django-portal] 01/06: AIRAVATA-2615 WIP Experiment Summary view

Posted by ma...@apache.org.
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 264845ef446cc6abd5d029cd9fb5ce8efd568a47
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Thu Jan 18 12:59:39 2018 -0500

    AIRAVATA-2615 WIP Experiment Summary view
---
 .../js/models/ExperimentStatus.js                  |  16 +++
 .../js/services/ExperimentService.js               |  12 ++-
 .../js/services/ProjectService.js                  |  10 +-
 .../js/components/experiment/ExperimentSummary.vue | 109 +++++++++++++++++++++
 .../js/containers/ViewExperimentContainer.vue      |  37 +++++++
 .../js/entry-view-experiment.js                    |  26 +++++
 .../django_airavata_workspace/view_experiment.html |  19 ++++
 django_airavata/apps/workspace/urls.py             |   2 +
 django_airavata/apps/workspace/views.py            |  13 +++
 django_airavata/apps/workspace/webpack.config.js   |   1 +
 10 files changed, 239 insertions(+), 6 deletions(-)

diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatus.js b/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatus.js
index bc8f0bf..2b5efc7 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatus.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ExperimentStatus.js
@@ -10,8 +10,24 @@ const FIELDS = [
      'reason',
 ];
 
+const STATE_NAMES = {
+    0: "CREATED",
+    1: "VALIDATED",
+    2: "SCHEDULED",
+    3: "LAUNCHED",
+    4: "EXECUTING",
+    5: "CANCELING",
+    6: "CANCELED",
+    7: "COMPLETED",
+    8: "FAILED",
+}
+
 export default class ExperimentStatus extends BaseModel {
     constructor(data = {}) {
         super(FIELDS, data);
     }
+
+    get stateName() {
+        return STATE_NAMES[this.state];
+    }
 }
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/services/ExperimentService.js b/django_airavata/apps/api/static/django_airavata_api/js/services/ExperimentService.js
index 0aa81b5..a90295b 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/services/ExperimentService.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/services/ExperimentService.js
@@ -32,10 +32,14 @@ class ExperimentService {
         }
     }
 
-    get() {
-        return FetchUtils.get('/api/experiments/'
-                + encodeURIComponent(experiment.experimentId) + '/')
-            .then(result => new Experiment(result));
+    get(experimentId, data = null) {
+        if (data) {
+            return Promise.resolve(new Experiment(data));
+        } else {
+            return FetchUtils.get('/api/experiments/'
+                    + encodeURIComponent(experimentId) + '/')
+                .then(result => new Experiment(result));
+        }
     }
 
     launch(experimentId) {
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/services/ProjectService.js b/django_airavata/apps/api/static/django_airavata_api/js/services/ProjectService.js
index c78c5a5..78c1825 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/services/ProjectService.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/services/ProjectService.js
@@ -33,8 +33,14 @@ class ProjectService {
         // TODO
     }
 
-    get() {
-        // TODO
+    get(projectId, data=null) {
+        if (data) {
+            return Promise.resolve(new Project(data));
+        } else {
+            return FetchUtils.get('/api/projects/'
+                    + encodeURIComponent(projectId) + '/')
+                .then(result => new Project(result));
+        }
     }
 }
 
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
new file mode 100644
index 0000000..ba9ecac
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/ExperimentSummary.vue
@@ -0,0 +1,109 @@
+<template>
+    <div>
+        <div class="row">
+            <div class="col">
+                <h1 class="h4 mb-4">
+                    <slot name="title">Experiment Summary</slot>
+                </h1>
+            </div>
+        </div>
+        <div class="row">
+            <div class="col">
+                <div class="card border-default">
+                    <div class="card-body">
+                        <table class="table">
+                            <tbody>
+                                <tr>
+                                    <th scope="row">Name</th>
+                                    <td><span :title="localExperiment.experimentId">{{ localExperiment.experimentName }}</span></td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">Description</th>
+                                    <td>{{ localExperiment.description }}</td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">Project</th>
+                                    <td>{{ project && project.name || '' }}</td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">Outputs</th>
+                                    <td></td>
+                                </tr>
+                                <!-- Going to leave this out for now -->
+                                <!-- <tr>
+                                    <th scope="row">Storage Directory</th>
+                                    <td></td>
+                                </tr> -->
+                                <tr>
+                                    <th scope="row">Owner</th>
+                                    <td>{{ localExperiment.userName }}</td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">Application</th>
+                                    <td></td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">Compute Resource</th>
+                                    <td></td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">Experiment Status</th>
+                                    <td>{{ localExperiment.experimentStatus[0].stateName }}</td>
+                                </tr>
+                            </tbody>
+                        </table>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+
+import {models, services} from 'django-airavata-api'
+
+export default {
+    name: 'experiment-summary',
+    props: {
+        experiment: {
+            type: models.Experiment,
+            required: true
+        },
+    },
+    data () {
+        return {
+            localExperiment: this.experiment.clone(),
+            project: null,
+        }
+    },
+    components: {
+    },
+    computed: {
+    },
+    methods: {
+        loadProject: function() {
+            services.ProjectService.get(this.experiment.projectId)
+                .then(proj => this.project = proj);
+        },
+        loadApplication: function() {
+            
+        },
+        loadOutputs: function() {
+            
+        },
+        loadComputeHost: function() {
+            
+        },
+    },
+    watch: {
+    },
+    mounted: function() {
+        console.log(JSON.stringify(this.experiment.experimentOutputs))
+        this.loadProject();
+    }
+}
+</script>
+
+<style>
+</style>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/ViewExperimentContainer.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/ViewExperimentContainer.vue
new file mode 100644
index 0000000..1bf3482
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/ViewExperimentContainer.vue
@@ -0,0 +1,37 @@
+<template>
+    <experiment-summary v-if="experiment" :experiment="experiment">
+    </experiment-summary>
+</template>
+
+<script>
+
+import {models, services} from 'django-airavata-api'
+import ExperimentSummary from '../components/experiment/ExperimentSummary.vue'
+
+export default {
+    name: 'view-experiment-container',
+    props: {
+        initialExperimentData: {
+            required: true
+        },
+    },
+    data () {
+        return {
+            experiment: null,
+        }
+    },
+    components: {
+        ExperimentSummary,
+    },
+    methods: {
+    },
+    computed: {
+    },
+    beforeMount: function () {
+        services.ExperimentService.get(this.initialExperimentData.experimentId, this.initialExperimentData)
+            .then(exp => this.experiment = exp);
+    }
+}
+</script>
+<style>
+</style>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-view-experiment.js b/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-view-experiment.js
new file mode 100644
index 0000000..6517ba8
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-view-experiment.js
@@ -0,0 +1,26 @@
+import Vue from 'vue'
+import BootstrapVue from 'bootstrap-vue'
+import ViewExperimentContainer from './containers/ViewExperimentContainer.vue'
+
+// This is imported globally on the website so no need to include it again in this view
+// import 'bootstrap/dist/css/bootstrap.css'
+import 'bootstrap-vue/dist/bootstrap-vue.css'
+
+Vue.use(BootstrapVue);
+
+new Vue({
+  el: '#view-experiment',
+  template: '<view-experiment-container :initial-experiment-data="experiment"></view-experiment-container>',
+  data () {
+      return {
+          experiment: null,
+      }
+  },
+  components: {
+      ViewExperimentContainer,
+  },
+  beforeMount: function () {
+      console.log(this.$el.dataset.experimentData);
+      this.experiment = JSON.parse(this.$el.dataset.experimentData);
+  }
+})
diff --git a/django_airavata/apps/workspace/templates/django_airavata_workspace/view_experiment.html b/django_airavata/apps/workspace/templates/django_airavata_workspace/view_experiment.html
new file mode 100644
index 0000000..e09bf11
--- /dev/null
+++ b/django_airavata/apps/workspace/templates/django_airavata_workspace/view_experiment.html
@@ -0,0 +1,19 @@
+{% extends './base.html' %}
+
+{% load static %}
+
+{% block css %}
+{{ block.super }}
+<link rel=stylesheet type=text/css href="{% static 'django_airavata_workspace/dist/view-experiment.css' %}">
+{% endblock %}
+
+{% block content %}
+
+<div id="view-experiment" data-experiment-data="{{ experiment_data }}"></div>
+
+{% endblock content %}
+
+{% block scripts %}
+{{ block.super }}
+<script src="{% static "django_airavata_workspace/dist/view-experiment.js" %}"></script>
+{% endblock %}
diff --git a/django_airavata/apps/workspace/urls.py b/django_airavata/apps/workspace/urls.py
index fe8848f..a3aabc1 100644
--- a/django_airavata/apps/workspace/urls.py
+++ b/django_airavata/apps/workspace/urls.py
@@ -6,6 +6,8 @@ from . import views
 app_name = 'django_airavata_workspace'
 urlpatterns = [
     url(r'^projects$', views.projects_list, name='projects'),
+    url(r'^experiments/(?P<experiment_id>[^/]+)/$', views.view_experiment,
+        name='view_experiment'),
     url(r'^experiments$', views.experiments_list, name='experiments'),
     url(r'^applications/(?P<app_module_id>[^/]+)/create_experiment$', views.create_experiment, name='create_experiment'),
     url(r'^dashboard$', views.dashboard, name='dashboard'),
diff --git a/django_airavata/apps/workspace/views.py b/django_airavata/apps/workspace/views.py
index 74c6b9f..50c755d 100644
--- a/django_airavata/apps/workspace/views.py
+++ b/django_airavata/apps/workspace/views.py
@@ -6,6 +6,7 @@ from django.conf import settings
 from django.contrib.auth.decorators import login_required
 from django.shortcuts import render, redirect
 
+from django_airavata.apps.api.views import ExperimentViewSet
 from django_airavata.apps.api.views import ProjectViewSet
 
 logger = logging.getLogger(__name__)
@@ -39,3 +40,15 @@ def create_experiment(request, app_module_id):
     return render(request, 'django_airavata_workspace/create_experiment.html', {
         'app_module_id': app_module_id
     })
+
+@login_required
+def view_experiment(request, experiment_id):
+    request.active_nav_item = 'experiments'
+
+    response = ExperimentViewSet.as_view(
+        {'get': 'retrieve'})(request, experiment_id=experiment_id)
+    experiment_json = JSONRenderer().render(response.data)
+
+    return render(request, 'django_airavata_workspace/view_experiment.html', {
+        'experiment_data': experiment_json
+    })
diff --git a/django_airavata/apps/workspace/webpack.config.js b/django_airavata/apps/workspace/webpack.config.js
index 2bbacb6..b200ad7 100644
--- a/django_airavata/apps/workspace/webpack.config.js
+++ b/django_airavata/apps/workspace/webpack.config.js
@@ -8,6 +8,7 @@ module.exports = {
       'project-list': './static/django_airavata_workspace/js/entry-project-list',
       'dashboard': './static/django_airavata_workspace/js/entry-dashboard',
       'create-experiment': './static/django_airavata_workspace/js/entry-create-experiment',
+      'view-experiment': './static/django_airavata_workspace/js/entry-view-experiment',
   },
   output: {
     path: path.resolve(__dirname, './static/django_airavata_workspace/dist/'),

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.

[airavata-django-portal] 02/06: AIRAVATA-2615 Experiment summary: additional fields

Posted by ma...@apache.org.
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 f805d3f944b782628047be5935954f38721e029d
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Fri Jan 19 18:33:28 2018 -0500

    AIRAVATA-2615 Experiment summary: additional fields
---
 .../js/components/experiment/ExperimentSummary.vue | 63 ++++++++++++++++++++--
 1 file changed, 58 insertions(+), 5 deletions(-)

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 ba9ecac..9159b92 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
@@ -26,6 +26,7 @@
                                     <td>{{ project && project.name || '' }}</td>
                                 </tr>
                                 <tr>
+                                    <!-- TODO -->
                                     <th scope="row">Outputs</th>
                                     <td></td>
                                 </tr>
@@ -39,16 +40,58 @@
                                     <td>{{ localExperiment.userName }}</td>
                                 </tr>
                                 <tr>
+                                    <!-- TODO -->
                                     <th scope="row">Application</th>
                                     <td></td>
                                 </tr>
                                 <tr>
+                                    <!-- TODO -->
                                     <th scope="row">Compute Resource</th>
                                     <td></td>
                                 </tr>
                                 <tr>
                                     <th scope="row">Experiment Status</th>
-                                    <td>{{ localExperiment.experimentStatus[0].stateName }}</td>
+                                    <td>{{ experimentStatus.stateName }}</td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">Notification List</th>
+                                    <td>{{ localExperiment.emailAddresses
+                                            ? localExperiment.emailAddresses.join(", ")
+                                            : '' }}</td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">Creation Time</th>
+                                    <td><span :title="localExperiment.creationTime.toString()">{{ creationTime }}</span></td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">Last Modified Time</th>
+                                    <td><span :title="experimentStatus.timeOfStateChange.toString()">{{ lastModifiedTime }}</span></td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">Wall Time Limit</th>
+                                    <td>{{ localExperiment.userConfigurationData.computationalResourceScheduling.wallTimeLimit }} minutes</td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">CPU Count</th>
+                                    <td>{{ localExperiment.userConfigurationData.computationalResourceScheduling.totalCPUCount }}</td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">Node Count</th>
+                                    <td>{{ localExperiment.userConfigurationData.computationalResourceScheduling.nodeCount }}</td>
+                                </tr>
+                                <tr>
+                                    <th scope="row">Queue</th>
+                                    <td>{{ localExperiment.userConfigurationData.computationalResourceScheduling.queueName }}</td>
+                                </tr>
+                                <tr>
+                                    <!-- TODO -->
+                                    <th scope="row">Inputs</th>
+                                    <td></td>
+                                </tr>
+                                <tr>
+                                    <!-- TODO -->
+                                    <th scope="row">Errors</th>
+                                    <td></td>
                                 </tr>
                             </tbody>
                         </table>
@@ -63,6 +106,8 @@
 
 import {models, services} from 'django-airavata-api'
 
+import moment from 'moment';
+
 export default {
     name: 'experiment-summary',
     props: {
@@ -80,6 +125,15 @@ export default {
     components: {
     },
     computed: {
+        creationTime: function() {
+            return moment(this.localExperiment.creationTime).fromNow();
+        },
+        experimentStatus: function() {
+            return this.localExperiment.experimentStatus[0];
+        },
+        lastModifiedTime: function() {
+            return moment(this.experimentStatus.timeOfStateChange).fromNow();
+        }
     },
     methods: {
         loadProject: function() {
@@ -87,19 +141,18 @@ export default {
                 .then(proj => this.project = proj);
         },
         loadApplication: function() {
-            
+
         },
         loadOutputs: function() {
-            
+
         },
         loadComputeHost: function() {
-            
+
         },
     },
     watch: {
     },
     mounted: function() {
-        console.log(JSON.stringify(this.experiment.experimentOutputs))
         this.loadProject();
     }
 }

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.

[airavata-django-portal] 06/06: AIRAVATA-2615 Stop polling if experiment no longer progressing

Posted by ma...@apache.org.
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 9ba962dce6e193da89b4a50ed69bf49cfdb1ea48
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Thu Jan 25 17:08:32 2018 -0500

    AIRAVATA-2615 Stop polling if experiment no longer progressing
---
 .../api/static/django_airavata_api/js/models/BaseModel.js     |  5 +++++
 .../api/static/django_airavata_api/js/models/Experiment.js    | 11 +++++++++++
 django_airavata/apps/api/views.py                             | 10 ++++++++--
 .../js/components/experiment/ExperimentSummary.vue            | 11 ++++++++++-
 4 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js b/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
index 8b5679f..5bb0c63 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/BaseModel.js
@@ -54,6 +54,11 @@ export default class BaseModel {
     convertModelField(modelClass, fieldValue, fieldDefault) {
         if (typeof fieldValue !== 'undefined') {
             if (modelClass.prototype instanceof BaseEnum) {
+                // When cloning the fieldValue is an enum instance
+                if (fieldValue instanceof BaseEnum){
+                    return fieldValue;
+                }
+                // Otherwise it is an integer that we need to convert to enum
                 return modelClass.byValue(fieldValue);
             } else {
                 return new modelClass(fieldValue);
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 1f249dc..560e4ce 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
@@ -1,6 +1,7 @@
 
 import BaseModel from './BaseModel';
 import ErrorModel from './ErrorModel'
+import ExperimentState from './ExperimentState'
 import ExperimentStatus from './ExperimentStatus'
 import InputDataObjectType from './InputDataObjectType'
 import OutputDataObjectType from './OutputDataObjectType'
@@ -98,4 +99,14 @@ export default class Experiment extends BaseModel {
         }
         return validationResults;
     }
+
+    get isProgressing() {
+        const progressingStates = [ExperimentState.SCHEDULED,
+                                   ExperimentState.LAUNCHED,
+                                   ExperimentState.EXECUTING,
+                                   ExperimentState.CANCELING];
+        return this.experimentStatus
+            && this.experimentStatus.length > 0
+            && progressingStates.indexOf(this.experimentStatus[0].state) >= 0;
+    }
 }
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index 45be9db..99fce0d 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -275,12 +275,18 @@ class FullExperimentViewSet(mixins.RetrieveModelMixin,
             self.request.airavata_client.getDataProduct(self.authz_token,
                                                         output.value)
             for output in experimentModel.experimentOutputs
-            if output.type in (DataType.URI, DataType.STDOUT, DataType.STDERR)]
+            if (output.value.startswith('airavata-dp')
+                and output.type in (DataType.URI,
+                                    DataType.STDOUT,
+                                    DataType.STDERR))]
         inputDataProducts = [
             self.request.airavata_client.getDataProduct(self.authz_token,
                                                         inp.value)
             for inp in experimentModel.experimentInputs
-            if inp.type in (DataType.URI, DataType.STDOUT, DataType.STDERR)]
+            if (inp.value.startswith('airavata-dp')
+                and inp.type in (DataType.URI,
+                                 DataType.STDOUT,
+                                 DataType.STDERR))]
         appInterfaceId = experimentModel.executionId
         applicationInterface = self.request.airavata_client\
             .getApplicationInterface(self.authz_token, appInterfaceId)
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 77c7535..ba00545 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
@@ -52,7 +52,13 @@
                                 </tr>
                                 <tr>
                                     <th scope="row">Experiment Status</th>
-                                    <td>{{ fullExperiment.experimentStatusName }}</td>
+                                    <td>
+                                        <template v-if="fullExperiment.experiment.isProgressing">
+                                            <i class="fa fa-refresh fa-spin"></i>
+                                            <span class="sr-only">Progressing...</span>
+                                        </template>
+                                        {{ fullExperiment.experimentStatusName }}
+                                    </td>
                                 </tr>
                                 <!--  TODO: leave this out for now -->
                                 <!-- <tr>
@@ -147,6 +153,9 @@ export default {
         },
         initPollingExperiment: function() {
             var pollExperiment = function() {
+                if (!this.localFullExperiment.experiment.isProgressing) {
+                    return;
+                }
                 this.loadExperiment()
                     .then(exp => {
                         setTimeout(pollExperiment.bind(this), 3000);

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.

[airavata-django-portal] 05/06: AIRAVATA-2615 poll for updates to experiment

Posted by ma...@apache.org.
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 f32c54fbe0e0670cc395ed57af898c4dd7924902
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Thu Jan 25 15:56:16 2018 -0500

    AIRAVATA-2615 poll for updates to experiment
---
 .../js/components/experiment/ExperimentSummary.vue       | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

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 997759b..77c7535 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
@@ -141,9 +141,25 @@ export default {
         }
     },
     methods: {
+        loadExperiment: function() {
+            return services.FullExperimentService.get(this.localFullExperiment.experiment.experimentId)
+                .then(exp => this.localFullExperiment = exp);
+        },
+        initPollingExperiment: function() {
+            var pollExperiment = function() {
+                this.loadExperiment()
+                    .then(exp => {
+                        setTimeout(pollExperiment.bind(this), 3000);
+                    })
+            }.bind(this);
+            setTimeout(pollExperiment, 3000);
+        }
     },
     watch: {
     },
+    mounted: function() {
+        this.initPollingExperiment();
+    }
 }
 </script>
 

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.

[airavata-django-portal] 03/06: AIRAVATA-2615: FullExperiment model

Posted by ma...@apache.org.
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 664f9359735c4521a9f44f74977a5fada61cb990
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Mon Jan 22 09:23:31 2018 -0500

    AIRAVATA-2615: FullExperiment model
    
    FullExperiment includes the experiment model and other models that are
    referenced in the experiment model like input and output DataProducts.
---
 django_airavata/apps/api/package-lock.json         | 19 +++++
 django_airavata/apps/api/package.json              |  4 +-
 django_airavata/apps/api/serializers.py            | 62 ++++++++++++++--
 .../api/static/django_airavata_api/js/index.js     |  8 ++-
 .../js/models/ComputeResourceDescription.js        | 42 +++++++++++
 .../django_airavata_api/js/models/DataProduct.js   | 50 +++++++++++++
 .../js/models/DataReplicaLocation.js               | 31 ++++++++
 .../js/models/FullExperiment.js                    | 64 +++++++++++++++++
 .../js/services/FullExperimentService.js           | 18 +++++
 django_airavata/apps/api/urls.py                   |  1 +
 django_airavata/apps/api/views.py                  | 53 +++++++++++++-
 .../js/components/experiment/ExperimentSummary.vue | 83 ++++++++++------------
 .../js/containers/ViewExperimentContainer.vue      | 10 +--
 .../js/entry-view-experiment.js                    |  7 +-
 .../django_airavata_workspace/view_experiment.html |  2 +-
 django_airavata/apps/workspace/views.py            |  8 ++-
 16 files changed, 394 insertions(+), 68 deletions(-)

diff --git a/django_airavata/apps/api/package-lock.json b/django_airavata/apps/api/package-lock.json
index 1476b2f..8c52d47 100644
--- a/django_airavata/apps/api/package-lock.json
+++ b/django_airavata/apps/api/package-lock.json
@@ -2244,6 +2244,11 @@
       "dev": true,
       "optional": true
     },
+    "querystringify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-1.0.0.tgz",
+      "integrity": "sha1-YoYkIRLFtxL6ZU5SZlK/ahP/Bcs="
+    },
     "randomatic": {
       "version": "1.1.7",
       "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
@@ -2413,6 +2418,11 @@
         "is-finite": "1.0.2"
       }
     },
+    "requires-port": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+      "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
+    },
     "safe-buffer": {
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
@@ -2490,6 +2500,15 @@
       "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
       "dev": true
     },
+    "url-parse": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.2.0.tgz",
+      "integrity": "sha512-DT1XbYAfmQP65M/mE6OALxmXzZ/z1+e5zk2TcSKe/KiYbNGZxgtttzC0mR/sjopbpOXcbniq7eIKmocJnUWlEw==",
+      "requires": {
+        "querystringify": "1.0.0",
+        "requires-port": "1.0.0"
+      }
+    },
     "user-home": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz",
diff --git a/django_airavata/apps/api/package.json b/django_airavata/apps/api/package.json
index b31e3c8..cb96262 100644
--- a/django_airavata/apps/api/package.json
+++ b/django_airavata/apps/api/package.json
@@ -9,7 +9,9 @@
     "build": "babel static/django_airavata_api/js -d static/django_airavata_api/dist",
     "watch": "babel static/django_airavata_api/js --watch -d static/django_airavata_api/dist"
   },
-  "dependencies": {},
+  "dependencies": {
+    "url-parse": "^1.2.0"
+  },
   "devDependencies": {
     "babel-cli": "^6.26.0",
     "babel-preset-env": "^1.5.1"
diff --git a/django_airavata/apps/api/serializers.py b/django_airavata/apps/api/serializers.py
index 511d080..a230503 100644
--- a/django_airavata/apps/api/serializers.py
+++ b/django_airavata/apps/api/serializers.py
@@ -1,13 +1,13 @@
 
-from airavata.model.experiment.ttypes import ExperimentModel
-from airavata.model.workspace.ttypes import Project
 from airavata.model.appcatalog.appdeployment.ttypes import ApplicationModule, ApplicationDeploymentDescription,CommandObject,SetEnvPaths
 from airavata.model.appcatalog.appinterface.ttypes import ApplicationInterfaceDescription
+from airavata.model.appcatalog.computeresource.ttypes import BatchQueue
 from airavata.model.application.io.ttypes import InputDataObjectType, OutputDataObjectType
+from airavata.model.data.replica.ttypes import DataProductModel, DataReplicaLocationModel
 from airavata.model.experiment.ttypes import ExperimentModel
+from airavata.model.status.ttypes import ExperimentStatus
 from airavata.model.workspace.ttypes import Project
-from airavata.model.appcatalog.appdeployment.ttypes import ApplicationModule
-from airavata.model.appcatalog.computeresource.ttypes import BatchQueue
+
 from . import thrift_utils
 
 from django.conf import settings
@@ -231,6 +231,10 @@ class BatchQueueSerializer(thrift_utils.create_serializer_class(BatchQueue)):
     pass
 
 
+class ExperimentStatusSerializer(thrift_utils.create_serializer_class(ExperimentStatus)):
+    timeOfStateChange = UTCPosixTimestampDateTimeField()
+
+
 class ExperimentSerializer(
         thrift_utils.create_serializer_class(ExperimentModel)):
 
@@ -239,7 +243,57 @@ class ExperimentSerializer(
         read_only = ('experimentId',)
 
     url = FullyEncodedHyperlinkedIdentityField(view_name='django_airavata_api:experiment-detail', lookup_field='experimentId', lookup_url_kwarg='experiment_id')
+    full_experiment = FullyEncodedHyperlinkedIdentityField(view_name='django_airavata_api:full-experiment-detail', lookup_field='experimentId', lookup_url_kwarg='experiment_id')
     project = FullyEncodedHyperlinkedIdentityField(view_name='django_airavata_api:project-detail', lookup_field='projectId', lookup_url_kwarg='project_id')
     userName = GatewayUsernameDefaultField()
     gatewayId = GatewayIdDefaultField()
     creationTime = UTCPosixTimestampDateTimeField(allow_null=True)
+    experimentStatus = ExperimentStatusSerializer(many=True)
+
+
+class DataReplicaLocationSerializer(
+        thrift_utils.create_serializer_class(DataReplicaLocationModel)):
+    creationTime = UTCPosixTimestampDateTimeField()
+    lastModifiedTime = UTCPosixTimestampDateTimeField()
+
+
+class DataProductSerializer(
+        thrift_utils.create_serializer_class(DataProductModel)):
+    creationTime = UTCPosixTimestampDateTimeField()
+    lastModifiedTime = UTCPosixTimestampDateTimeField()
+    replicaLocations = DataReplicaLocationSerializer(many=True)
+
+
+# TODO move this into airavata_sdk?
+class FullExperiment:
+    """Experiment with referenced data models."""
+
+    def __init__(self, experimentModel, project=None, outputDataProducts=None,
+                 inputDataProducts=None, applicationModule=None,
+                 computeResource=None):
+        self.experiment = experimentModel
+        self.experimentId = experimentModel.experimentId
+        self.project = project
+        self.outputDataProducts = outputDataProducts
+        self.inputDataProducts = inputDataProducts
+        self.applicationModule = applicationModule
+        self.computeResource = computeResource
+
+
+class FullExperimentSerializer(serializers.Serializer):
+    url = FullyEncodedHyperlinkedIdentityField(
+        view_name='django_airavata_api:full-experiment-detail',
+        lookup_field='experimentId',
+        lookup_url_kwarg='experiment_id')
+    experiment = ExperimentSerializer()
+    outputDataProducts = DataProductSerializer(many=True, read_only=True)
+    inputDataProducts = DataProductSerializer(many=True, read_only=True)
+    applicationModule = ApplicationModuleSerializer(read_only=True)
+    computeResource = ComputeResourceDescriptionSerializer(read_only=True)
+    project = ProjectSerializer(read_only=True)
+
+    def create(self, validated_data):
+        raise Exception("Not implemented")
+
+    def update(self, instance, validated_data):
+        raise Exception("Not implemented")
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 8860efb..6562ed1 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
@@ -3,13 +3,15 @@ import ApplicationInterfaceDefinition from './models/ApplicationInterfaceDefinit
 import ApplicationModule from './models/ApplicationModule'
 import Experiment from './models/Experiment'
 import InputDataObjectType from './models/InputDataObjectType'
-import OutputDataTypeObject from './models/OutputDataTypeObject'
+import OutputDataObjectType from './models/OutputDataObjectType'
 import Project from './models/Project'
+import FullExperiment from './models/FullExperiment'
 
 import ApplicationDeploymentService from './services/ApplicationDeploymentService'
 import ApplicationInterfaceService from './services/ApplicationInterfaceService'
 import ApplicationModuleService from './services/ApplicationModuleService'
 import ExperimentService from './services/ExperimentService'
+import FullExperimentService from './services/FullExperimentService'
 import ProjectService from './services/ProjectService'
 
 import FetchUtils from './utils/FetchUtils'
@@ -19,8 +21,9 @@ exports.models = {
     ApplicationInterfaceDefinition,
     ApplicationModule,
     Experiment,
+    FullExperiment,
     InputDataObjectType,
-    OutputDataTypeObject,
+    OutputDataObjectType,
     Project,
 }
 
@@ -29,6 +32,7 @@ exports.services = {
     ApplicationInterfaceService,
     ApplicationModuleService,
     ExperimentService,
+    FullExperimentService,
     ProjectService,
 }
 
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourceDescription.js b/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourceDescription.js
new file mode 100644
index 0000000..f59d770
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ComputeResourceDescription.js
@@ -0,0 +1,42 @@
+import BaseModel from './BaseModel'
+import BatchQueue from './BatchQueue'
+
+const FIELDS = [
+    'computeResourceId',
+    'hostName',
+    {
+        name: 'hostAliases',
+        type: 'string',
+        list: true
+    },
+    {
+        name: 'ipAddresses',
+        type: 'string',
+        list: true
+    },
+    'resourceDescription',
+    'enabled',
+    {
+        name: 'batchQueues',
+        type: BatchQueue,
+        list: true
+    },
+    // TODO: map these
+    // 'fileSystems',
+    // 'jobSubmissionInterfaces',
+    // 'dataMovementInterfaces',
+    'maxMemoryPerNode',
+    'gatewayUsageReporting',
+    'gatewayUsageModuleLoadCommand',
+    'gatewayUsageExecutable',
+    'cpusPerNode',
+    'defaultNodeCount',
+    'defaultCPUCount',
+    'defaultWalltime',
+]
+
+export default class FullExperiment extends BaseModel {
+    constructor(data = {}) {
+        super(FIELDS, data);
+    }
+}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/DataProduct.js b/django_airavata/apps/api/static/django_airavata_api/js/models/DataProduct.js
new file mode 100644
index 0000000..dff0251
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/DataProduct.js
@@ -0,0 +1,50 @@
+
+import BaseModel from './BaseModel'
+import DataReplicaLocation from './DataReplicaLocation'
+
+import URL from 'url-parse'
+
+const FIELDS = [
+    'productUri',
+    'gatewayId',
+    'parentProductUri',
+    'productName',
+    'productDescription',
+    'ownerName',
+    'dataProductType',
+    'productSize',
+    {
+        name: 'creationTime',
+        type: 'date',
+    },
+    {
+        name: 'lastModifiedTime',
+        type: 'date',
+    },
+    'productMetadata',
+    {
+        name: 'replicaLocations',
+        type: DataReplicaLocation,
+        list: true
+    },
+];
+
+const FILENAME_REGEX = /[^/]+$/;
+
+export default class DataProduct extends BaseModel {
+    constructor(data = {}) {
+        super(FIELDS, data);
+    }
+
+    get filename() {
+        if (this.replicaLocations && this.replicaLocations.length > 0) {
+            const firstReplicaLocation = this.replicaLocations[0];
+            const fileURL = new URL(firstReplicaLocation.filePath);
+            const filenameMatch = FILENAME_REGEX.exec(fileURL.pathname);
+            if (filenameMatch) {
+                return filenameMatch[0];
+            }
+        }
+        return null;
+    }
+}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/DataReplicaLocation.js b/django_airavata/apps/api/static/django_airavata_api/js/models/DataReplicaLocation.js
new file mode 100644
index 0000000..d0bbc07
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/DataReplicaLocation.js
@@ -0,0 +1,31 @@
+import BaseModel from './BaseModel'
+
+const FIELDS = [
+    'replicaId',
+    'productUri',
+    'replicaName',
+    'replicaDescription',
+    {
+        name: 'creationTime',
+        type: 'date',
+    },
+    {
+        name: 'lastModifiedTime',
+        type: 'date',
+    },
+    {
+        name: 'validUntilTime',
+        type: 'date',
+    },
+    'replicaLocationCategory',
+    'replicaPersistentType',
+    'storageResourceId',
+    'filePath',
+    'replicaMetadata',
+];
+
+export default class DataReplicaLocation extends BaseModel {
+    constructor(data = {}) {
+        super(FIELDS, data);
+    }
+}
\ No newline at end of file
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js b/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js
new file mode 100644
index 0000000..34e8d65
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/FullExperiment.js
@@ -0,0 +1,64 @@
+
+import ApplicationModule from './ApplicationModule'
+import BaseModel from './BaseModel'
+import ComputeResourceDescription from './ComputeResourceDescription'
+import DataProduct from './DataProduct.js'
+import Experiment from './Experiment'
+import Project from './Project'
+
+const FIELDS = [
+    'experimentId',
+    {
+        name: 'experiment',
+        type: Experiment,
+    },
+    {
+        name: 'project',
+        type: Project
+    },
+    {
+        name: 'applicationModule',
+        type: ApplicationModule
+    },
+    {
+        name: 'computeResource',
+        type: ComputeResourceDescription
+    },
+    {
+        name: 'outputDataProducts',
+        type: DataProduct,
+        list: true
+    },
+    {
+        name: 'inputDataProducts',
+        type: DataProduct,
+        list: true
+    }
+];
+
+export default class FullExperiment extends BaseModel {
+    constructor(data = {}) {
+        super(FIELDS, data);
+    }
+
+    get projectName() {
+        return this.project ? this.project.name : null;
+    }
+
+    get applicationName() {
+        return this.applicationModule ? this.applicationModule.appModuleName : null;
+    }
+
+    get computeHostName() {
+        return this.computeResource ? this.computeResource.hostName : null;
+    }
+
+    get experimentStatus() {
+        return this.experiment.experimentStatus && this.experiment.experimentStatus.length > 0
+            ? this.experiment.experimentStatus[0] : null;
+    }
+
+    get experimentStatusName() {
+        return this.experimentStatus ? this.experimentStatus.stateName : null;
+    }
+}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/services/FullExperimentService.js b/django_airavata/apps/api/static/django_airavata_api/js/services/FullExperimentService.js
new file mode 100644
index 0000000..90acd57
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/services/FullExperimentService.js
@@ -0,0 +1,18 @@
+
+import FullExperiment from '../models/FullExperiment'
+import FetchUtils from '../utils/FetchUtils'
+
+class FullExperimentService {
+    get(experimentId, data = null) {
+        if (data) {
+            return Promise.resolve(new FullExperiment(data));
+        } else {
+            return FetchUtils.get('/api/full-experiments/'
+                    + encodeURIComponent(experimentId) + '/')
+                .then(result => new FullExperiment(result));
+        }
+    }
+}
+
+// Export as a singleton
+export default new FullExperimentService();
\ No newline at end of file
diff --git a/django_airavata/apps/api/urls.py b/django_airavata/apps/api/urls.py
index a9c059a..e20babf 100644
--- a/django_airavata/apps/api/urls.py
+++ b/django_airavata/apps/api/urls.py
@@ -11,6 +11,7 @@ logger = logging.getLogger(__name__)
 router = routers.DefaultRouter()
 router.register(r'projects', views.ProjectViewSet, base_name='project')
 router.register(r'experiments', views.ExperimentViewSet, base_name='experiment')
+router.register(r'full-experiments', views.FullExperimentViewSet, base_name='full-experiment')
 router.register(r'new/application/module', views.RegisterApplicationModule, base_name='register_app_module')
 router.register(r'application-interfaces', views.ApplicationInterfaceViewSet, base_name='application-interface')
 router.register(r'applications', views.ApplicationModuleViewSet, base_name='application')
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index 7d2f6ed..45be9db 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -24,6 +24,9 @@ from airavata.model.appcatalog.appdeployment.ttypes import ApplicationModule, Ap
 from airavata.model.appcatalog.appinterface.ttypes import ApplicationInterfaceDescription
 from airavata.model.appcatalog.computeresource.ttypes import ComputeResourceDescription
 from airavata.model.credential.store.ttypes import CredentialOwnerType,SummaryType,CredentialSummary
+from airavata.model.application.io.ttypes import DataType
+
+from airavata_sdk.experiment import Experiment
 
 from collections import OrderedDict
 import logging
@@ -102,6 +105,7 @@ class APIBackedViewSet(mixins.CreateModelMixin,
     """
     pass
 
+
 class APIResultIterator(object):
     """
     Iterable container over API results which allow limit/offset style slicing.
@@ -232,7 +236,7 @@ class ExperimentViewSet(APIBackedViewSet):
     lookup_field = 'experiment_id'
 
     def get_list(self):
-        return self.request.airavata_client.getUserExperiments(self.authz_token, self.gateway_id, self.username, 1, 0)
+        return self.request.airavata_client.getUserExperiments(self.authz_token, self.gateway_id, self.username, -1, 0)
 
     def get_instance(self, lookup_value):
         return self.request.airavata_client.getExperiment(self.authz_token, lookup_value)
@@ -256,6 +260,53 @@ class ExperimentViewSet(APIBackedViewSet):
             return Response({'success': False, 'errorMessage': e.message})
 
 
+class FullExperimentViewSet(mixins.RetrieveModelMixin,
+                            GenericAPIBackedViewSet):
+
+    serializer_class = serializers.FullExperimentSerializer
+    lookup_field = 'experiment_id'
+
+    def get_instance(self, lookup_value):
+        """Get FullExperiment instance with resolved references."""
+        # TODO: move loading experiment and references to airavata_sdk?
+        experimentModel = self.request.airavata_client.getExperiment(
+            self.authz_token, lookup_value)
+        outputDataProducts = [
+            self.request.airavata_client.getDataProduct(self.authz_token,
+                                                        output.value)
+            for output in experimentModel.experimentOutputs
+            if output.type in (DataType.URI, DataType.STDOUT, DataType.STDERR)]
+        inputDataProducts = [
+            self.request.airavata_client.getDataProduct(self.authz_token,
+                                                        inp.value)
+            for inp in experimentModel.experimentInputs
+            if inp.type in (DataType.URI, DataType.STDOUT, DataType.STDERR)]
+        appInterfaceId = experimentModel.executionId
+        applicationInterface = self.request.airavata_client\
+            .getApplicationInterface(self.authz_token, appInterfaceId)
+        appModuleId = applicationInterface.applicationModules[0]
+        applicationModule = self.request.airavata_client\
+            .getApplicationModule(self.authz_token, appModuleId)
+        compute_resource_id = None
+        user_conf = experimentModel.userConfigurationData
+        if user_conf and user_conf.computationalResourceScheduling:
+            comp_res_sched = user_conf.computationalResourceScheduling
+            compute_resource_id = comp_res_sched.resourceHostId
+        compute_resource = self.request.airavata_client.getComputeResource(
+            self.authz_token, compute_resource_id)\
+            if compute_resource_id else None
+        project = self.request.airavata_client.getProject(
+            self.authz_token, experimentModel.projectId)
+        full_experiment = serializers.FullExperiment(
+            experimentModel,
+            project=project,
+            outputDataProducts=outputDataProducts,
+            inputDataProducts=inputDataProducts,
+            applicationModule=applicationModule,
+            computeResource=compute_resource)
+        return full_experiment
+
+
 class ApplicationModuleViewSet(APIBackedViewSet):
     serializer_class = serializers.ApplicationModuleSerializer
     lookup_field = 'app_module_id'
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 9159b92..997759b 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
@@ -15,20 +15,23 @@
                             <tbody>
                                 <tr>
                                     <th scope="row">Name</th>
-                                    <td><span :title="localExperiment.experimentId">{{ localExperiment.experimentName }}</span></td>
+                                    <td><span :title="experiment.experimentId">{{ experiment.experimentName }}</span></td>
                                 </tr>
                                 <tr>
                                     <th scope="row">Description</th>
-                                    <td>{{ localExperiment.description }}</td>
+                                    <td>{{ experiment.description }}</td>
                                 </tr>
                                 <tr>
                                     <th scope="row">Project</th>
-                                    <td>{{ project && project.name || '' }}</td>
+                                    <td>{{ fullExperiment.projectName }}</td>
                                 </tr>
                                 <tr>
-                                    <!-- TODO -->
                                     <th scope="row">Outputs</th>
-                                    <td></td>
+                                    <td>
+                                        <template v-for="output in fullExperiment.outputDataProducts">
+                                            {{ output.filename }}
+                                        </template>
+                                    </td>
                                 </tr>
                                 <!-- Going to leave this out for now -->
                                 <!-- <tr>
@@ -37,56 +40,59 @@
                                 </tr> -->
                                 <tr>
                                     <th scope="row">Owner</th>
-                                    <td>{{ localExperiment.userName }}</td>
+                                    <td>{{ experiment.userName }}</td>
                                 </tr>
                                 <tr>
-                                    <!-- TODO -->
                                     <th scope="row">Application</th>
-                                    <td></td>
+                                    <td>{{ fullExperiment.applicationName }}</td>
                                 </tr>
                                 <tr>
-                                    <!-- TODO -->
                                     <th scope="row">Compute Resource</th>
-                                    <td></td>
+                                    <td>{{ fullExperiment.computeHostName }}</td>
                                 </tr>
                                 <tr>
                                     <th scope="row">Experiment Status</th>
-                                    <td>{{ experimentStatus.stateName }}</td>
+                                    <td>{{ fullExperiment.experimentStatusName }}</td>
                                 </tr>
-                                <tr>
+                                <!--  TODO: leave this out for now -->
+                                <!-- <tr>
                                     <th scope="row">Notification List</th>
-                                    <td>{{ localExperiment.emailAddresses
-                                            ? localExperiment.emailAddresses.join(", ")
+                                    <td>{{ fullExperiment.experiment.emailAddresses
+                                            ? fullExperiment.experiment.emailAddresses.join(", ")
                                             : '' }}</td>
-                                </tr>
+                                </tr> -->
                                 <tr>
                                     <th scope="row">Creation Time</th>
-                                    <td><span :title="localExperiment.creationTime.toString()">{{ creationTime }}</span></td>
+                                    <td><span :title="experiment.creationTime.toString()">{{ creationTime }}</span></td>
                                 </tr>
                                 <tr>
                                     <th scope="row">Last Modified Time</th>
-                                    <td><span :title="experimentStatus.timeOfStateChange.toString()">{{ lastModifiedTime }}</span></td>
+                                    <td><span :title="fullExperiment.experimentStatus.timeOfStateChange.toString()">{{ lastModifiedTime }}</span></td>
                                 </tr>
                                 <tr>
                                     <th scope="row">Wall Time Limit</th>
-                                    <td>{{ localExperiment.userConfigurationData.computationalResourceScheduling.wallTimeLimit }} minutes</td>
+                                    <td>{{ experiment.userConfigurationData.computationalResourceScheduling.wallTimeLimit }} minutes</td>
                                 </tr>
                                 <tr>
                                     <th scope="row">CPU Count</th>
-                                    <td>{{ localExperiment.userConfigurationData.computationalResourceScheduling.totalCPUCount }}</td>
+                                    <td>{{ experiment.userConfigurationData.computationalResourceScheduling.totalCPUCount }}</td>
                                 </tr>
                                 <tr>
                                     <th scope="row">Node Count</th>
-                                    <td>{{ localExperiment.userConfigurationData.computationalResourceScheduling.nodeCount }}</td>
+                                    <td>{{ experiment.userConfigurationData.computationalResourceScheduling.nodeCount }}</td>
                                 </tr>
                                 <tr>
                                     <th scope="row">Queue</th>
-                                    <td>{{ localExperiment.userConfigurationData.computationalResourceScheduling.queueName }}</td>
+                                    <td>{{ experiment.userConfigurationData.computationalResourceScheduling.queueName }}</td>
                                 </tr>
                                 <tr>
                                     <!-- TODO -->
                                     <th scope="row">Inputs</th>
-                                    <td></td>
+                                    <td>
+                                        <template v-for="input in fullExperiment.inputDataProducts">
+                                            {{ input.filename }}
+                                        </template>
+                                    </td>
                                 </tr>
                                 <tr>
                                     <!-- TODO -->
@@ -111,50 +117,33 @@ import moment from 'moment';
 export default {
     name: 'experiment-summary',
     props: {
-        experiment: {
-            type: models.Experiment,
+        fullExperiment: {
+            type: models.FullExperiment,
             required: true
         },
     },
     data () {
         return {
-            localExperiment: this.experiment.clone(),
-            project: null,
+            localFullExperiment: this.fullExperiment.clone(),
         }
     },
     components: {
     },
     computed: {
         creationTime: function() {
-            return moment(this.localExperiment.creationTime).fromNow();
-        },
-        experimentStatus: function() {
-            return this.localExperiment.experimentStatus[0];
+            return moment(this.localFullExperiment.experiment.creationTime).fromNow();
         },
         lastModifiedTime: function() {
-            return moment(this.experimentStatus.timeOfStateChange).fromNow();
+            return moment(this.localFullExperiment.experimentStatus.timeOfStateChange).fromNow();
+        },
+        experiment: function() {
+            return this.localFullExperiment.experiment;
         }
     },
     methods: {
-        loadProject: function() {
-            services.ProjectService.get(this.experiment.projectId)
-                .then(proj => this.project = proj);
-        },
-        loadApplication: function() {
-
-        },
-        loadOutputs: function() {
-
-        },
-        loadComputeHost: function() {
-
-        },
     },
     watch: {
     },
-    mounted: function() {
-        this.loadProject();
-    }
 }
 </script>
 
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/ViewExperimentContainer.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/ViewExperimentContainer.vue
index 1bf3482..bebfffa 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/ViewExperimentContainer.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/containers/ViewExperimentContainer.vue
@@ -1,5 +1,5 @@
 <template>
-    <experiment-summary v-if="experiment" :experiment="experiment">
+    <experiment-summary v-if="fullExperiment" :fullExperiment="fullExperiment">
     </experiment-summary>
 </template>
 
@@ -11,13 +11,13 @@ import ExperimentSummary from '../components/experiment/ExperimentSummary.vue'
 export default {
     name: 'view-experiment-container',
     props: {
-        initialExperimentData: {
+        initialFullExperimentData: {
             required: true
         },
     },
     data () {
         return {
-            experiment: null,
+            fullExperiment: null,
         }
     },
     components: {
@@ -28,8 +28,8 @@ export default {
     computed: {
     },
     beforeMount: function () {
-        services.ExperimentService.get(this.initialExperimentData.experimentId, this.initialExperimentData)
-            .then(exp => this.experiment = exp);
+        services.FullExperimentService.get(this.initialFullExperimentData.experimentId, this.initialFullExperimentData)
+            .then(exp => this.fullExperiment = exp);
     }
 }
 </script>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-view-experiment.js b/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-view-experiment.js
index 6517ba8..a2c8c8b 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-view-experiment.js
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/entry-view-experiment.js
@@ -10,17 +10,16 @@ Vue.use(BootstrapVue);
 
 new Vue({
   el: '#view-experiment',
-  template: '<view-experiment-container :initial-experiment-data="experiment"></view-experiment-container>',
+  template: '<view-experiment-container :initial-full-experiment-data="fullExperimentData"></view-experiment-container>',
   data () {
       return {
-          experiment: null,
+          fullExperimentData: null,
       }
   },
   components: {
       ViewExperimentContainer,
   },
   beforeMount: function () {
-      console.log(this.$el.dataset.experimentData);
-      this.experiment = JSON.parse(this.$el.dataset.experimentData);
+      this.fullExperimentData = JSON.parse(this.$el.dataset.fullExperimentData);
   }
 })
diff --git a/django_airavata/apps/workspace/templates/django_airavata_workspace/view_experiment.html b/django_airavata/apps/workspace/templates/django_airavata_workspace/view_experiment.html
index e09bf11..0f12b5e 100644
--- a/django_airavata/apps/workspace/templates/django_airavata_workspace/view_experiment.html
+++ b/django_airavata/apps/workspace/templates/django_airavata_workspace/view_experiment.html
@@ -9,7 +9,7 @@
 
 {% block content %}
 
-<div id="view-experiment" data-experiment-data="{{ experiment_data }}"></div>
+<div id="view-experiment" data-full-experiment-data="{{ full_experiment_data }}"></div>
 
 {% endblock content %}
 
diff --git a/django_airavata/apps/workspace/views.py b/django_airavata/apps/workspace/views.py
index 50c755d..9f78172 100644
--- a/django_airavata/apps/workspace/views.py
+++ b/django_airavata/apps/workspace/views.py
@@ -7,6 +7,7 @@ from django.contrib.auth.decorators import login_required
 from django.shortcuts import render, redirect
 
 from django_airavata.apps.api.views import ExperimentViewSet
+from django_airavata.apps.api.views import FullExperimentViewSet
 from django_airavata.apps.api.views import ProjectViewSet
 
 logger = logging.getLogger(__name__)
@@ -41,14 +42,15 @@ def create_experiment(request, app_module_id):
         'app_module_id': app_module_id
     })
 
+
 @login_required
 def view_experiment(request, experiment_id):
     request.active_nav_item = 'experiments'
 
-    response = ExperimentViewSet.as_view(
+    response = FullExperimentViewSet.as_view(
         {'get': 'retrieve'})(request, experiment_id=experiment_id)
-    experiment_json = JSONRenderer().render(response.data)
+    full_experiment_json = JSONRenderer().render(response.data)
 
     return render(request, 'django_airavata_workspace/view_experiment.html', {
-        'experiment_data': experiment_json
+        'full_experiment_data': full_experiment_json
     })

-- 
To stop receiving notification emails like this one, please contact
machristie@apache.org.