You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2018/11/21 23:29:33 UTC

[airavata-django-portal] branch master updated (5e0538e -> 83a3c2e)

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 5e0538e  Check for missing, non-required fields when deserializing
     new ab419f5  Documentation on adding Django app
     new 83a3c2e  Parser app with WIP code to load parser and display image name

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


Summary of changes:
 .gitignore                                         |   2 +
 django_airavata/apps/api/serializers.py            |   5 +
 .../api/static/django_airavata_api/js/index.js     |   1 +
 .../static/django_airavata_api/js/models/IOType.js |   4 +
 .../static/django_airavata_api/js/models/Parser.js |  28 ++
 .../django_airavata_api/js/models/ParserInput.js   |  19 ++
 .../django_airavata_api/js/models/ParserOutput.js  |  19 ++
 .../django_airavata_api/js/service_config.js       |  16 +
 django_airavata/apps/api/urls.py                   |   1 +
 django_airavata/apps/api/views.py                  |  21 ++
 .../{static/common => apps/dataparsers}/.babelrc   |   0
 .../migrations => apps/dataparsers}/__init__.py    |   0
 .../apps/{workspace => dataparsers}/admin.py       |   0
 django_airavata/apps/dataparsers/apps.py           |  15 +
 .../dataparsers}/migrations/__init__.py            |   0
 .../apps/{admin => dataparsers}/models.py          |   1 -
 .../apps/{groups => dataparsers}/package.json      |  11 +-
 .../js/containers/ParserDetailsContainer.vue       |  43 +++
 .../js/entry-parser-details.js                     |  26 ++
 .../django_airavata_dataparsers/base.html          |  21 ++
 .../django_airavata_dataparsers/home.html          |  19 ++
 .../parser-details.html}                           |   6 +-
 .../apps/{workspace => dataparsers}/tests.py       |   0
 django_airavata/apps/dataparsers/urls.py           |  11 +
 django_airavata/apps/dataparsers/views.py          |  11 +
 .../apps/{groups => dataparsers}/webpack.config.js |  14 +-
 django_airavata/settings.py                        |   1 +
 django_airavata/urls.py                            |   1 +
 docs/dev/new_django_app.md                         | 353 +++++++++++++++++++++
 docs/index.md                                      |   8 +
 mkdocs.yml                                         |  12 +
 requirements-dev.txt                               |   1 +
 32 files changed, 655 insertions(+), 15 deletions(-)
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/models/IOType.js
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/models/Parser.js
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/models/ParserInput.js
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/models/ParserOutput.js
 copy django_airavata/{static/common => apps/dataparsers}/.babelrc (100%)
 copy django_airavata/{wagtailapps/base/migrations => apps/dataparsers}/__init__.py (100%)
 copy django_airavata/apps/{workspace => dataparsers}/admin.py (100%)
 create mode 100644 django_airavata/apps/dataparsers/apps.py
 copy django_airavata/{wagtailapps/base => apps/dataparsers}/migrations/__init__.py (100%)
 copy django_airavata/apps/{admin => dataparsers}/models.py (96%)
 copy django_airavata/apps/{groups => dataparsers}/package.json (81%)
 mode change 100755 => 100644
 create mode 100644 django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/containers/ParserDetailsContainer.vue
 create mode 100644 django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/entry-parser-details.js
 create mode 100644 django_airavata/apps/dataparsers/templates/django_airavata_dataparsers/base.html
 create mode 100644 django_airavata/apps/dataparsers/templates/django_airavata_dataparsers/home.html
 copy django_airavata/apps/{workspace/templates/django_airavata_workspace/dashboard.html => dataparsers/templates/django_airavata_dataparsers/parser-details.html} (56%)
 copy django_airavata/apps/{workspace => dataparsers}/tests.py (100%)
 create mode 100644 django_airavata/apps/dataparsers/urls.py
 create mode 100644 django_airavata/apps/dataparsers/views.py
 copy django_airavata/apps/{groups => dataparsers}/webpack.config.js (79%)
 mode change 100755 => 100644
 create mode 100644 docs/dev/new_django_app.md
 create mode 100644 docs/index.md
 create mode 100644 mkdocs.yml


[airavata-django-portal] 02/02: Parser app with WIP code to load parser and display image name

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 83a3c2e243d337bef823032faed4bdee7fb18263
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Wed Nov 21 18:27:57 2018 -0500

    Parser app with WIP code to load parser and display image name
---
 django_airavata/apps/api/serializers.py            |  5 ++
 .../api/static/django_airavata_api/js/index.js     |  1 +
 .../static/django_airavata_api/js/models/IOType.js |  4 +
 .../static/django_airavata_api/js/models/Parser.js | 28 +++++++
 .../django_airavata_api/js/models/ParserInput.js   | 19 +++++
 .../django_airavata_api/js/models/ParserOutput.js  | 19 +++++
 .../django_airavata_api/js/service_config.js       | 16 ++++
 django_airavata/apps/api/urls.py                   |  1 +
 django_airavata/apps/api/views.py                  | 21 +++++
 django_airavata/apps/dataparsers/.babelrc          |  5 ++
 django_airavata/apps/dataparsers/__init__.py       |  0
 django_airavata/apps/dataparsers/admin.py          |  2 +
 django_airavata/apps/dataparsers/apps.py           | 15 ++++
 .../apps/dataparsers/migrations/__init__.py        |  0
 django_airavata/apps/dataparsers/models.py         |  1 +
 django_airavata/apps/dataparsers/package.json      | 34 ++++++++
 .../js/containers/ParserDetailsContainer.vue       | 43 ++++++++++
 .../js/entry-parser-details.js                     | 26 ++++++
 .../django_airavata_dataparsers/base.html          | 21 +++++
 .../django_airavata_dataparsers/home.html          | 19 +++++
 .../parser-details.html                            | 19 +++++
 django_airavata/apps/dataparsers/tests.py          |  2 +
 django_airavata/apps/dataparsers/urls.py           | 11 +++
 django_airavata/apps/dataparsers/views.py          | 11 +++
 django_airavata/apps/dataparsers/webpack.config.js | 92 ++++++++++++++++++++++
 django_airavata/settings.py                        |  1 +
 django_airavata/urls.py                            |  1 +
 27 files changed, 417 insertions(+)

diff --git a/django_airavata/apps/api/serializers.py b/django_airavata/apps/api/serializers.py
index 90225c2..342d338 100644
--- a/django_airavata/apps/api/serializers.py
+++ b/django_airavata/apps/api/serializers.py
@@ -29,6 +29,7 @@ from airavata.model.appcatalog.gatewayprofile.ttypes import (
 from airavata.model.appcatalog.groupresourceprofile.ttypes import (
     GroupResourceProfile
 )
+from airavata.model.appcatalog.parser.ttypes import Parser
 from airavata.model.appcatalog.storageresource.ttypes import (
     StorageResourceDescription
 )
@@ -724,3 +725,7 @@ class StorageResourceSerializer(
         lookup_url_kwarg='storage_resource_id')
     creationTime = UTCPosixTimestampDateTimeField()
     updateTime = UTCPosixTimestampDateTimeField()
+
+
+class ParserSerializer(thrift_utils.create_serializer_class(Parser)):
+    pass
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 9184f0e..252b097 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
@@ -103,6 +103,7 @@ exports.services = {
   GroupResourceProfileService: ServiceFactory.service("GroupResourceProfiles"),
   GroupService: ServiceFactory.service("Groups"),
   LocaJobSubmissionService,
+  ParserService: ServiceFactory.service("Parsers"),
   ProjectService,
   SCPDataMovementService,
   ServiceFactory,
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/IOType.js b/django_airavata/apps/api/static/django_airavata_api/js/models/IOType.js
new file mode 100644
index 0000000..28b01b3
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/IOType.js
@@ -0,0 +1,4 @@
+import BaseEnum from "./BaseEnum";
+
+export default class IOType extends BaseEnum {}
+IOType.init(["FILE", "PROPERTY"]);
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/Parser.js b/django_airavata/apps/api/static/django_airavata_api/js/models/Parser.js
new file mode 100644
index 0000000..99ecadc
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/Parser.js
@@ -0,0 +1,28 @@
+
+import BaseModel from "./BaseModel";
+import ParserInputFile from "./ParserInput"
+import ParserOutputFile from "./ParserOutput"
+
+const FIELDS = [
+  "id",
+  "imageName",
+  "outputDirPath",
+  "inputDirPath",
+  "executionCommand",
+  {
+    name: "inputFiles",
+    list: true,
+    type: ParserInputFile
+  },
+  {
+    name: "outputFiles",
+    list: true,
+    type: ParserOutputFile
+  }
+];
+
+export default class Parser extends BaseModel {
+  constructor(data = {}) {
+    super(FIELDS, data);
+  }
+}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ParserInput.js b/django_airavata/apps/api/static/django_airavata_api/js/models/ParserInput.js
new file mode 100644
index 0000000..52afc24
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ParserInput.js
@@ -0,0 +1,19 @@
+import BaseModel from "./BaseModel";
+import IOType from "./IOType";
+
+const FIELDS = [
+  "id",
+  "name",
+  "requiredInput",
+  "parserId",
+  {
+    name: "type",
+    type: IOType
+  }
+];
+
+export default class ParserInput extends BaseModel {
+  constructor(data = {}) {
+    super(FIELDS, data);
+  }
+}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ParserOutput.js b/django_airavata/apps/api/static/django_airavata_api/js/models/ParserOutput.js
new file mode 100644
index 0000000..62de83d
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ParserOutput.js
@@ -0,0 +1,19 @@
+import BaseModel from "./BaseModel";
+import IOType from "./IOType";
+
+const FIELDS = [
+  "id",
+  "name",
+  "requiredOutput",
+  "parserId",
+  {
+    name: "type",
+    type: IOType
+  }
+];
+
+export default class ParserOutput extends BaseModel {
+  constructor(data = {}) {
+    super(FIELDS, data);
+  }
+}
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/service_config.js b/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
index 138c870..1a09882 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/service_config.js
@@ -5,6 +5,7 @@ import CredentialSummary from "./models/CredentialSummary";
 import GatewayResourceProfile from "./models/GatewayResourceProfile";
 import Group from "./models/Group";
 import GroupResourceProfile from "./models/GroupResourceProfile";
+import Parser from "./models/Parser";
 import SharedEntity from "./models/SharedEntity";
 import StoragePreference from "./models/StoragePreference";
 import StorageResourceDescription from "./models/StorageResourceDescription";
@@ -220,6 +221,21 @@ export default {
     queryParams: ["limit", "offset"],
     modelClass: Group
   },
+  Parsers: {
+    url: "/api/parsers",
+    viewSet: [
+      {
+        name: "retrieve"
+      },
+      {
+        name: "create"
+      },
+      {
+        name: "update"
+      }
+    ],
+    modelClass: Parser
+  },
   SharedEntities: {
     url: "/api/shared-entities",
     viewSet: [
diff --git a/django_airavata/apps/api/urls.py b/django_airavata/apps/api/urls.py
index a8d6a8b..eb81baf 100644
--- a/django_airavata/apps/api/urls.py
+++ b/django_airavata/apps/api/urls.py
@@ -40,6 +40,7 @@ router.register(r'gateway-resource-profiles',
 router.register(r'storage-preferences',
                 views.StoragePreferenceViewSet,
                 base_name='storage-preference')
+router.register(r'parsers', views.ParserViewSet, base_name='parser')
 
 app_name = 'django_airavata_api'
 urlpatterns = [
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index 92aeb06..52a959d 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -1009,3 +1009,24 @@ class StoragePreferenceViewSet(APIBackedViewSet):
     def perform_destroy(self, instance):
         self.request.airavata_client.deleteGatewayStoragePreference(
             self.authz_token, settings.GATEWAY_ID, instance.storageResourceId)
+
+
+class ParserViewSet(mixins.CreateModelMixin,
+                    mixins.RetrieveModelMixin,
+                    mixins.UpdateModelMixin,
+                    GenericAPIBackedViewSet):
+    serializer_class = serializers.ParserSerializer
+    lookup_field = 'parser_id'
+    lookup_value_regex = '[^/]+'
+
+    def get_instance(self, lookup_value):
+        return self.request.airavata_client.getParser(
+            self.authz_token, lookup_value)
+
+    def perform_create(self, serializer):
+        parser = serializer.save()
+        self.request.airavata_client.saveParser(self.authz_token, parser)
+
+    def perform_update(self, serializer):
+        parser = serializer.save()
+        self.request.airavata_client.saveParser(self.authz_token, parser)
diff --git a/django_airavata/apps/dataparsers/.babelrc b/django_airavata/apps/dataparsers/.babelrc
new file mode 100644
index 0000000..3ed94df
--- /dev/null
+++ b/django_airavata/apps/dataparsers/.babelrc
@@ -0,0 +1,5 @@
+{
+  "presets": [
+    ["env", { "modules": false }]
+  ]
+}
diff --git a/django_airavata/apps/dataparsers/__init__.py b/django_airavata/apps/dataparsers/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/django_airavata/apps/dataparsers/admin.py b/django_airavata/apps/dataparsers/admin.py
new file mode 100644
index 0000000..b97a94f
--- /dev/null
+++ b/django_airavata/apps/dataparsers/admin.py
@@ -0,0 +1,2 @@
+
+# Register your models here.
diff --git a/django_airavata/apps/dataparsers/apps.py b/django_airavata/apps/dataparsers/apps.py
new file mode 100644
index 0000000..28bf394
--- /dev/null
+++ b/django_airavata/apps/dataparsers/apps.py
@@ -0,0 +1,15 @@
+from django_airavata.app_config import AiravataAppConfig
+
+
+class DataParsersConfig(AiravataAppConfig):
+    name = 'django_airavata.apps.dataparsers'
+    label = 'django_airavata_dataparsers'
+    verbose_name = 'Data Parsers'
+    url_app_name = label
+    app_order = 20
+    url_home = 'django_airavata_dataparsers:home'
+    fa_icon_class = 'fa-files-o'
+    app_description = """
+        Define data parsers for post-processing experimental and ad-hoc
+        datasets.
+    """
diff --git a/django_airavata/apps/dataparsers/migrations/__init__.py b/django_airavata/apps/dataparsers/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/django_airavata/apps/dataparsers/models.py b/django_airavata/apps/dataparsers/models.py
new file mode 100644
index 0000000..6b20219
--- /dev/null
+++ b/django_airavata/apps/dataparsers/models.py
@@ -0,0 +1 @@
+# Create your models here.
diff --git a/django_airavata/apps/dataparsers/package.json b/django_airavata/apps/dataparsers/package.json
new file mode 100644
index 0000000..c6372fb
--- /dev/null
+++ b/django_airavata/apps/dataparsers/package.json
@@ -0,0 +1,34 @@
+{
+  "name": "django-airavata-dataparsers-views",
+  "description": "A Vue.js project",
+  "version": "1.0.0",
+  "author": "Marcus Christie <ma...@apache.org>",
+  "private": true,
+  "scripts": {
+    "dev": "cross-env NODE_ENV=development webpack --progress --hide-modules",
+    "watch": "cross-env NODE_ENV=development webpack --watch",
+    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
+  },
+  "dependencies": {
+    "bootstrap": "^4.1.3",
+    "bootstrap-vue": "^2.0.0-rc.11",
+    "django-airavata-api": "file:../api",
+    "django-airavata-common-ui": "file:../../static/common",
+    "vue": "^2.5.17"
+  },
+  "devDependencies": {
+    "babel-core": "^6.0.0",
+    "babel-loader": "^7.1.2",
+    "babel-preset-env": "^1.5.1",
+    "clean-webpack-plugin": "^0.1.17",
+    "cross-env": "^3.0.0",
+    "css-loader": "^0.25.0",
+    "extract-text-webpack-plugin": "^3.0.2",
+    "file-loader": "^0.9.0",
+    "style-loader": "^0.19.0",
+    "vue-loader": "^12.1.0",
+    "vue-template-compiler": "^2.3.3",
+    "webpack": "^3.1.0",
+    "webpack-dev-server": "^2.4.5"
+  }
+}
diff --git a/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/containers/ParserDetailsContainer.vue b/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/containers/ParserDetailsContainer.vue
new file mode 100644
index 0000000..7810852
--- /dev/null
+++ b/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/containers/ParserDetailsContainer.vue
@@ -0,0 +1,43 @@
+<template>
+  <div>
+    <div class="row">
+      <div class="col">
+        <h1 class="h4 mb-4">
+          <div>{{ parserId }}</div>
+        </h1>
+      </div>
+    </div>
+    <div class="row" v-if="parser">
+      <div class="col">
+        <b-form-group label="Image Name" label-for="image-name">
+          <b-form-input id="image-name" type="text" v-model="parser.imageName" />
+        </b-form-group>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { services } from "django-airavata-api";
+
+export default {
+  name: "parser-details-container",
+  props: {
+    parserId: {
+      type: String,
+      required: true
+    }
+  },
+  data() {
+    return {
+      parser: null
+    };
+  },
+  created() {
+    services.ParserService.retrieve({
+      lookup: this.parserId
+    }).then(parser => (this.parser = parser));
+  }
+};
+</script>
+
diff --git a/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/entry-parser-details.js b/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/entry-parser-details.js
new file mode 100644
index 0000000..8092700
--- /dev/null
+++ b/django_airavata/apps/dataparsers/static/django_airavata_dataparsers/js/entry-parser-details.js
@@ -0,0 +1,26 @@
+import Vue from "vue";
+import BootstrapVue from "bootstrap-vue";
+import ParserDetailsContainer from "./containers/ParserDetailsContainer.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: "#parser-details",
+  template:
+    '<parser-details-container v-bind:parser-id="parserId"></parser-details-container>',
+  data: {
+    parserId: null
+  },
+  components: {
+    ParserDetailsContainer
+  },
+  beforeMount: function() {
+    if (this.$el.dataset.parserId) {
+      this.parserId = this.$el.dataset.parserId;
+    }
+  }
+});
diff --git a/django_airavata/apps/dataparsers/templates/django_airavata_dataparsers/base.html b/django_airavata/apps/dataparsers/templates/django_airavata_dataparsers/base.html
new file mode 100644
index 0000000..168b010
--- /dev/null
+++ b/django_airavata/apps/dataparsers/templates/django_airavata_dataparsers/base.html
@@ -0,0 +1,21 @@
+
+{% extends 'base.html' %}
+
+{% load static %}
+
+{% block css %}
+<link rel=stylesheet type=text/css href="{% static 'django_airavata_dataparsers/dist/common.css' %}">
+{% endblock %}
+
+{% block nav-items %}
+
+        <a href="{% url 'django_airavata_dataparsers:home' %}"
+            class="c-nav__item {% if request.active_nav_item == 'home' %}is-active{% endif %}"
+            data-toggle=tooltip data-placement=right title="Home">
+            <i class="fa fa-home"></i> <span class=sr-only>Home</span>
+        </a>
+{% endblock %}
+
+{% block scripts %}
+<script src="{% static "django_airavata_dataparsers/dist/common.js" %}"></script>
+{% endblock %}
diff --git a/django_airavata/apps/dataparsers/templates/django_airavata_dataparsers/home.html b/django_airavata/apps/dataparsers/templates/django_airavata_dataparsers/home.html
new file mode 100644
index 0000000..2953cda
--- /dev/null
+++ b/django_airavata/apps/dataparsers/templates/django_airavata_dataparsers/home.html
@@ -0,0 +1,19 @@
+{% extends './base.html' %}
+
+{% load static %}
+
+{% block css %}
+{{ block.super }}
+{% comment %}Load any CSS specific to this page here, if necessary{% endcomment %}
+{% endblock %}
+
+{% block content %}
+
+<h1>Hello World!</h1>
+
+{% endblock content %}
+
+{% block scripts %}
+{{ block.super }}
+{% comment %}Load any JS specific to this page here, if necessary{% endcomment %}
+{% endblock %}
diff --git a/django_airavata/apps/dataparsers/templates/django_airavata_dataparsers/parser-details.html b/django_airavata/apps/dataparsers/templates/django_airavata_dataparsers/parser-details.html
new file mode 100644
index 0000000..c3a077d
--- /dev/null
+++ b/django_airavata/apps/dataparsers/templates/django_airavata_dataparsers/parser-details.html
@@ -0,0 +1,19 @@
+{% extends './base.html' %}
+
+{% load static %}
+
+{% block css %}
+{{ block.super }}
+<link rel=stylesheet type=text/css href="{% static 'django_airavata_dataparsers/dist/parser-details.css' %}">
+{% endblock %}
+
+{% block content %}
+
+<div id="parser-details" data-parser-id="{{ parser_id }}"></div>
+
+{% endblock content %}
+
+{% block scripts %}
+{{ block.super }}
+<script src="{% static "django_airavata_dataparsers/dist/parser-details.js" %}"></script>
+{% endblock %}
diff --git a/django_airavata/apps/dataparsers/tests.py b/django_airavata/apps/dataparsers/tests.py
new file mode 100644
index 0000000..4929020
--- /dev/null
+++ b/django_airavata/apps/dataparsers/tests.py
@@ -0,0 +1,2 @@
+
+# Create your tests here.
diff --git a/django_airavata/apps/dataparsers/urls.py b/django_airavata/apps/dataparsers/urls.py
new file mode 100644
index 0000000..c25bfa6
--- /dev/null
+++ b/django_airavata/apps/dataparsers/urls.py
@@ -0,0 +1,11 @@
+
+from django.conf.urls import url
+
+from . import views
+
+app_name = 'django_airavata_dataparsers'
+urlpatterns = [
+    url(r'^home$', views.home, name='home'),
+    url(r'^parsers/(?P<parser_id>[^/]+)/$',
+        views.parser_details, name="parser_details")
+]
diff --git a/django_airavata/apps/dataparsers/views.py b/django_airavata/apps/dataparsers/views.py
new file mode 100644
index 0000000..8d7bef9
--- /dev/null
+++ b/django_airavata/apps/dataparsers/views.py
@@ -0,0 +1,11 @@
+from django.shortcuts import render
+
+
+def home(request):
+    return render(request, 'django_airavata_dataparsers/home.html')
+
+
+def parser_details(request, parser_id):
+    return render(request, 'django_airavata_dataparsers/parser-details.html', {
+        "parser_id": parser_id
+    })
diff --git a/django_airavata/apps/dataparsers/webpack.config.js b/django_airavata/apps/dataparsers/webpack.config.js
new file mode 100644
index 0000000..20f0290
--- /dev/null
+++ b/django_airavata/apps/dataparsers/webpack.config.js
@@ -0,0 +1,92 @@
+var path = require('path')
+var webpack = require('webpack')
+const ExtractTextPlugin = require("extract-text-webpack-plugin");
+const CleanWebpackPlugin = require('clean-webpack-plugin');
+
+module.exports = {
+  entry: {
+      'parser-details': './static/django_airavata_dataparsers/js/entry-parser-details',
+  },
+  output: {
+    path: path.resolve(__dirname, './static/django_airavata_dataparsers/dist/'),
+    publicPath: '/static/django_airavata_dataparsers/dist/',
+    filename: '[name].js'
+  },
+  module: {
+    rules: [
+      {
+        test: /\.vue$/,
+        loader: 'vue-loader',
+        options: {
+          loaders: {
+          },
+          extractCSS: true
+          // other vue-loader options go here
+        }
+      },
+      {
+        test: /\.js$/,
+        loader: 'babel-loader',
+        exclude: /node_modules/
+      },
+      {
+          test: /\.css$/,
+          use: ExtractTextPlugin.extract({
+              fallback: "style-loader",
+              use: "css-loader"
+          })
+      },
+      {
+        test: /\.(png|jpg|gif|svg)$/,
+        loader: 'file-loader',
+        options: {
+          name: '[name].[ext]?[hash]'
+        }
+      }
+    ]
+  },
+  resolve: {
+    alias: {
+      'vue$': 'vue/dist/vue.esm.js'
+    }
+  },
+  devServer: {
+    historyApiFallback: true,
+    noInfo: true
+  },
+  performance: {
+    hints: false
+  },
+  devtool: '#eval-source-map',
+  plugins: [
+      // Exclude all but the 'en' locale from moment's locales
+      new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /^en$/),
+      new ExtractTextPlugin("[name].css"),
+      new CleanWebpackPlugin(['./static/django_airavata_dataparsers/dist']),
+      new webpack.optimize.CommonsChunkPlugin({
+          name: 'common',
+      }),
+
+  ]
+}
+
+if (process.env.NODE_ENV === 'production') {
+  module.exports.devtool = '#source-map'
+  // http://vue-loader.vuejs.org/en/workflow/production.html
+  module.exports.plugins = (module.exports.plugins || []).concat([
+    new webpack.DefinePlugin({
+      'process.env': {
+        NODE_ENV: '"production"'
+      }
+    }),
+    new webpack.optimize.UglifyJsPlugin({
+      sourceMap: true,
+      compress: {
+        warnings: false
+      }
+    }),
+    new webpack.LoaderOptionsPlugin({
+      minimize: true
+    })
+  ])
+}
diff --git a/django_airavata/settings.py b/django_airavata/settings.py
index 1ce34e6..4128c1a 100644
--- a/django_airavata/settings.py
+++ b/django_airavata/settings.py
@@ -44,6 +44,7 @@ INSTALLED_APPS = [
     'rest_framework',
     'django_airavata.apps.api.apps.ApiConfig',
     'django_airavata.apps.groups.apps.GroupsConfig',
+    'django_airavata.apps.dataparsers.apps.DataParsersConfig',
 
     # wagtail related apps
     'wagtail.contrib.forms',
diff --git a/django_airavata/urls.py b/django_airavata/urls.py
index 6cdcb2a..50e4084 100644
--- a/django_airavata/urls.py
+++ b/django_airavata/urls.py
@@ -30,6 +30,7 @@ urlpatterns = [
     url(r'^workspace/', include('django_airavata.apps.workspace.urls')),
     url(r'^api/', include('django_airavata.apps.api.urls')),
     url(r'^groups/', include('django_airavata.apps.groups.urls')),
+    url(r'^dataparsers/', include('django_airavata.apps.dataparsers.urls')),
     url(r'^home$', views.home, name='home'),
     url(r'^cms/', include(wagtailadmin_urls)),
     url(r'^documents/', include(wagtaildocs_urls)),


[airavata-django-portal] 01/02: Documentation 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 ab419f54c328dfc036e2fd63ed548bda1d18b148
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Wed Nov 21 18:22:44 2018 -0500

    Documentation on adding Django app
---
 .gitignore                 |   2 +
 docs/dev/new_django_app.md | 353 +++++++++++++++++++++++++++++++++++++++++++++
 docs/index.md              |   8 +
 mkdocs.yml                 |  12 ++
 requirements-dev.txt       |   1 +
 5 files changed, 376 insertions(+)

diff --git a/.gitignore b/.gitignore
index 1729ed7..734cdd3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,5 @@ jsconfig.json
 airavata_django_portal.egg-info
 # AIRAVATA-2951 package-lock.json files cause the build to fail when deploying to server
 package-lock.json
+# mkdocs
+site/
diff --git a/docs/dev/new_django_app.md b/docs/dev/new_django_app.md
new file mode 100644
index 0000000..56ba67e
--- /dev/null
+++ b/docs/dev/new_django_app.md
@@ -0,0 +1,353 @@
+# Adding a Django App
+
+The functionality of the Airavata Django Portal is broken up into separate
+Django apps. The apps live in the `django_airavata/apps` directory. When
+adding new functionality to the Django portal it may make sense to add it as
+a new separate Django app instead of adding it to an existing app. The
+following steps document how to do this.
+
+## Create the new Django App
+
+For this example, assume the name of the app is **myapp**. The following also
+assumes you have sourced your virtual environment.
+
+```
+cd airavata-django-portal
+mkdir django_airavata/apps/myapp
+python manage.py startapp myapp django_airavata/apps/myapp
+```
+
+## Integrating with the Django Portal
+
+### AppConfig settings
+
+Edit the AppConfig so that it extends the AiravataAppConfig and fill in the
+required details:
+
+```python
+from django_airavata.app_config import AiravataAppConfig
+
+
+class MyAppConfig(AiravataAppConfig):
+    name = 'django_airavata.apps.myapp'
+    label = 'django_airavata_myapp'
+    verbose_name = 'My App'
+    url_app_name = label
+    app_order = 10
+    url_home = 'django_airavata_myapp:home'
+    fa_icon_class = 'fa-bolt'
+    app_description = """
+        My app for doing stuff in the Airavata Django Portal.
+    """
+```
+
+Some of these are self explanatory, but here are some details on each of
+these properties:
+
+- _name_ - this is the python package of the app
+- _label_ - this needs to be unique across all installed Django apps. I
+  just make this match the _app_name_ in `urls.py`.
+- _verbose_name_ - display name of app
+- _url_app_name_ - this needs to match the _app_name_ in `urls.py`
+- _app_order_ - order of app in the menu listing. Range is 0 - 100. See the
+  other Django apps for their values to figure out how to order this app
+  relative to them.
+- _url_home_ - namespaced url of the "home" page of this app. This will be
+  the url used when a user selects this app in a navigational menu.
+- _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
+
+### Add AppConfig to INSTALLED_APPS
+
+Edit INSTALLED_APPS in settings.py:
+
+```python
+INSTALLED_APPS = [
+  # ...
+  'django_airavata.apps.myapp.MyAppConfig'
+]
+```
+
+### Add the apps urls to the site's urls.py
+
+Edit `django_airavata/urls.py` and add the app's urls config:
+
+```python
+urlpatterns = [
+    url(r'^djadmin/', admin.site.urls),
+    url(r'^admin/', include('django_airavata.apps.admin.urls')),
+    url(r'^auth/', include('django_airavata.apps.auth.urls')),
+    url(r'^workspace/', include('django_airavata.apps.workspace.urls')),
+    url(r'^api/', include('django_airavata.apps.api.urls')),
+    url(r'^groups/', include('django_airavata.apps.groups.urls')),
+    # ... Add the app urls here
+    url(r'^myapp/', include('django_airavata.apps.myapp.urls')),
+    # ...
+    url(r'^home$', views.home, name='home'),
+    url(r'^cms/', include(wagtailadmin_urls)),
+    url(r'^documents/', include(wagtaildocs_urls)),
+    url(r'', include(wagtail_urls)),
+] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
+```
+
+It's important that the app urls are added before the `wagtail_urls` since
+wagtail controls those urls.
+
+
+## App urls.py and base template
+
+Let's add a starter home page and urls.py config for this app.  Create a `urls.py` file in `myapp/`:
+
+```python
+from django.conf.urls import url
+
+from . import views
+
+app_name = 'django_airavata_myapp'
+urlpatterns = [
+    url(r'^home$', views.home, name='home'),
+]
+```
+
+Add a view function called `home` in views.py:
+
+```python
+from django.shortcuts import render
+
+
+def home(request):
+    return render(request, 'django_airavata_myapp/home.html')
+```
+
+Create a templates directory called in `myapp` called `templates/django_airavata_myapp/`.
+
+Then create a base template in that directory called `base.html`:
+
+```html
+
+{% extends 'base.html' %}
+
+{% load static %}
+
+{% block css %}
+{% comment %}Load any styles sheets that are common across all pages in your app{% endcomment %}
+<link rel=stylesheet type=text/css href="{% static 'django_airavata_myapp/dist/common.css' %}">
+{% 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 scripts %}
+{% comment %}Load any javascript common to all pages in your app{% endcomment %}
+<script src="{% static "django_airavata_workspace/dist/common.js" %}"></script>
+{% endblock %}
+```
+
+Now, create a `home.html` template:
+
+```html
+
+{% extends './base.html' %}
+
+{% load static %}
+
+{% block css %}
+{{ block.super }}
+{% comment %}Load any CSS specific to this page here, if necessary{% endcomment %}
+{% endblock %}
+
+{% block content %}
+
+<h1>Hello World!</h1>
+
+{% endblock content %}
+
+{% block scripts %}
+{{ block.super }}
+{% comment %}Load any JS specific to this page here, if necessary{% endcomment %}
+{% endblock %}
+```
+
+Now if you log into the Django portal you should see "My App" in the menu at
+the top and clicking on it should display the home page of this app.
+
+
+## JS build config - Vue.js
+
+Now we'll add JavaScript build config to the app using Vue.js, npm and webpack.
+
+Add a package.json file to the app's directory (i.e., django_airavata/apps/myapp):
+
+```json
+{
+  "name": "django-airavata-myapp-views",
+  "description": "A Vue.js project",
+  "version": "1.0.0",
+  "author": "Marcus Christie <ma...@apache.org>",
+  "private": true,
+  "scripts": {
+    "dev": "cross-env NODE_ENV=development webpack --progress --hide-modules",
+    "watch": "cross-env NODE_ENV=development webpack --watch",
+    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
+  },
+  "dependencies": {
+    "bootstrap": "^4.0.0-beta.2",
+    "bootstrap-vue": "^1.4.1",
+    "django-airavata-api": "file:../api",
+    "django-airavata-common-ui": "file:../../static/common",
+    "vue": "^2.5.17"
+  },
+  "devDependencies": {
+    "babel-core": "^6.0.0",
+    "babel-loader": "^7.1.2",
+    "babel-preset-env": "^1.5.1",
+    "clean-webpack-plugin": "^0.1.17",
+    "cross-env": "^3.0.0",
+    "css-loader": "^0.25.0",
+    "extract-text-webpack-plugin": "^3.0.2",
+    "file-loader": "^0.9.0",
+    "style-loader": "^0.19.0",
+    "vue-loader": "^12.1.0",
+    "vue-template-compiler": "^2.3.3",
+    "webpack": "^3.1.0",
+    "webpack-dev-server": "^2.4.5"
+  }
+}
+```
+
+Add a `.babelrc` to this directory too:
+
+```json
+{
+  "presets": [
+    ["env", { "modules": false }]
+  ]
+}
+```
+
+Now add a `webpack.config.js` file too:
+
+```javascript
+var path = require('path')
+var webpack = require('webpack')
+const ExtractTextPlugin = require("extract-text-webpack-plugin");
+const CleanWebpackPlugin = require('clean-webpack-plugin');
+
+module.exports = {
+  entry: {
+      'home': './static/django_airavata_myapp/js/entry-home',
+  },
+  output: {
+    path: path.resolve(__dirname, './static/django_airavata_myapp/dist/'),
+    publicPath: '/static/django_airavata_myapp/dist/',
+    filename: '[name].js'
+  },
+  module: {
+    rules: [
+      {
+        test: /\.vue$/,
+        loader: 'vue-loader',
+        options: {
+          loaders: {
+          },
+          extractCSS: true
+          // other vue-loader options go here
+        }
+      },
+      {
+        test: /\.js$/,
+        loader: 'babel-loader',
+        exclude: /node_modules/
+      },
+      {
+          test: /\.css$/,
+          use: ExtractTextPlugin.extract({
+              fallback: "style-loader",
+              use: "css-loader"
+          })
+      },
+      {
+        test: /\.(png|jpg|gif|svg)$/,
+        loader: 'file-loader',
+        options: {
+          name: '[name].[ext]?[hash]'
+        }
+      }
+    ]
+  },
+  resolve: {
+    alias: {
+      'vue$': 'vue/dist/vue.esm.js'
+    }
+  },
+  devServer: {
+    historyApiFallback: true,
+    noInfo: true
+  },
+  performance: {
+    hints: false
+  },
+  devtool: '#eval-source-map',
+  plugins: [
+      new ExtractTextPlugin("[name].css"),
+      new CleanWebpackPlugin(['./static/interactwel_gui/dist']),
+      new webpack.optimize.CommonsChunkPlugin({
+          name: 'common',
+      }),
+
+  ]
+}
+
+if (process.env.NODE_ENV === 'production') {
+  module.exports.devtool = '#source-map'
+  // http://vue-loader.vuejs.org/en/workflow/production.html
+  module.exports.plugins = (module.exports.plugins || []).concat([
+    new webpack.DefinePlugin({
+      'process.env': {
+        NODE_ENV: '"production"'
+      }
+    }),
+    new webpack.optimize.UglifyJsPlugin({
+      sourceMap: true,
+      compress: {
+        warnings: false
+      }
+    }),
+    new webpack.LoaderOptionsPlugin({
+      minimize: true
+    })
+  ])
+}
+```
+
+You'll customize *entry* by modifying and/or adding additional entry points
+and you'll need to modify *output.path* and *output.publicPath* 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 entry points, for example `entry-home.js`.
+
+For each entry point you'll create a template, extending your app's
+`base.html` and including that entry points generated css and js file.
+
+For a complete example, see the *workspace* app.
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..a23d6cf
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,8 @@
+
+# Apache Airavata Django Portal
+
+The Airavata Django Portal is a web interface to the [Apache
+Airavata](http://airavata.apache.org/) API implemented using the Django web
+framework. The intention is that the Airavata Django Portal can be used as is
+for a full featured web based science gateway but it can also be customized
+through various plugins to add more domain specific functionality as needed.
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 0000000..7eca799
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,12 @@
+site_name: Airavata Django Portal
+
+repo_url: https://github.com/apache/airavata-django-portal/
+
+nav:
+  - Home: index.md
+  - User Guide:
+    - Using the integrated CMS: cms.md
+  - Developer Guide:
+    - Adding a Django App: dev/new_django_app.md
+
+theme: readthedocs
diff --git a/requirements-dev.txt b/requirements-dev.txt
index e1e5f8e..b90575d 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -1,5 +1,6 @@
 -r requirements.txt
 flake8==3.5.0
 flake8-isort==2.5
+mkdocs==1.0.4
 
 -e ".[dev]"