Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplified Workflow Run Form #9151

Merged
merged 1 commit into from
Aug 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions client/src/components/Workflow/Run/WorkflowRun.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,22 @@
<workflow-run-form
ref="runform"
:model="model"
v-if="!simpleForm"
:set-run-button-status="setRunButtonStatus"
@submissionSuccess="handleInvocations"
/>
<div v-else>
<workflow-run-form-simple
ref="runform"
:model="model"
:set-run-button-status="setRunButtonStatus"
:target-history="simpleFormTargetHistory"
:use-job-cache="simpleFormUseJobCache"
@submissionSuccess="handleInvocations"
/>
<!-- Options to default one way or the other, disable if admins want, etc.. -->
<a href="#" @click="showAdvanced">Expand to full workflow form.</a>
</div>
</div>
</span>
</span>
Expand All @@ -58,6 +71,7 @@ import WaitButton from "components/WaitButton";
import LoadingSpan from "components/LoadingSpan";
import WorkflowRunSuccess from "./WorkflowRunSuccess";
import WorkflowRunForm from "./WorkflowRunForm";
import WorkflowRunFormSimple from "./WorkflowRunFormSimple";
import { WorkflowRunModel } from "./model.js";
import { errorMessageAsString } from "utils/simple-error";

Expand All @@ -67,9 +81,22 @@ export default {
WaitButton,
WorkflowRunSuccess,
WorkflowRunForm,
WorkflowRunFormSimple,
},
props: {
workflowId: { type: String },
preferSimpleForm: {
type: Boolean,
default: false,
},
simpleFormTargetHistory: {
type: String,
default: "current",
},
simpleFormUseJobCache: {
type: Boolean,
default: false,
},
},
data() {
return {
Expand All @@ -83,20 +110,50 @@ export default {
runButtonWaitText: "",
runButtonPercentage: -1,
invocations: null,
simpleForm: null,
model: null,
};
},
created() {
getRunData(this.workflowId)
.then((runData) => {
const model = new WorkflowRunModel(runData);
let simpleForm = this.preferSimpleForm;
if (simpleForm) {
// These only work with PJA - the API doesn't evaluate them at
// all outside that context currently. The main workflow form renders
// these dynamically and takes care of all the validation and setup details
// on the frontend. If these are implemented on the backend at some
// point this restriction can be lifted.
if (model.hasReplacementParametersInToolForm) {
console.log("cannot render simple workflow form - has ${} values in tool steps");
simpleForm = false;
}
// If there are required parameters in a tool form (a disconnected runtime
// input), we have to render the tool form steps and cannot use the
// simplified tool form.
if (model.hasOpenToolSteps) {
console.log(
"cannot render simple workflow form - one or more tools have disconnected runtime inputs"
);
simpleForm = false;
}
// Just render the whole form for resource request parameters (kind of
// niche - I'm not sure anyone is using these currently anyway).
if (model.hasWorkflowResourceParameters) {
console.log(`Cannot render simple workflow form - workflow resource parameters are configured`);
simpleForm = false;
}
}
this.simpleForm = simpleForm;
this.model = model;
this.hasUpgradeMessages = model.hasUpgradeMessages;
this.hasStepVersionChanges = model.hasStepVersionChanges;
this.workflowName = this.model.name;
this.loading = false;
})
.catch((response) => {
console.log(response);
this.error = errorMessageAsString(response);
});
},
Expand All @@ -112,6 +169,9 @@ export default {
handleInvocations(invocations) {
this.invocations = invocations;
},
showAdvanced() {
this.simpleForm = false;
},
},
};
</script>
114 changes: 114 additions & 0 deletions client/src/components/Workflow/Run/WorkflowRunFormSimple.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<template>
<div ref="form"></div>
</template>

<script>
import Form from "mvc/form/form-view";
import { invokeWorkflow } from "./services";

export default {
props: {
model: {
type: Object,
required: true,
},
setRunButtonStatus: {
type: Function,
required: true,
},
targetHistory: {
type: String,
default: "current",
},
useJobCache: {
type: Boolean,
default: false,
},
},
data() {
return {
form: null,
inputTypes: {},
};
},
computed: {},
created() {
this.form = new Form(this.formDefinition());
this.$nextTick(() => {
const el = this.$refs["form"];
el.appendChild(this.form.$el[0]);
});
},
methods: {
formDefinition() {
const inputs = [];

// Add workflow parameters.
Object.values(this.model.wpInputs).forEach((input) => {
const inputCopy = Object.assign({}, input);
// do we want to keep the color if we're not showing steps?
inputCopy.color = undefined;
inputs.push(inputCopy);
this.inputTypes[inputCopy.name] = "replacement_parameter";
});

// Add actual input modules.
this.model.steps.forEach((step, i) => {
const is_input =
["data_input", "data_collection_input", "parameter_input"].indexOf(step.step_type) != -1;
if (!is_input) {
return;
}

const stepName = new String(step.step_index);
const stepLabel = step.step_label || new String(step.step_index + 1);
const help = step.annotation;
const longFormInput = step.inputs[0];
const stepAsInput = Object.assign({}, longFormInput, { name: stepName, help: help, label: stepLabel });
// disable collection mapping...
stepAsInput.flavor = "module";
inputs.push(stepAsInput);
this.inputTypes[stepName] = step.step_type;
});

const def = {
inputs: inputs,
};
return def;
},
execute() {
const replacementParams = {};
const inputs = {};
const formData = this.form.data.create();
for (const inputName in formData) {
const value = formData[inputName];
const inputType = this.inputTypes[inputName];
if (inputType == "replacement_parameter") {
replacementParams[inputName] = value;
} else if (inputType == "data_input" || inputType == "data_collection_input") {
inputs[inputName] = value;
}
}
const data = {
replacement_dict: replacementParams,
inputs: inputs,
inputs_by: "step_index",
batch: true,
use_cached_job: this.useJobCache,
};
if (this.targetHistory == "current") {
data.history_id = this.model.historyId;
} else {
data.new_history_name = this.model.name;
}
invokeWorkflow(this.model.workflowId, data)
.then((invocations) => {
this.$emit("submissionSuccess", invocations);
})
.catch((error) => {
console.log(error);
});
},
},
};
</script>
9 changes: 8 additions & 1 deletion client/src/components/Workflow/Run/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@ export class WorkflowRunModel {
this.runData = runData;
this.name = runData.name;
this.workflowResourceParameters = runData.workflow_resource_parameters;
this.hasWorkflowResourceParameters = !_.isEmpty(this.workflowResourceParameters);
this.historyId = runData.history_id;
this.workflowId = runData.id;

this.hasUpgradeMessages = runData.has_upgrade_messages;
this.hasStepVersionChanges = runData.step_version_changes && runData.step_version_changes.length > 0;
this.hasStepVersionChanges = !_.isEmpty(runData.step_version_changes);

this.steps = [];
this.links = [];
this.parms = [];
this.wpInputs = {};
let hasOpenToolSteps = false;
let hasReplacementParametersInToolForm = false;

_.each(runData.steps, (step, i) => {
var icon = WorkflowIcons[step.step_type];
Expand Down Expand Up @@ -130,6 +133,7 @@ export class WorkflowRunModel {
_.each(this.steps, (step, i) => {
_.each(this.parms[i], (input, name) => {
_handleWorkflowParameter(input.value, (wp_input) => {
hasReplacementParametersInToolForm = true;
wp_input.links.push(step);
input.wp_linked = true;
input.type = "text";
Expand Down Expand Up @@ -166,6 +170,7 @@ export class WorkflowRunModel {
(input.value && input.value.__class__ == "RuntimeValue" && !input.step_linked)
) {
step.collapsed = false;
hasOpenToolSteps = true;
}
if (is_runtime_value) {
input.value = null;
Expand All @@ -180,6 +185,8 @@ export class WorkflowRunModel {
});
}
});
this.hasOpenToolSteps = hasOpenToolSteps;
this.hasReplacementParametersInToolForm = hasReplacementParametersInToolForm;
}
}

Expand Down
16 changes: 15 additions & 1 deletion client/src/entry/analysis/AnalysisRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,20 @@ export const getAnalysisRouter = (Galaxy) =>
/** load workflow by its url in run mode */
_loadWorkflow: function () {
const workflowId = QueryStringParsing.get("id");
this._display_vue_helper(WorkflowRun, { workflowId: workflowId }, "workflow");
const Galaxy = getGalaxyInstance();
let preferSimpleForm = Galaxy.config.simplified_workflow_run_ui == "prefer";
const preferSimpleFormOverride = QueryStringParsing.get("simplified_workflow_run_ui");
if (preferSimpleFormOverride == "prefer") {
preferSimpleForm = true;
}
const simpleFormTargetHistory = Galaxy.config.simplified_workflow_run_ui_target_history;
const simpleFormUseJobCache = Galaxy.config.simplified_workflow_run_ui_job_cache == "on";
const props = {
workflowId,
preferSimpleForm,
simpleFormTargetHistory,
simpleFormUseJobCache,
};
this._display_vue_helper(WorkflowRun, props, "workflow");
},
});
3 changes: 3 additions & 0 deletions lib/galaxy/managers/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ def _use_config(config, key, **context):
'ga_code' : _use_config,
'enable_unique_workflow_defaults' : _use_config,
'enable_beta_markdown_export' : _use_config,
'simplified_workflow_run_ui' : _use_config,
'simplified_workflow_run_ui_target_history': _use_config,
'simplified_workflow_run_ui_job_cache': _use_config,
'has_user_tool_filters' : _defaults_to(False),
# TODO: is there no 'correct' way to get an api url? controller='api', action='tools' is a hack
# at any rate: the following works with path_prefix but is still brittle
Expand Down
Loading