Merge branch 'master' into 14643-re-run-workflow
[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 WorkflowResoruceDefinition {
15     cwlVersion: string;
16     graph?: Array<Workflow | CommandLineTool>;
17     $graph?: Array<Workflow | CommandLineTool>;
18 }
19 export interface Workflow {
20     class: 'Workflow';
21     doc?: string;
22     id?: string;
23     inputs: CommandInputParameter[];
24     outputs: any[];
25     steps: any[];
26 }
27
28 export interface CommandLineTool {
29     class: 'CommandLineTool';
30     id: string;
31     inputs: CommandInputParameter[];
32     outputs: any[];
33 }
34
35 export type CommandInputParameter =
36     BooleanCommandInputParameter |
37     IntCommandInputParameter |
38     LongCommandInputParameter |
39     FloatCommandInputParameter |
40     DoubleCommandInputParameter |
41     StringCommandInputParameter |
42     FileCommandInputParameter |
43     DirectoryCommandInputParameter |
44     StringArrayCommandInputParameter |
45     IntArrayCommandInputParameter |
46     FloatArrayCommandInputParameter |
47     FileArrayCommandInputParameter |
48     DirectoryArrayCommandInputParameter |
49     EnumCommandInputParameter;
50
51 export enum CWLType {
52     NULL = 'null',
53     BOOLEAN = 'boolean',
54     INT = 'int',
55     LONG = 'long',
56     FLOAT = 'float',
57     DOUBLE = 'double',
58     STRING = 'string',
59     FILE = 'File',
60     DIRECTORY = 'Directory',
61 }
62
63 export interface CommandInputEnumSchema {
64     symbols: string[];
65     type: 'enum';
66     label?: string;
67     name?: string;
68 }
69
70 export interface CommandInputArraySchema<ItemType> {
71     items: ItemType;
72     type: 'array';
73     label?: string;
74 }
75
76 export interface File {
77     class: CWLType.FILE;
78     location?: string;
79     path?: string;
80     basename?: string;
81 }
82
83 export interface Directory {
84     class: CWLType.DIRECTORY;
85     location?: string;
86     path?: string;
87     basename?: string;
88 }
89
90 export interface GenericCommandInputParameter<Type, Value> {
91     id: string;
92     label?: string;
93     doc?: string | string[];
94     default?: Value;
95     type?: Type | Array<Type | CWLType.NULL>;
96     value?: Value;
97     disabled?: boolean;
98 }
99 export type GenericArrayCommandInputParameter<Type, Value> = GenericCommandInputParameter<CommandInputArraySchema<Type>, Value[]>;
100
101 export type BooleanCommandInputParameter = GenericCommandInputParameter<CWLType.BOOLEAN, boolean>;
102 export type IntCommandInputParameter = GenericCommandInputParameter<CWLType.INT, number>;
103 export type LongCommandInputParameter = GenericCommandInputParameter<CWLType.LONG, number>;
104 export type FloatCommandInputParameter = GenericCommandInputParameter<CWLType.FLOAT, number>;
105 export type DoubleCommandInputParameter = GenericCommandInputParameter<CWLType.DOUBLE, number>;
106 export type StringCommandInputParameter = GenericCommandInputParameter<CWLType.STRING, string>;
107 export type FileCommandInputParameter = GenericCommandInputParameter<CWLType.FILE, File>;
108 export type DirectoryCommandInputParameter = GenericCommandInputParameter<CWLType.DIRECTORY, Directory>;
109 export type EnumCommandInputParameter = GenericCommandInputParameter<CommandInputEnumSchema, string>;
110
111 export type StringArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.STRING, string>;
112 export type IntArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.INT, string>;
113 export type FloatArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.FLOAT, string>;
114 export type FileArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.FILE, File>;
115 export type DirectoryArrayCommandInputParameter = GenericArrayCommandInputParameter<CWLType.DIRECTORY, Directory>;
116
117 export type WorkflowInputsData = {
118     [key: string]: boolean | number | string | File | Directory;
119 };
120 export const parseWorkflowDefinition = (workflow: WorkflowResource): WorkflowResoruceDefinition => {
121     const definition = safeLoad(workflow.definition);
122     return definition;
123 };
124
125 export const getWorkflowInputs = (workflowDefinition: WorkflowResoruceDefinition) => {
126     if (workflowDefinition.graph) {
127         const mainWorkflow = workflowDefinition.graph.find(item => item.class === 'Workflow' && item.id === '#main');
128         return mainWorkflow
129             ? mainWorkflow.inputs
130             : undefined;
131     } else {
132         const mainWorkflow = workflowDefinition.$graph!.find(item => item.class === 'Workflow' && item.id === '#main');
133         return mainWorkflow
134             ? mainWorkflow.inputs
135             : undefined;
136     }
137 };
138
139 export const getInputLabel = (input: CommandInputParameter) => {
140     return `${input.label || input.id}`;
141 };
142
143 export const isRequiredInput = ({ type }: CommandInputParameter) => {
144     if (type instanceof Array) {
145         for (const t of type) {
146             if (t === CWLType.NULL) {
147                 return false;
148             }
149         }
150     }
151     return true;
152 };
153
154 export const isPrimitiveOfType = (input: GenericCommandInputParameter<any, any>, type: CWLType) =>
155     input.type instanceof Array
156         ? input.type.indexOf(type) > -1
157         : input.type === type;
158
159 export const isArrayOfType = (input: GenericCommandInputParameter<any, any>, type: CWLType) =>
160     typeof input.type === 'object' &&
161         input.type.type === 'array'
162         ? input.type.items === type
163         : false;
164
165 export const stringifyInputType = ({ type }: CommandInputParameter) => {
166     if (typeof type === 'string') {
167         return type;
168     } else if (type instanceof Array) {
169         return type.join(' | ');
170     } else if (typeof type === 'object') {
171         if (type.type === 'enum') {
172             return 'enum';
173         } else if (type.type === 'array') {
174             return `${type.items}[]`;
175         } else {
176             return 'unknown';
177         }
178     } else {
179         return 'unknown';
180     }
181 };