You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2021/06/18 19:38:18 UTC
[airavata-django-portal] 01/20: AIRAVATA-3453 POC: initial
supcrtbl2 custom interface with WCs
This is an automated email from the ASF dual-hosted git repository.
machristie pushed a commit to branch airavata-3453
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git
commit 702d90505103c044aa8672b1ff3cd9e1d2ebf6b9
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Tue Apr 27 09:41:43 2021 -0400
AIRAVATA-3453 POC: initial supcrtbl2 custom interface with WCs
---
django_airavata/apps/workspace/package.json | 4 +-
.../static/django_airavata_workspace/.gitignore | 1 +
.../js/web-components/ExperimentEditor.vue | 114 +++++++++++++++++++++
.../js/web-components/Foo.vue | 3 +
.../js/web-components/store.js | 44 ++++++++
.../django_airavata_workspace/supcrtbl2.html | 80 +++++++++++++++
django_airavata/apps/workspace/views.py | 6 +-
django_airavata/apps/workspace/vue.config.js | 15 +--
8 files changed, 258 insertions(+), 9 deletions(-)
diff --git a/django_airavata/apps/workspace/package.json b/django_airavata/apps/workspace/package.json
index 8d53566..6d227b1 100644
--- a/django_airavata/apps/workspace/package.json
+++ b/django_airavata/apps/workspace/package.json
@@ -12,7 +12,9 @@
"test": "npm run test:unit",
"test:unit": "vue-cli-service test:unit",
"test:unit:watch": "vue-cli-service test:unit --watch",
- "format": "prettier --write ."
+ "format": "prettier --write .",
+ "wc": "WC_MODE='true' vue-cli-service build --target wc --inline-vue --name adpf './static/django_airavata_workspace/js/web-components/*.vue' --dest ./static/django_airavata_workspace/wc",
+ "wc:watch": "WC_MODE='true' vue-cli-service build --target wc --inline-vue --name adpf './static/django_airavata_workspace/js/web-components/*.vue' --dest ./static/django_airavata_workspace/wc --watch"
},
"dependencies": {
"bootstrap": "^4.3.1",
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/.gitignore b/django_airavata/apps/workspace/static/django_airavata_workspace/.gitignore
new file mode 100644
index 0000000..ab46eb7
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/.gitignore
@@ -0,0 +1 @@
+wc
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentEditor.vue
new file mode 100644
index 0000000..6b956f5
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentEditor.vue
@@ -0,0 +1,114 @@
+<template>
+ <form v-if="experiment" @input="onInput" @submit.prevent="onSubmit">
+ <slot name="experiment-name">
+ <input
+ type="text"
+ name="experiment-name"
+ :value="experiment.experimentName"
+ />
+ </slot>
+ <template v-for="input in experiment.experimentInputs">
+ <div :key="input.name">
+ <slot :name="input.name">
+ {{input.name}} <input v-if="input.type.name == 'STRING'" :name="`input:${input.name}`" :value="input.value"/>
+ </slot>
+ <!-- TODO: add support for other input types -->
+ </div>
+ </template>
+ <slot name="save-button">
+ <button type="submit" name="save-experiment-button">Save</button>
+ </slot>
+ </form>
+</template>
+
+<script>
+import {
+ getApplicationModule,
+ getApplicationInterfaceForModule,
+ saveExperiment,
+ getDefaultProjectId,
+ getExperiment,
+} from "./store";
+
+export default {
+ props: {
+ applicationId: {
+ type: String,
+ required: true,
+ },
+ experimentId: {
+ type: String,
+ required: false,
+ },
+ },
+ async created() {
+ this.applicationModule = await getApplicationModule(this.applicationId);
+ this.appInterface = await getApplicationInterfaceForModule(
+ this.applicationId
+ );
+ this.experiment = await this.loadExperiment();
+ },
+ data() {
+ return {
+ applicationModule: null,
+ appInterface: null,
+ experiment: null,
+ };
+ },
+ methods: {
+ onInput(event) {
+ console.log(event.target.name, event.target.value);
+ if (event.target.name === "experiment-name") {
+ this.experiment.experimentName = event.target.value;
+ }
+ if (event.target.name.startsWith("input:")) {
+ for (const input of this.experiment.experimentInputs) {
+ if (event.target.name === `input:${input.name}`){
+ input.value = event.target.value;
+ }
+ }
+ }
+ },
+ onSubmit(event) {
+ // console.log(event);
+ // 'save' event is cancelable. Listener can call .preventDefault() on the event to cancel.
+ // composed: true allows the shadow DOM event to bubble up through the shadow shadow root.
+ const saveEvent = new CustomEvent('save', {detail: [this.experiment], cancelable: true, composed: true});
+ this.$el.dispatchEvent(saveEvent);
+ if (saveEvent.defaultPrevented) {
+ return;
+ }
+ if (event.submitter.name === "save-experiment-button") {
+ this.saveExperiment();
+ } else {
+ // Default submit button handling is save and launch
+ }
+ },
+ async saveExperiment() {
+ return await saveExperiment(this.experiment);
+ },
+ async loadExperiment() {
+
+ if (this.experimentId) {
+ const experiment = await getExperiment(this.experimentId);
+ this.$emit('loaded', experiment);
+ return experiment;
+ } else {
+ const experiment = this.appInterface.createExperiment();
+ experiment.experimentName =
+ this.applicationModule.appModuleName +
+ " on " +
+ new Date().toLocaleString();
+ const defaultProjectId = await getDefaultProjectId();
+ experiment.projectId = defaultProjectId;
+ experiment.userConfigurationData.computationalResourceScheduling.resourceHostId =
+ "bigred3.uits.iu.edu_2141bf96-c458-4ecd-8759-aa3a08f31956";
+ this.$emit('loaded', experiment);
+ return experiment;
+ }
+ }
+ },
+};
+</script>
+
+<style></style>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/Foo.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/Foo.vue
new file mode 100644
index 0000000..7b8b46c
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/Foo.vue
@@ -0,0 +1,3 @@
+<template>
+ <div></div>
+</template>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/store.js b/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/store.js
new file mode 100644
index 0000000..2f66bfb
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/store.js
@@ -0,0 +1,44 @@
+import { services } from "django-airavata-api";
+const APPLICATION_MODULES = {};
+const APPLICATION_INTERFACES = {};
+export async function getApplicationModule(applicationId) {
+ if (applicationId in APPLICATION_MODULES) {
+ return APPLICATION_MODULES[applicationId];
+ }
+ const result = await services.ApplicationModuleService.retrieve({
+ lookup: applicationId,
+ });
+ APPLICATION_MODULES[applicationId] = result;
+ return result;
+}
+
+export async function getApplicationInterfaceForModule(applicationId) {
+ if (applicationId in APPLICATION_INTERFACES) {
+ return APPLICATION_INTERFACES[applicationId];
+ }
+ const result = await services.ApplicationModuleService.getApplicationInterface(
+ { lookup: applicationId }
+ );
+ APPLICATION_INTERFACES[applicationId] = result;
+ return result;
+}
+
+export async function saveExperiment(experiment) {
+ if (experiment.experimentId) {
+ return await services.ExperimentService.update({
+ data: experiment,
+ lookup: experiment.experimentId,
+ });
+ } else {
+ return await services.ExperimentService.create({ data: experiment });
+ }
+}
+
+export async function getDefaultProjectId() {
+ const preferences = await services.WorkspacePreferencesService.get();
+ return preferences.most_recent_project_id;
+}
+
+export async function getExperiment(experimentId) {
+ return await services.ExperimentService.retrieve({ lookup: experimentId });
+}
diff --git a/django_airavata/apps/workspace/templates/django_airavata_workspace/supcrtbl2.html b/django_airavata/apps/workspace/templates/django_airavata_workspace/supcrtbl2.html
new file mode 100644
index 0000000..588fc3b
--- /dev/null
+++ b/django_airavata/apps/workspace/templates/django_airavata_workspace/supcrtbl2.html
@@ -0,0 +1,80 @@
+{% extends 'base.html' %}
+
+{% load static %}
+{% load render_bundle from webpack_loader %}
+
+{% block css %}
+{% comment %} TODO: are chunk-vendors and chunk-common needed? {% endcomment %}
+{% comment %} {% render_bundle 'chunk-vendors' 'css' 'WORKSPACE' %} {% endcomment %}
+{% comment %} {% render_bundle 'chunk-common' 'css' 'WORKSPACE' %} {% endcomment %}
+{% comment %} {% render_bundle 'adpf' 'css' 'WORKSPACE' %} {% endcomment %}
+{% endblock %}
+
+{% block content %}
+{% comment %} TODO: maybe use wc- as a prefix? {% endcomment %}
+<div class="main-content-wrapper">
+ <main class="main-content">
+ <div class="container-fluid">
+ <h1>SUPCRTBL Online Version 1.0.1</h2>
+ <adpf-experiment-editor
+ id="experiment-editor"
+ application-id="supcrtbl_eb4216b3-fcbf-4422-a70d-27af2550cfb6"
+ {% if experiment_id %}
+ experiment-id="{{ experiment_id }}"
+ {% endif %} >
+ <div id="solvent" slot="Specify Solvent Phase Region">
+ <label for="input:Specify Solvent Phase Region">Specify solvent phase region:</label>
+ <input type="radio" name="input:Specify Solvent Phase Region" value="0">One-phase region</input> <br/>
+ <input type="radio" name="input:Specify Solvent Phase Region" value="1">liquid vapor saturation curve</input>
+ </div>
+
+ <div slot="Input-to-Echo">
+ My custom input editor: <input id="myinput" style="background-color: lightgrey;" name="input:Input-to-Echo" value=""/>
+ </div>
+ </adpf-experiment-editor>
+ </div>
+ </main>
+</div>
+{% endblock content %}
+
+{% block scripts %}
+{% comment %} {% render_bundle 'chunk-vendors' 'js' 'WORKSPACE' %} {% endcomment %}
+<script src="{% static 'django_airavata_workspace/wc/adpf.chunk-vendors.js' %}"></script>
+{% comment %} {% render_bundle 'chunk-common' 'js' 'WORKSPACE' %} {% endcomment %}
+{% comment %} {% render_bundle 'adpf' 'js' 'WORKSPACE' %} {% endcomment %}
+<script src="{% static 'django_airavata_workspace/wc/adpf.min.js' %}"></script>
+<script>
+document.getElementById("experiment-editor").addEventListener('loaded', e => {
+ const [experiment] = e.detail;
+ for (const input of experiment.experimentInputs) {
+ // This runs before the custom element is registered which is probably why we need setAttribute here
+ // TODO: just iterate over the slotted inputs
+ const inputEl = document.querySelector(`[name="input:${input.name}"]`)
+ if (!inputEl) {
+ console.warn("Could not find input editor for ", input);
+ } else {
+ if (inputEl.type === 'radio') {
+ const radios = document.querySelectorAll(`[name="input:${input.name}"]`);
+ for (const radio of radios) {
+ if (radio.value === input.value) {
+ radio.checked = true;
+ break;
+ }
+ }
+ }
+ inputEl.setAttribute("value", input.value);
+ }
+ // document.getElementById("myinput").setAttribute("value", input.value);
+ }
+});
+function validateExperiment(event) {
+ const [experiment] = event.detail;
+ // This works, can check the current values of all inputs
+ if (experiment.experimentInputs[0].value === "Valcustom3") {
+ console.log('save: preventing default');
+ event.preventDefault();
+ }
+}
+document.getElementById('experiment-editor').addEventListener('save', validateExperiment);
+</script>
+{% endblock %}
diff --git a/django_airavata/apps/workspace/views.py b/django_airavata/apps/workspace/views.py
index 3f6d336..84cc7e6 100644
--- a/django_airavata/apps/workspace/views.py
+++ b/django_airavata/apps/workspace/views.py
@@ -114,7 +114,8 @@ def create_experiment(request, app_module_id):
context['experiment_data_dir'] = request.GET['experiment-data-dir']
return render(request,
- 'django_airavata_workspace/create_experiment.html',
+ # 'django_airavata_workspace/create_experiment.html',
+ 'django_airavata_workspace/supcrtbl2.html',
context)
@@ -123,7 +124,8 @@ def edit_experiment(request, experiment_id):
request.active_nav_item = 'experiments'
return render(request,
- 'django_airavata_workspace/edit_experiment.html',
+ # 'django_airavata_workspace/edit_experiment.html',
+ 'django_airavata_workspace/supcrtbl2.html',
{'bundle_name': 'edit-experiment',
'experiment_id': experiment_id})
diff --git a/django_airavata/apps/workspace/vue.config.js b/django_airavata/apps/workspace/vue.config.js
index 01afb3d..c08ea40 100644
--- a/django_airavata/apps/workspace/vue.config.js
+++ b/django_airavata/apps/workspace/vue.config.js
@@ -31,12 +31,15 @@ module.exports = {
},
},
configureWebpack: {
- plugins: [
- new BundleTracker({
- filename: "webpack-stats.json",
- path: "./static/django_airavata_workspace/dist/",
- }),
- ],
+ plugins:
+ process.env.WC_MODE !== "true"
+ ? [
+ new BundleTracker({
+ filename: "webpack-stats.json",
+ path: "./static/django_airavata_workspace/dist/",
+ }),
+ ]
+ : [],
optimization: {
/*
* Force creating a vendor bundle so we can load the 'app' and 'vendor'