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 2020/06/12 19:51:17 UTC
[airavata-django-portal] 04/05: AIRAVATA-3285 range and stepper
numeric interactive parameter widgets
This is an automated email from the ASF dual-hosted git repository.
machristie pushed a commit to branch AIRAVATA-3285--Interactive-output-view-providers
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git
commit 5bbf1f9c7598eb295d9c46d49f195598141f7a6f
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Thu May 28 09:57:51 2020 -0400
AIRAVATA-3285 range and stepper numeric interactive parameter widgets
---
django_airavata/apps/api/output_views.py | 43 ++++++++++++----
.../InteractiveParameterRangeWidget.vue | 59 ++++++++++++++++++++++
.../InteractiveParameterStepperWidget.vue | 58 +++++++++++++++++++++
.../InteractiveParameterWidgetContainer.vue | 32 ++++++++++--
4 files changed, 177 insertions(+), 15 deletions(-)
diff --git a/django_airavata/apps/api/output_views.py b/django_airavata/apps/api/output_views.py
index dfc3808..d4fd1ee 100644
--- a/django_airavata/apps/api/output_views.py
+++ b/django_airavata/apps/api/output_views.py
@@ -210,19 +210,26 @@ def _generate_data(request,
experiment,
output_file=output_file,
**kwargs)
- _convert_options(data)
+ _process_interactive_params(data)
return data
-def _convert_options(data):
- """Convert interactive options to explicit text/value dicts."""
+def _process_interactive_params(data):
if 'interactive' in data:
+ _convert_options(data)
for param in data['interactive']:
- if 'options' in param and isinstance(param['options'][0], str):
- param['options'] = _convert_options_strings(param['options'])
- elif 'options' in param and isinstance(
- param['options'][0], collections.Sequence):
- param['options'] = _convert_options_sequences(param['options'])
+ if 'type' not in param:
+ param['type'] = _infer_interactive_param_type(param)
+
+
+def _convert_options(data):
+ """Convert interactive options to explicit text/value dicts."""
+ for param in data['interactive']:
+ if 'options' in param and isinstance(param['options'][0], str):
+ param['options'] = _convert_options_strings(param['options'])
+ elif 'options' in param and isinstance(
+ param['options'][0], collections.Sequence):
+ param['options'] = _convert_options_sequences(param['options'])
def _convert_options_strings(options):
@@ -233,6 +240,18 @@ def _convert_options_sequences(options):
return [{"text": o[0], "value": o[1]} for o in options]
+def _infer_interactive_param_type(param):
+ v = param['value']
+ if isinstance(v, float):
+ return "float"
+ elif isinstance(v, int):
+ return "integer"
+ elif isinstance(v, str):
+ return "string"
+ elif isinstance(v, bool):
+ return "boolean"
+
+
def _convert_params_to_type(output_view_provider, params):
method_sig = inspect.signature(output_view_provider.generate_data)
method_params = method_sig.parameters
@@ -242,8 +261,12 @@ def _convert_params_to_type(output_view_provider, params):
method_params[k].default is not None):
# TODO: handle lists?
# Handle boolean and numeric values, converting from string
- if type(method_params[k].default) is not str:
- params[k] = json.loads(v)
+ if isinstance(method_params[k].default, bool):
+ params[k] = v == "true"
+ elif isinstance(method_params[k].default, float):
+ params[k] = float(v)
+ elif isinstance(method_params[k].default, int):
+ params[k] = int(v)
else:
params[k] = v
return params
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterRangeWidget.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterRangeWidget.vue
new file mode 100644
index 0000000..8e8e9d2
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterRangeWidget.vue
@@ -0,0 +1,59 @@
+<template>
+ <div>
+ <b-form-input
+ ref="rangeInput"
+ type="range"
+ :value="value"
+ :min="parameter.min"
+ :max="parameter.max"
+ :step="parameter.step || 'any'"
+ @input="updateValue"
+ @mouseup="mouseUp"
+ @keyup="keyUp"
+ />
+ <div>Value: {{ currentValue }}</div>
+ </div>
+</template>
+
+<script>
+export default {
+ name: "interactive-parameter-range-widget",
+ props: {
+ value: {
+ type: Number,
+ required: true
+ },
+ parameter: {
+ type: Object
+ }
+ },
+ data() {
+ return {
+ currentValue: parseFloat(this.value)
+ };
+ },
+ computed: {
+ disabled() {
+ return this.currentValue === this.initialValue;
+ },
+ initialValue() {
+ return parseFloat(this.value);
+ }
+ },
+ methods: {
+ updateValue(newValue) {
+ this.currentValue = parseFloat(newValue);
+ },
+ submit() {
+ this.$emit("input", this.currentValue);
+ },
+ mouseUp() {
+ this.$refs.rangeInput.blur();
+ if (!this.disabled) {
+ this.submit();
+ }
+ },
+ keyUp() {}
+ }
+};
+</script>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterStepperWidget.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterStepperWidget.vue
new file mode 100644
index 0000000..a048f1e
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterStepperWidget.vue
@@ -0,0 +1,58 @@
+<template>
+ <b-input-group>
+ <b-form-input
+ ref="textInput"
+ type="number"
+ :value="value"
+ :min="parameter.min"
+ :max="parameter.max"
+ :step="parameter.step || 'any'"
+ @input="updateValue"
+ @keydown.native.enter="enterKeyPressed"
+ />
+ <b-input-group-append>
+ <b-button variant="primary" :disabled="disabled" @click="submit"
+ >Submit</b-button
+ >
+ </b-input-group-append>
+ </b-input-group>
+</template>
+
+<script>
+export default {
+ name: "interactive-parameter-stepper-widget",
+ props: {
+ value: {
+ type: Number,
+ required: true
+ },
+ parameter: {
+ type: Object
+ }
+ },
+ data() {
+ return {
+ currentValue: parseFloat(this.value)
+ };
+ },
+ computed: {
+ disabled() {
+ return this.currentValue === parseFloat(this.value);
+ }
+ },
+ methods: {
+ updateValue(newValue) {
+ this.currentValue = parseFloat(newValue);
+ },
+ submit() {
+ this.$emit("input", this.currentValue);
+ },
+ enterKeyPressed() {
+ if (!this.disabled) {
+ this.$refs.textInput.blur();
+ this.submit();
+ }
+ }
+ }
+};
+</script>
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterWidgetContainer.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterWidgetContainer.vue
index 8886a5a..c9d21c1 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterWidgetContainer.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/components/experiment/output-displays/interactive-parameters/InteractiveParameterWidgetContainer.vue
@@ -1,5 +1,6 @@
<template>
- <compoment :is="widgetComponent"
+ <compoment
+ :is="widgetComponent"
:value="parameter.value"
:parameter="parameter"
@input="$emit('input', $event)"
@@ -8,7 +9,9 @@
<script>
import InteractiveParameterCheckboxWidget from "./InteractiveParameterCheckboxWidget";
+import InteractiveParameterRangeWidget from "./InteractiveParameterRangeWidget.vue";
import InteractiveParameterSelectWidget from "./InteractiveParameterSelectWidget";
+import InteractiveParameterStepperWidget from "./InteractiveParameterStepperWidget.vue";
import InteractiveParameterTextInputWidget from "./InteractiveParameterTextInputWidget";
export default {
@@ -21,16 +24,36 @@ export default {
},
components: {
InteractiveParameterCheckboxWidget,
- InteractiveParameterSelectWidget
+ InteractiveParameterRangeWidget,
+ InteractiveParameterSelectWidget,
+ InteractiveParameterStepperWidget,
+ InteractiveParameterTextInputWidget
},
computed: {
widgetComponent() {
if (this.parameter.options) {
return InteractiveParameterSelectWidget;
- } else if (typeof this.parameter.value === "boolean" || (this.parameter.widget && this.parameter.widget === 'checkbox')) {
+ } else if (
+ this.parameter.type === "boolean" ||
+ (this.parameter.widget && this.parameter.widget === "checkbox")
+ ) {
return InteractiveParameterCheckboxWidget;
- } else if (typeof this.parameter.value === "string" || (this.parameter.widget && this.parameter.widget === 'textinput')) {
+ } else if (
+ this.parameter.type === "string" ||
+ (this.parameter.widget && this.parameter.widget === "textinput")
+ ) {
return InteractiveParameterTextInputWidget;
+ } else if (
+ this.parameter.type === "float" &&
+ "min" in this.parameter &&
+ "max" in this.parameter
+ ) {
+ return InteractiveParameterRangeWidget;
+ } else if (
+ this.parameter.type === "float" ||
+ (this.parameter.widget && this.parameter.widget === "stepper")
+ ) {
+ return InteractiveParameterStepperWidget;
} else {
return null;
}
@@ -38,4 +61,3 @@ export default {
}
};
</script>
-