Merge branch '16583-intermediate-collections' refs #16583
[arvados-workbench2.git] / src / models / workflow.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { Resource, ResourceKind } from "./resource";
6 import { safeLoad } from 'js-yaml';
7
8 export interface WorkflowResource extends Resource {
9     kind: ResourceKind.WORKFLOW;
10     name: string;
11     description: string;
12     definition: string;
13 }
14 export interface WorkflowResourceDefinition {
15     cwlVersion: string;
16     $graph?: Array<Workflow | CommandLineTool>;
17 }
18 export interface Workflow {
19     class: 'Workflow';
20     doc?: string;
21     id?: string;
22     inputs: CommandInputParameter[];
23     outputs: any[];
24     steps: any[];
25     hints?: ProcessRequirement[];
26 }
27
28 export interface CommandLineTool {
29     class: 'CommandLineTool';
30     id: string;
31     inputs: CommandInputParameter[];
32     outputs: any[];
33     hints?: ProcessRequirement[];
34 }
35
36 export type ProcessRequirement = GenericProcessRequirement | WorkflowRunnerResources;
37
38 export interface GenericProcessRequirement {
39     class: string;
40 }
41
42 export interface WorkflowRunnerResources {
43     class: 'http://arvados.org/cwl#WorkflowRunnerResources';
44     ramMin?: number;
45     coresMin?: number;
46     keep_cache?: number;
47     acrContainerImage?: string;
48 }
49
50 export type CommandInputParameter =
51     BooleanCommandInputParameter |
52     IntCommandInputParameter |
53     LongCommandInputParameter |
54     FloatCommandInputParameter |
55     DoubleCommandInputParameter |
56     StringCommandInputParameter |
57     FileCommandInputParameter |
58     DirectoryCommandInputParameter |
59     StringArrayCommandInputParameter |
60     IntArrayCommandInputParameter |
61     FloatArrayCommandInputParameter |
62     FileArrayCommandInputParameter |
63     DirectoryArrayCommandInputParameter |
64     EnumCommandInputParameter;
65
66 export enum CWLType {
67     NULL = 'null',
68     BOOLEAN = 'boolean',
69     INT = 'int',
70     LONG = 'long',
71     FLOAT = 'float',
72     DOUBLE = 'double',
73     STRING = 'string',
74     FILE = 'File',
75     DIRECTORY = 'Directory',
76 }
77
78 export interface CommandInputEnumSchema {
79     symbols: string[];
80     type: 'enum';
81     label?: string;
82     name?: string;
83 }
84
85 export interface CommandInputArraySchema<ItemType> {
86     items: ItemType;
87     type: 'array';
88     label?: string;
89 }
90
91 export interface File {
92     class: CWLType.FILE;
93     location?: string;
94     path?: string;
95     basename?: string;
96 }
97
98 export interface Directory {
99     class: CWLType.DIRECTORY;
100     location?: string;
101     path?: string;
102     basename?: string;
103 }
104
105 export interface GenericCommandInputParameter<Type, Value> {
106     id: string;
107     label?: string;
108     doc?: string | string[];
109     default?: Value;
110     type?: Type | Array<Type | CWLType.NULL>;
111     value?: Value;
112     disabled?: boolean;
113 }
114 export type GenericArrayCommandInputParameter<Type, Value> = GenericCommandInputParameter<CommandInputArraySchema<Type>, Value[]>;
115
116 export type BooleanCommandInputParameter = GenericCommandInputParameter<CWLType.BOOLEAN, boolean>;
117 export type IntCommandInputParameter = GenericCommandInputParameter<CWLType.INT, number>;
118 export type LongCommandInputParameter = GenericCommandInputParameter<CWLType.LONG, number>;
119 export type FloatCommandInputParameter = GenericCommandInputParameter<CWLType.FLOAT, number>;
120 export type DoubleCommandInputParameter = GenericCommandInputParameter<CWLType.DOUBLE, number>;
121 export type StringCommandInputParameter = GenericCommandInputParameter<CWLType.STRING, string>;
122 export type FileCommandInputParameter = GenericCommandInputParameter<CWLType.FILE, File>;
123 export type DirectoryCommandInputParameter = GenericCommandInputParameter<CWLType.DIRECTORY, Directory>;
124 export type EnumCommandInputParameter = GenericCommandInputParameter<CommandInputEnumSchema, string>;
125
126 export type StringArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.STRING, string>;
127 export type IntArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.INT, string>;
128 export type FloatArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.FLOAT, string>;
129 export type FileArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.FILE, File>;
130 export type DirectoryArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.DIRECTORY, Directory>;
131
132 export type WorkflowInputsData = {
133     [key: string]: boolean | number | string | File | Directory;
134 };
135 export const parseWorkflowDefinition = (workflow: WorkflowResource): WorkflowResourceDefinition => {
136     const definition = safeLoad(workflow.definition);
137     return definition;
138 };
139
140 export const getWorkflow = (workflowDefinition: WorkflowResourceDefinition) => {
141     if (!workflowDefinition.$graph) { return undefined; }
142     const mainWorkflow = workflowDefinition.$graph.find(item => item.class === 'Workflow' && item.id === '#main');
143     return mainWorkflow
144         ? mainWorkflow
145         : undefined;
146 };
147
148 export const getWorkflowInputs = (workflowDefinition: WorkflowResourceDefinition) => {
149     if (!workflowDefinition) { return undefined; }
150     return getWorkflow(workflowDefinition)
151         ? getWorkflow(workflowDefinition)!.inputs
152         : undefined;
153 };
154
155 export const getInputLabel = (input: CommandInputParameter) => {
156     return `${input.label || input.id}`;
157 };
158
159 export const isRequiredInput = ({ type }: CommandInputParameter) => {
160     if (type instanceof Array) {
161         for (const t of type) {
162             if (t === CWLType.NULL) {
163                 return false;
164             }
165         }
166     }
167     return true;
168 };
169
170 export const isPrimitiveOfType = (input: GenericCommandInputParameter<any, any>, type: CWLType) =>
171     input.type instanceof Array
172         ? input.type.indexOf(type) > -1
173         : input.type === type;
174
175 export const isArrayOfType = (input: GenericCommandInputParameter<any, any>, type: CWLType) =>
176     typeof input.type === 'object' &&
177         input.type.type === 'array'
178         ? input.type.items === type
179         : false;
180
181 export const stringifyInputType = ({ type }: CommandInputParameter) => {
182     if (typeof type === 'string') {
183         return type;
184     } else if (type instanceof Array) {
185         return type.join(' | ');
186     } else if (typeof type === 'object') {
187         if (type.type === 'enum') {
188             return 'enum';
189         } else if (type.type === 'array') {
190             return `${type.items}[]`;
191         } else {
192             return 'unknown';
193         }
194     } else {
195         return 'unknown';
196     }
197 };