Run from code
You can start a workflow from code and, if the top-level configuration defines an
onReturn hook, receive a return value when the user
exits the workflow with the Confirm data button (the check icon in the
toolbar). On a regular close, the workflow resolves to undefined.
The result flows like this:
- The user clicks Confirm data.
- The
onReturnhandler runs and callscontroller.returnResult(value). - Your awaited
startWorkflow(...)resolves to thatvalue.
Basic usage
import {startWorkflow} from '@datagrok-libraries/compute-api';
const result = await startWorkflow<MyReturnShape>('SomePackage:SomeWorkflow', '1.0', {});
nqName (first argument) is the workflow
provider's package:function identifier.
version is passed to the provider in its params, and selects the
configuration version the provider returns. It is usually the configuration's
version, or one of the versions the provider's
meta.versions annotation lists. The third argument is the initial
PipelineInstanceConfig; pass {} to start
with the provider's defaults.
With initial configuration
For dynamic workflows you can pre-populate the initial step list and per-step
values by passing a PipelineInstanceConfig as the third argument. LSP fills
in the recursive field shape.
import {startWorkflow} from '@datagrok-libraries/compute-api';
import type {PipelineInstanceConfig} from '@datagrok-libraries/compute-api';
const instanceConfig: PipelineInstanceConfig = {
id: 'some_workflow',
steps: [{
id: 'load',
initialValues: {deviceClass: 'Bioreactor Class'},
inputRestrictions: {deviceClass: 'disabled'},
}],
};
const result = await startWorkflow<MyReturnShape>(
'SomePackage:SomeWorkflow',
'1.0',
instanceConfig,
);
initialValues and inputRestrictions follow the same semantics as the
script node fields of the same name. See
Consistency for the meaning of restriction values.
initialValues of a script step may also hold output values: a step with
any output value starts as run, so links that write into it mark its
inputs inconsistent instead of changing them.
A workflow entry without steps gets the defaults from its configuration:
the steps of a static workflow or the initialSteps of a dynamic one,
expanded all the way down. Pass steps: [] for an empty workflow. A
listed steps array is built as given, for static workflows too.
On a workflow entry, initialValues fills its
states, and skipOnInit: true skips its
init hook:
const instanceConfig: PipelineInstanceConfig = {
id: 'some_workflow',
initialValues: {startedBy: 'batch import'},
skipOnInit: true,
steps: [{id: 'load'}],
};
Run without UI
runWorkflow runs a workflow without opening it, for example to read its
outputs in another app or to check a workflow in a test. It takes the same
arguments as startWorkflow:
import {runWorkflow, saveWorkflowRun} from '@datagrok-libraries/compute-api';
const result = await runWorkflow('SomePackage:SomeWorkflow', '1.0', {
id: 'some_workflow',
steps: [{id: 'load', initialValues: {deviceClass: 'Bioreactor Class'}}],
});
The workflow is created from the initial configuration, as in the editor. If a
step that is ready to run has validation errors, nothing runs. Otherwise every
step that can run runs in order, as Run ready steps does. A step that waits
for earlier steps is checked once they have run, and is skipped if it still has
errors. Each step runs only after its validators have checked its inputs, and
validator debounce doesn't delay the run.
The result holds:
isRun:falsewhen nothing ran because of validation errors.state: the workflow tree in the shape of the initial configuration. Each step has itsinitialValues, which hold the inputs and, once the step has run, the outputs. It also has itsstatusas the tree shows it,isOutputOutdated,runError, and itsvalidationsandconsistencyby input. Each workflow has thevalidationsof its workflow validators.summary: one row per workflow and step, as in the summary of a tree export: errors, warnings and inconsistent inputs, and for a workflow the counts of failed and outdated steps below it.
const steps = 'steps' in result.state ? result.state.steps : [result.state];
const load = steps.find((step) => step.id === 'load');
const table = load?.initialValues.table;
Tables in the initial configuration are copied, so a step that edits a table does not change yours.
state is itself an initial configuration: passed to runWorkflow or
startWorkflow, it starts the workflow with the steps that ran already run.
A step with outputs in initialValues is not run again, even when you change
its inputs; remove its outputs, and those of the steps after it that use
them, to run them again.
The run is not saved. saveWorkflowRun saves state to history as a new run,
the way Duplicate copies a workflow, and the saved run opens in the
editor. A step that failed is saved as not run, without its error.
const run = await saveWorkflowRun('SomePackage:SomeWorkflow', '1.0', result.state, {title: 'Batch 7'});
Packages that don't use compute-api can call the Compute2:RunWorkflow and
Compute2:SaveWorkflowRun functions with the same parameters.
A step input that a link writes takes the linked value: the link replaces the
value given in initialValues without a warning, since the step hasn't run.
Pass values only for inputs that no link writes.