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 <machr...@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 <machris...@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)),