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