You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2019/08/20 14:52:11 UTC

[airavata-django-portal] branch master updated (b64307b -> 3e393a0)

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 b64307b  gateways19 tutorial: setting up local django
     new aba5367  Parameterized notebook output viewer
     new fd95395  AIRAVATA-2934 Updated docs on adding django app
     new 5d05b9d  AIRAVATA-2934 custom django app docs
     new 3e393a0  AIRAVATA-3187 HTML output view provider display

The 4 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/output_views.py           | 83 +++++++++++++++++++++-
 django_airavata/apps/api/urls.py                   |  4 ++
 django_airavata/apps/api/views.py                  | 22 ++++++
 .../js/components/experiment/ExperimentSummary.vue |  1 +
 .../output-displays/HtmlOutputDisplay.vue          | 45 ++++++++++++
 .../output-displays/NotebookOutputDisplay.vue      | 53 ++++++++++++++
 .../output-displays/OutputDisplayContainer.vue     | 16 ++++-
 docs/dev/custom_django_app.md                      | 70 ++++++++++++++++++
 docs/dev/new_django_app.md                         | 68 ++++++++++--------
 mkdocs.yml                                         |  1 +
 requirements.txt                                   |  3 +
 setup.py                                           |  4 +-
 12 files changed, 336 insertions(+), 34 deletions(-)
 create mode 100644 django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/HtmlOutputDisplay.vue
 create mode 100644 django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/NotebookOutputDisplay.vue
 create mode 100644 docs/dev/custom_django_app.md


[airavata-django-portal] 02/04: AIRAVATA-2934 Updated docs on adding django app

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 fd95395e3313f7c6ad4842fac5f64c7576264ca4
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Wed Jul 10 10:36:58 2019 -0400

    AIRAVATA-2934 Updated docs on adding django app
---
 docs/dev/new_django_app.md | 68 ++++++++++++++++++++++++++--------------------
 1 file changed, 39 insertions(+), 29 deletions(-)

diff --git a/docs/dev/new_django_app.md b/docs/dev/new_django_app.md
index 21c2a89..e8b289c 100644
--- a/docs/dev/new_django_app.md
+++ b/docs/dev/new_django_app.md
@@ -38,6 +38,15 @@ class MyAppConfig(AiravataAppConfig):
     app_description = """
         My app for doing stuff in the Airavata Django Portal.
     """
+    nav = [
+        {
+            'label': 'Dashboard',
+            'icon': 'fa fa-tachometer-alt',
+            'url': 'django_airavata_myapp:dashboard',
+            'active_prefixes': ['dashboard']
+        },
+        # ... additional entries as needed
+    ]
 ```
 
 Some of these are self explanatory, but here are some details on each of these
@@ -55,6 +64,19 @@ properties:
 - _fa_icon_class_ - a FontAwesome icon class. See
   [the list of available icons for v. 4.7](https://fontawesome.com/v4.7.0/icons/).
 - _app_description_ - description of this app
+- _nav_ - **optional** provide navigation into sections of the app. The _nav_ is
+  optional but is necessary to provide users with a link from the left hand side
+  navigation bar to a url in your app.
+  - _label_ - textual label, displayed on hover in the side navigation bar
+  - _icon_ - FontAwesome icon, see _fa_icon_class_ above
+  - _url_ - named or namespaced url
+  - _active_prefixes_ - list of strings that come after this app's base url for
+    all urls that are considered "active" for this nav item. This is used to
+    highlight the currently active nav item in the left side navigation bar. For
+    example, let's say the app's base url is "/myapp" and urls belonging to the
+    "projects" nav item are of the form "/myapp/projects/`<project_id>`" and
+    "/myapp/new-project". Then you would set _active_prefixes_ to `["projects",
+    "new-project"].
 
 ### Add AppConfig to INSTALLED_APPS
 
@@ -163,27 +185,6 @@ this file assuming that it will load webpack bundles generated by vue-cli:
 {% render_bundle bundle_name 'css' 'MYAPP' %}
 {% endblock %}
 
-{% block nav-items %}
-
-        {% comment %}Define the left side navigation for drilling into sub pages of your app{% endcomment %}
-        <a href="{% url 'django_airavata_myapp:function1' %}"
-            class="c-nav__item {% if request.active_nav_item == 'function1' %}is-active{% endif %}"
-            data-toggle=tooltip data-placement=right title="Function #1">
-            <i class="fa fa-bolt"></i> <span class=sr-only>Function #1</span>
-        </a>
-        <a href="{% url 'django_airavata_myapp:function2' %}"
-            class="c-nav__item {% if request.active_nav_item == 'function2' %}is-active{% endif %}"
-            data-toggle=tooltip data-placement=right title="Function #2">
-            <i class="fa fa-bolt"></i> <span class=sr-only>Function #2</span>
-        </a>
-        <a href="{% url 'django_airavata_myapp:function3' %}"
-            class="c-nav__item {% if request.active_nav_item == 'function3' %}is-active{% endif %}"
-            data-toggle=tooltip data-placement=right title="Function #3">
-            <i class="fa fa-bolt"></i> <span class=sr-only>Function #3</span>
-        </a>
-
-{% endblock %}
-
 {% block content %}
 <div id="{{ bundle_name }}"/>
 {% endblock %}
@@ -200,14 +201,19 @@ this file assuming that it will load webpack bundles generated by vue-cli:
 Now, create a `home.html` template:
 
 ```html
-{% extends './base.html' %} {% load static %} {% block css %} {% comment %}This
-isn't a Vue.js app, so just turn off loading CSS.{% endcomment %} {% endblock %}
+{% extends './base.html' %}
+{% load static %}
+{% block css %}
+{% comment %}This isn't a Vue.js app, so just turn off loading CSS.{% endcomment %}
+{% endblock %}
 {% block content %}
 
 <h1>Hello World!</h1>
 
-{% endblock content %} {% block scripts %} {% comment %}This isn't a Vue.js app,
-so just turn off loading JavaScript.{% endcomment %} {% endblock %}
+{% endblock content %}
+{% block scripts %}
+{% comment %}This isn't a Vue.js app, so just turn off loading JavaScript.{% endcomment %}
+{% endblock %}
 ```
 
 Now if you log into the Django portal you should see "My App" in the menu at the
@@ -282,7 +288,9 @@ Now add a `vue.config.js` file too:
 ```javascript
 const BundleTracker = require("webpack-bundle-tracker");
 const path = require("path");
-const staticDir = process.env.STATIC_ROOT ? process.env.STATIC_ROOT : "./static/";
+const staticDir = process.env.STATIC_ROOT
+  ? process.env.STATIC_ROOT
+  : "./static/";
 
 module.exports = {
   publicPath:
@@ -364,8 +372,8 @@ module.exports = {
 ```
 
 You'll customize _pages_ by modifying and/or adding additional entry points and
-you'll need to modify _publicPath_ and _outputDir_ and the BundleTracker config to
-correspond to your folder structure.
+you'll need to modify _publicPath_ and _outputDir_ and the BundleTracker config
+to correspond to your folder structure.
 
 Now create a static folder for holding javascript code. For this example we
 would create `static/django_airavata_myapp/js`. In this folder you can put the
@@ -380,7 +388,9 @@ For a complete example, see the _workspace_ app.
 
 ## build_js.sh build script
 
-In the root of the project is a master build script, `build_js.sh`, that generates a production build of all of the JS frontend code in the project. Add a line in there for your Django app, like so:
+In the root of the project is a master build script, `build_js.sh`, that
+generates a production build of all of the JS frontend code in the project. Add
+a line in there for your Django app, like so:
 
 ```bash
 ...


[airavata-django-portal] 01/04: Parameterized notebook output viewer

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 aba53675fd368472c9acffb757e5a1633913f5e9
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Mon Aug 19 15:45:15 2019 -0400

    Parameterized notebook output viewer
---
 django_airavata/apps/api/output_views.py           | 79 +++++++++++++++++++++-
 django_airavata/apps/api/urls.py                   |  2 +
 django_airavata/apps/api/views.py                  | 11 +++
 .../js/components/experiment/ExperimentSummary.vue |  1 +
 .../output-displays/NotebookOutputDisplay.vue      | 53 +++++++++++++++
 .../output-displays/OutputDisplayContainer.vue     | 12 +++-
 requirements.txt                                   |  3 +
 setup.py                                           |  4 +-
 8 files changed, 162 insertions(+), 3 deletions(-)

diff --git a/django_airavata/apps/api/output_views.py b/django_airavata/apps/api/output_views.py
index ea8fc70..87452d2 100644
--- a/django_airavata/apps/api/output_views.py
+++ b/django_airavata/apps/api/output_views.py
@@ -1,7 +1,11 @@
 import json
 import logging
+import os
 
+import nbformat
+import papermill as pm
 from django.conf import settings
+from nbconvert import HTMLExporter
 
 from airavata.model.application.io.ttypes import DataType
 
@@ -9,6 +13,8 @@ from . import data_products_helper
 
 logger = logging.getLogger(__name__)
 
+BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+
 
 class DefaultViewProvider:
     display_type = 'default'
@@ -20,6 +26,39 @@ class DefaultViewProvider:
         }
 
 
+class ParameterizedNotebookViewProvider:
+    display_type = 'notebook'
+    name = "Example Parameterized Notebook View"
+    # fixture_output_file = os.path.join(BASE_DIR, "data", "Gaussian.log")
+
+    def generate_data(self,
+                      experiment_output,
+                      experiment,
+                      output_file=None,
+                      output_dir=None):
+        # use papermill to generate the output notebook
+        output_file_path = os.path.realpath(output_file.name)
+        pm.execute_notebook(
+            os.path.join(BASE_DIR, "path", "to", "notebook.ipynb"),
+            # TODO: use TemporaryFile instead
+            '/tmp/output.ipynb',
+            parameters=dict(
+                experiment_output={},
+                experiment={},
+                output_file=output_file_path,
+                output_dir=output_dir
+            )
+        )
+        # TODO: convert the output notebook into html format
+        output_notebook = nbformat.read('/tmp/output.ipynb', as_version=4)
+        html_exporter = HTMLExporter()
+        (body, resources) = html_exporter.from_notebook_node(output_notebook)
+        # TODO: return the HTML output as the output key
+        return {
+            'output': body
+        }
+
+
 DEFAULT_VIEW_PROVIDERS = {
     'default': DefaultViewProvider()
 }
@@ -47,17 +86,27 @@ def get_output_views(request, experiment, application_interface=None):
                     'provider-id': output_view_provider_id,
                     'display-type': output_view_provider.display_type,
                     'name': getattr(output_view_provider, 'name',
-                                    output_view_provider_id)
+                                    output_view_provider_id),
                 }
                 if getattr(output_view_provider, 'immediate', False):
                     # Immediately call generate_data function
                     data = _generate_data(
                         request, output_view_provider, output, experiment)
                     view_config['data'] = data
+                else:
+                    view_config['data'] = {}
                 output_views[output.name].append(view_config)
     return output_views
 
 
+def _get_output_view_provider(output_view_provider_id):
+
+    if output_view_provider_id in DEFAULT_VIEW_PROVIDERS:
+        return DEFAULT_VIEW_PROVIDERS[output_view_provider_id]
+    elif output_view_provider_id in settings.OUTPUT_VIEW_PROVIDERS:
+        return settings.OUTPUT_VIEW_PROVIDERS[output_view_provider_id]
+
+
 def _get_output_view_providers(experiment_output, application_interface):
     output_view_providers = []
     logger.debug("experiment_output={}".format(experiment_output))
@@ -89,6 +138,7 @@ def _get_application_output_view_providers(application_interface, output_name):
                   for o in application_interface.applicationOutputs
                   if o.name == output_name]
     if len(app_output) == 1:
+        logger.debug("{}: {}".format(output_name, app_output))
         app_output = app_output[0]
     else:
         return []
@@ -104,6 +154,26 @@ def _get_application_output_view_providers(application_interface, output_name):
     return []
 
 
+def generate_data(request,
+                  output_view_provider_id,
+                  experiment_output_name,
+                  experiment_id):
+    output_view_provider = _get_output_view_provider(output_view_provider_id)
+    # TODO if output_view_provider is None, return 404
+    experiment = request.airavata_client.getExperiment(
+        request.authz_token, experiment_id)
+    experiment_output = [o
+                         for o in experiment.experimentOutputs
+                         if o.name == experiment_output_name]
+    # TODO: handle experiment_output not found by name
+    experiment_output = experiment_output[0]
+    # TODO: add experiment_output_dir
+    return _generate_data(request,
+                          output_view_provider,
+                          experiment_output,
+                          experiment)
+
+
 def _generate_data(request,
                    output_view_provider,
                    experiment_output,
@@ -111,6 +181,9 @@ def _generate_data(request,
     # TODO: handle URI_COLLECTION also
     logger.debug("getting data product for {}".format(experiment_output.value))
     output_file = None
+    fixture_output_file = getattr(output_view_provider,
+                                  'fixture_output_file',
+                                  None)
     if (experiment_output.value and
         experiment_output.type in (DataType.URI,
                                    DataType.STDOUT,
@@ -120,6 +193,10 @@ def _generate_data(request,
             request.authz_token, experiment_output.value)
         if data_products_helper.exists(request, data_product):
             output_file = data_products_helper.open(request, data_product)
+        elif fixture_output_file is not None:
+            output_file = open(fixture_output_file)
+    # TODO: change interface to provide output_file as a path
+    # TODO: convert experiment and experiment_output to dict/JSON
     data = output_view_provider.generate_data(
         experiment_output, experiment, output_file=output_file)
     return data
diff --git a/django_airavata/apps/api/urls.py b/django_airavata/apps/api/urls.py
index 9f21bda..951ad43 100644
--- a/django_airavata/apps/api/urls.py
+++ b/django_airavata/apps/api/urls.py
@@ -93,6 +93,8 @@ urlpatterns = [
     url(r'^api-status-check/',
         views.APIServerStatusCheckView.as_view(),
         name='api-status-check'),
+    url(r'^notebook-output',
+        views.notebook_output_view, name="notebook-output")
 ]
 
 if logger.isEnabledFor(logging.DEBUG):
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index a693253..a8e559e 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -1733,3 +1733,14 @@ class APIServerStatusCheckView(APIView):
                 "apiServerUp": False
             }
         return Response(data)
+
+
+def notebook_output_view(request):
+    provider_id = request.GET['provider-id']
+    experiment_id = request.GET['experiment-id']
+    experiment_output_name = request.GET['experiment-output-name']
+    data = output_views.generate_data(request,
+                                      provider_id,
+                                      experiment_output_name,
+                                      experiment_id)
+    return HttpResponse(data['output'])
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 68f5106..6c216e5 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
@@ -66,6 +66,7 @@
             :experiment-output="output"
             :data-products="outputDataProducts[output.name]"
             :output-views="localFullExperiment.outputViews[output.name]"
+            :experiment-id="experiment.experimentId"
           />
         </div>
       </div>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/NotebookOutputDisplay.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/NotebookOutputDisplay.vue
new file mode 100644
index 0000000..ce23543
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/NotebookOutputDisplay.vue
@@ -0,0 +1,53 @@
+<template>
+  <iframe :src="url"></iframe>
+</template>
+
+<script>
+import { models } from "django-airavata-api";
+export default {
+  name: "notebook-output-display",
+  props: {
+    experimentOutput: {
+      type: models.OutputDataObjectType,
+      required: true
+    },
+    dataProducts: {
+      type: Array,
+      required: true
+    },
+    experimentId: {
+      type: String,
+      required: true
+    },
+    providerId: {
+      type: String,
+      required: true
+    }
+  },
+  data() {
+    return {
+      rawOutput: null
+    };
+  },
+  computed: {
+    url() {
+      return (
+        "/api/notebook-output?" +
+        "experiment-id=" +
+        encodeURIComponent(this.experimentId) +
+        "&experiment-output-name=" +
+        encodeURIComponent(this.experimentOutput.name) +
+        "&provider-id=" + encodeURIComponent(this.providerId)
+      );
+    }
+  },
+};
+</script>
+
+<style scoped>
+iframe {
+  width: 100%;
+  height: 400px;
+  border: none;
+}
+</style>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/OutputDisplayContainer.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/OutputDisplayContainer.vue
index 57157ae..4bac1f1 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/OutputDisplayContainer.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/OutputDisplayContainer.vue
@@ -22,6 +22,8 @@
       :is="outputDisplayComponentName"
       :experiment-output="experimentOutput"
       :data-products="dataProducts"
+      :experiment-id="experimentId"
+      :provider-id="currentView['provider-id']"
       :data="outputViewData"
     />
   </b-card>
@@ -32,6 +34,7 @@ import { models } from "django-airavata-api";
 import { components } from "django-airavata-common-ui";
 import DefaultOutputDisplay from "./DefaultOutputDisplay";
 import LinkDisplay from "./LinkDisplay";
+import NotebookOutputDisplay from "./NotebookOutputDisplay";
 
 export default {
   name: "output-viewer-container",
@@ -48,12 +51,17 @@ export default {
       type: Array,
       required: false,
       default: null
+    },
+    experimentId: {
+      type: String,
+      required: true
     }
   },
   components: {
     "data-product-viewer": components.DataProductViewer,
     DefaultOutputDisplay,
-    LinkDisplay
+    LinkDisplay,
+    NotebookOutputDisplay
   },
   data() {
     return {
@@ -69,6 +77,8 @@ export default {
         return "default-output-display";
       } else if (this.currentView["display-type"] === "link") {
         return "link-display";
+      } else if (this.currentView["display-type"] === "notebook") {
+        return "notebook-output-display";
       } else {
         return null;
       }
diff --git a/requirements.txt b/requirements.txt
index b9e4158..e9a853d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -11,4 +11,7 @@ mysqlclient==1.4.2.post1
 wagtail==2.0
 wagtailfontawesome==1.1.3
 
+jupyter==1.0.0
+papermill==1.0.1
+
 -e "."
diff --git a/setup.py b/setup.py
index 1760221..815d5d5 100644
--- a/setup.py
+++ b/setup.py
@@ -28,7 +28,9 @@ setup(
             'thrift',
             'thrift_connector',
             'wagtail',
-            'wagtailfontawesome'
+            'wagtailfontawesome',
+            'jupyter',
+            'papermill'
     ],
     extras_require={
         'dev': [


[airavata-django-portal] 03/04: AIRAVATA-2934 custom django app docs

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 5d05b9d69a66022e0abea971150c1e577470cd1e
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Wed Jul 10 10:37:11 2019 -0400

    AIRAVATA-2934 custom django app docs
---
 docs/dev/custom_django_app.md | 70 +++++++++++++++++++++++++++++++++++++++++++
 mkdocs.yml                    |  1 +
 2 files changed, 71 insertions(+)

diff --git a/docs/dev/custom_django_app.md b/docs/dev/custom_django_app.md
new file mode 100644
index 0000000..c53e0cc
--- /dev/null
+++ b/docs/dev/custom_django_app.md
@@ -0,0 +1,70 @@
+# Custom Django Apps
+
+The functionality of the Airavata Django Portal can be extended by adding custom
+Django apps that can provide completely custom user interfaces while leveraging
+the Airavata Django Portal REST API. This page documents how to get started with
+creating a custom Django app that works with the Airavata Django Portal and how
+to make use of functionality provided.
+
+## Getting Started
+
+Creating a custom Django app requires creating an installable Python package
+with metadata describing that it is a Django app meant to be automatically
+installed into the Airavata Django Portal when it is loaded into the virtual
+environment.
+
+We'll go through the minimal setup code needed. This will follow along with the
+code in the [https://github.com/machristie/test-dynamic-djangoapp]() repo, which
+represents a minimal custom Django app for the Django Portal.
+
+1.  Install the Airavata Django Portal. See the
+    [https://github.com/apache/airavata-django-portal/blob/master/README.md](README)
+    for instructions.
+2.  With the Django Portal virtual environment activated, navigate to a separate
+    directory outside the airavata-django-portal, where you'll create your
+    custom django app. In that directory, run
+    `django-admin startapp my_custom_app`, but instead of _my_custom_app_
+    specify the module name you want to use. For example, let's say your
+    directory is called `custom-django-app` and you want to call the module name
+    `custom_app`. Then you would run
+
+        cd ../custom-django-app
+        django-admin startapp custom_app
+
+    This will result in the following files:
+
+        custom-django-app
+        custom-django-app/custom_app
+        custom-django-app/custom_app/migrations
+        custom-django-app/custom_app/migrations/__init__.py
+        custom-django-app/custom_app/models.py
+        custom-django-app/custom_app/__init__.py
+        custom-django-app/custom_app/apps.py
+        custom-django-app/custom_app/admin.py
+        custom-django-app/custom_app/tests.py
+        custom-django-app/custom_app/views.py
+
+3.  Create a `setup.py` file in your custom apps root directory. In the example
+    above that would be in the `custom-django-app/` directory.
+
+        import setuptools
+
+        setuptools.setup(
+            name="my-custom-django-app",
+            version="0.0.1",
+            description="... description ...",
+            packages=setuptools.find_packages(),
+            install_requires=[
+                'django>=1.11.16'
+            ],
+            entry_points="""
+        [airavata.djangoapp]
+        custom_app = custom_app.apps:CustomAppConfig
+        """,
+        )
+
+    Change the `name` and `description` as appropriate. The necessary metadata
+    for letting the Airavata Django Portal know that this Python package is a
+    custom Django app is specified in the `[airavata.djangoapp]` section.
+
+4.  To be completed ...
diff --git a/mkdocs.yml b/mkdocs.yml
index 6225661..7029dfb 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -8,6 +8,7 @@ nav:
     - Using the integrated CMS: cms.md
   - Developer Guide:
     - Adding a Django App: dev/new_django_app.md
+    - Adding a Custom Django App: dev/custom_django_app.md
     - Developing the Frontend: dev/developing_frontend.md
     - Developing the Backend: dev/developing_backend.md
   - Tutorials:


[airavata-django-portal] 04/04: AIRAVATA-3187 HTML output view provider display

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 3e393a0f89563f712904edf4317f305777c9e7f4
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Tue Aug 20 10:51:38 2019 -0400

    AIRAVATA-3187 HTML output view provider display
---
 django_airavata/apps/api/output_views.py           |  6 +--
 django_airavata/apps/api/urls.py                   |  4 +-
 django_airavata/apps/api/views.py                  | 11 ++++++
 .../output-displays/HtmlOutputDisplay.vue          | 45 ++++++++++++++++++++++
 .../output-displays/OutputDisplayContainer.vue     |  4 ++
 5 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/django_airavata/apps/api/output_views.py b/django_airavata/apps/api/output_views.py
index 87452d2..953d975 100644
--- a/django_airavata/apps/api/output_views.py
+++ b/django_airavata/apps/api/output_views.py
@@ -121,8 +121,6 @@ def _get_output_view_providers(experiment_output, application_interface):
             logger.exception(
                 "Failed to parse metadata for output {}".format(
                     experiment_output.name))
-    if 'default' not in output_view_providers:
-        output_view_providers.insert(0, 'default')
     # Add in any output view providers defined on the application interface
     if application_interface is not None:
         app_output_view_providers = _get_application_output_view_providers(
@@ -130,6 +128,8 @@ def _get_output_view_providers(experiment_output, application_interface):
         for view_provider in app_output_view_providers:
             if view_provider not in output_view_providers:
                 output_view_providers.append(view_provider)
+    if 'default' not in output_view_providers:
+        output_view_providers.insert(0, 'default')
     return output_view_providers
 
 
@@ -193,7 +193,7 @@ def _generate_data(request,
             request.authz_token, experiment_output.value)
         if data_products_helper.exists(request, data_product):
             output_file = data_products_helper.open(request, data_product)
-        elif fixture_output_file is not None:
+        elif settings.DEBUG and fixture_output_file is not None:
             output_file = open(fixture_output_file)
     # TODO: change interface to provide output_file as a path
     # TODO: convert experiment and experiment_output to dict/JSON
diff --git a/django_airavata/apps/api/urls.py b/django_airavata/apps/api/urls.py
index 951ad43..9f59eb1 100644
--- a/django_airavata/apps/api/urls.py
+++ b/django_airavata/apps/api/urls.py
@@ -94,7 +94,9 @@ urlpatterns = [
         views.APIServerStatusCheckView.as_view(),
         name='api-status-check'),
     url(r'^notebook-output',
-        views.notebook_output_view, name="notebook-output")
+        views.notebook_output_view, name="notebook-output"),
+    url(r'^html-output',
+        views.html_output_view, name="html-output"),
 ]
 
 if logger.isEnabledFor(logging.DEBUG):
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index a8e559e..068d43b 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -1744,3 +1744,14 @@ def notebook_output_view(request):
                                       experiment_output_name,
                                       experiment_id)
     return HttpResponse(data['output'])
+
+
+def html_output_view(request):
+    provider_id = request.GET['provider-id']
+    experiment_id = request.GET['experiment-id']
+    experiment_output_name = request.GET['experiment-output-name']
+    data = output_views.generate_data(request,
+                                      provider_id,
+                                      experiment_output_name,
+                                      experiment_id)
+    return JsonResponse(data)
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/HtmlOutputDisplay.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/HtmlOutputDisplay.vue
new file mode 100644
index 0000000..1d6b76f
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/HtmlOutputDisplay.vue
@@ -0,0 +1,45 @@
+<template>
+  <div v-html="rawOutput"/>
+</template>
+
+<script>
+import { models, utils } from "django-airavata-api";
+export default {
+  name: "html-output-display",
+  props: {
+    experimentOutput: {
+      type: models.OutputDataObjectType,
+      required: true
+    },
+    dataProducts: {
+      type: Array,
+      required: true
+    },
+    experimentId: {
+      type: String,
+      required: true
+    },
+    providerId: {
+      type: String,
+      required: true
+    }
+  },
+  data() {
+    return {
+      rawOutput: null
+    };
+  },
+  created() {
+    utils.FetchUtils.get("/api/html-output", {
+      "experiment-id": this.experimentId,
+      "experiment-output-name": this.experimentOutput.name,
+      "provider-id": this.providerId
+    }).then(data => {
+      this.rawOutput = data.output
+    })
+  }
+};
+</script>
+
+<style scoped>
+</style>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/OutputDisplayContainer.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/OutputDisplayContainer.vue
index 4bac1f1..40387ab 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/OutputDisplayContainer.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/OutputDisplayContainer.vue
@@ -33,6 +33,7 @@
 import { models } from "django-airavata-api";
 import { components } from "django-airavata-common-ui";
 import DefaultOutputDisplay from "./DefaultOutputDisplay";
+import HtmlOutputDisplay from "./HtmlOutputDisplay";
 import LinkDisplay from "./LinkDisplay";
 import NotebookOutputDisplay from "./NotebookOutputDisplay";
 
@@ -60,6 +61,7 @@ export default {
   components: {
     "data-product-viewer": components.DataProductViewer,
     DefaultOutputDisplay,
+    HtmlOutputDisplay,
     LinkDisplay,
     NotebookOutputDisplay
   },
@@ -79,6 +81,8 @@ export default {
         return "link-display";
       } else if (this.currentView["display-type"] === "notebook") {
         return "notebook-output-display";
+      } else if (this.currentView["display-type"] === "html") {
+        return "html-output-display";
       } else {
         return null;
       }