[arvados-workbench2] updated: 2.4.0-162-g4024cf50
git repository hosting
git at public.arvados.org
Tue Jul 19 14:12:44 UTC 2022
Summary of changes:
.licenseignore | 2 +
cypress/fixtures/files/cat.png | Bin 0 -> 512704 bytes
cypress/fixtures/webdav-propfind-outputs.xml | 50 ++
cypress/integration/process.spec.js | 623 +++++++++++++++++++++++++
src/models/workflow.ts | 10 +-
src/store/processes/processes-actions.ts | 18 +-
src/views/process-panel/process-io-card.tsx | 23 +-
src/views/process-panel/process-panel-root.tsx | 40 +-
8 files changed, 735 insertions(+), 31 deletions(-)
create mode 100644 cypress/fixtures/files/cat.png
create mode 100644 cypress/fixtures/webdav-propfind-outputs.xml
via 4024cf50be7d0f9d543f74c8369af18855b2645b (commit)
via 7f1fc8720518f4f712d49def31b76b6af1b6ceab (commit)
from 387443bdebe2fb106e844a38823ba3f538b9bd70 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit 4024cf50be7d0f9d543f74c8369af18855b2645b
Author: Stephen Smith <stephen at curii.com>
Date: Tue Jul 19 10:05:50 2022 -0400
16073: Add process io panel cypress tests
Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen at curii.com>
diff --git a/.licenseignore b/.licenseignore
index 7622a594..2440cc33 100644
--- a/.licenseignore
+++ b/.licenseignore
@@ -15,6 +15,8 @@ public/*
src/lib/cwl-svg/*
tools/arvados_config.yml
cypress/fixtures/files/5mb.bin
+cypress/fixtures/files/cat.png
+cypress/fixtures/webdav-propfind-outputs.xml
.yarn/releases/*
package.json
yarn.lock
diff --git a/cypress/fixtures/files/cat.png b/cypress/fixtures/files/cat.png
new file mode 100644
index 00000000..6ebc4ba1
Binary files /dev/null and b/cypress/fixtures/files/cat.png differ
diff --git a/cypress/fixtures/webdav-propfind-outputs.xml b/cypress/fixtures/webdav-propfind-outputs.xml
new file mode 100644
index 00000000..4bd16591
--- /dev/null
+++ b/cypress/fixtures/webdav-propfind-outputs.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<D:multistatus xmlns:D="DAV:">
+ <D:response>
+ <D:href>/c=zzzzz-4zz18-zzzzzzzzzzzzzzz/</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:resourcetype>
+ <D:collection xmlns:D="DAV:" />
+ </D:resourcetype>
+ <D:getlastmodified>Mon, 11 Jul 2022 21:54:20 GMT</D:getlastmodified>
+ <D:supportedlock>
+ <D:lockentry xmlns:D="DAV:">
+ <D:lockscope>
+ <D:exclusive />
+ </D:lockscope>
+ <D:locktype>
+ <D:write />
+ </D:locktype>
+ </D:lockentry>
+ </D:supportedlock>
+ <D:displayname></D:displayname>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ <D:response>
+ <D:href>/c=zzzzz-4zz18-zzzzzzzzzzzzzzz/cwl.output.json</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:displayname>cwl.output.json</D:displayname>
+ <D:getcontentlength>141</D:getcontentlength>
+ <D:getlastmodified>Mon, 11 Jul 2022 21:54:20 GMT</D:getlastmodified>
+ <D:supportedlock>
+ <D:lockentry xmlns:D="DAV:">
+ <D:lockscope>
+ <D:exclusive />
+ </D:lockscope>
+ <D:locktype>
+ <D:write />
+ </D:locktype>
+ </D:lockentry>
+ </D:supportedlock>
+ <D:resourcetype></D:resourcetype>
+ <D:getcontenttype>application/json</D:getcontenttype>
+ <D:getetag>"000000000000000000"</D:getetag>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+</D:multistatus>
diff --git a/cypress/integration/process.spec.js b/cypress/integration/process.spec.js
index 55290fa3..b9022a4c 100644
--- a/cypress/integration/process.spec.js
+++ b/cypress/integration/process.spec.js
@@ -274,4 +274,627 @@ describe('Process tests', function() {
.should('contain', 'Process retried 2 times');
});
});
+
+
+ it('displays IO parameters with keep links and previews', function() {
+ const testInputs = [
+ {
+ definition: {
+ "id": "#main/input_file",
+ "label": "Label Description",
+ "type": "File"
+ },
+ input: {
+ "input_file": {
+ "basename": "input1.tar",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+01/input1.tar",
+ "secondaryFiles": [
+ {
+ "basename": "input1-2.txt",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+01/input1-2.txt"
+ },
+ {
+ "basename": "input1-3.txt",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+01/input1-3.txt"
+ },
+ {
+ "basename": "input1-4.txt",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+01/input1-4.txt"
+ }
+ ]
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_dir",
+ "doc": "Doc Description",
+ "type": "Directory"
+ },
+ input: {
+ "input_dir": {
+ "basename": "11111111111111111111111111111111+01",
+ "class": "Directory",
+ "location": "keep:11111111111111111111111111111111+01"
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_bool",
+ "doc": ["Doc desc 1", "Doc desc 2"],
+ "type": "boolean"
+ },
+ input: {
+ "input_bool": true,
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_int",
+ "type": "int"
+ },
+ input: {
+ "input_int": 1,
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_long",
+ "type": "long"
+ },
+ input: {
+ "input_long" : 1,
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_float",
+ "type": "float"
+ },
+ input: {
+ "input_float": 1.5,
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_double",
+ "type": "double"
+ },
+ input: {
+ "input_double": 1.3,
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_string",
+ "type": "string"
+ },
+ input: {
+ "input_string": "Hello World",
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_file_array",
+ "type": {
+ "items": "File",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_file_array": [
+ {
+ "basename": "input2.tar",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+02/input2.tar"
+ },
+ {
+ "basename": "input3.tar",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+03/input3.tar",
+ "secondaryFiles": [
+ {
+ "basename": "input3-2.txt",
+ "class": "File",
+ "location": "keep:00000000000000000000000000000000+03/input3-2.txt"
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_dir_array",
+ "type": {
+ "items": "Directory",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_dir_array": [
+ {
+ "basename": "11111111111111111111111111111111+02",
+ "class": "Directory",
+ "location": "keep:11111111111111111111111111111111+02"
+ },
+ {
+ "basename": "11111111111111111111111111111111+03",
+ "class": "Directory",
+ "location": "keep:11111111111111111111111111111111+03"
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_int_array",
+ "type": {
+ "items": "int",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_int_array": [
+ 1,
+ 3,
+ 5
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_long_array",
+ "type": {
+ "items": "long",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_long_array": [
+ 10,
+ 20
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_float_array",
+ "type": {
+ "items": "float",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_float_array": [
+ 10.2,
+ 10.4,
+ 10.6
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_double_array",
+ "type": {
+ "items": "double",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_double_array": [
+ 20.1,
+ 20.2,
+ 20.3
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/input_string_array",
+ "type": {
+ "items": "string",
+ "type": "array"
+ }
+ },
+ input: {
+ "input_string_array": [
+ "Hello",
+ "World",
+ "!"
+ ]
+ }
+ }
+ ];
+
+ const testOutputs = [
+ {
+ definition: {
+ "id": "#main/output_file",
+ "label": "Label Description",
+ "type": "File"
+ },
+ output: {
+ "output_file": {
+ "basename": "cat.png",
+ "class": "File",
+ "location": "cat.png"
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_file_with_secondary",
+ "doc": "Doc Description",
+ "type": "File"
+ },
+ output: {
+ "output_file_with_secondary": {
+ "basename": "main.dat",
+ "class": "File",
+ "location": "main.dat",
+ "secondaryFiles": [
+ {
+ "basename": "secondary.dat",
+ "class": "File",
+ "location": "secondary.dat"
+ },
+ {
+ "basename": "secondary2.dat",
+ "class": "File",
+ "location": "secondary2.dat"
+ }
+ ]
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_dir",
+ "doc": ["Doc desc 1", "Doc desc 2"],
+ "type": "Directory"
+ },
+ output: {
+ "output_dir": {
+ "basename": "outdir1",
+ "class": "Directory",
+ "location": "outdir1"
+ }
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_bool",
+ "type": "boolean"
+ },
+ output: {
+ "output_bool": true
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_int",
+ "type": "int"
+ },
+ output: {
+ "output_int": 1
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_long",
+ "type": "long"
+ },
+ output: {
+ "output_long": 1
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_float",
+ "type": "float"
+ },
+ output: {
+ "output_float": 100.5
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_double",
+ "type": "double"
+ },
+ output: {
+ "output_double": 100.3
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_string",
+ "type": "string"
+ },
+ output: {
+ "output_string": "Hello output"
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_file_array",
+ "type": {
+ "items": "File",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_file_array": [
+ {
+ "basename": "output2.tar",
+ "class": "File",
+ "location": "output2.tar"
+ },
+ {
+ "basename": "output3.tar",
+ "class": "File",
+ "location": "output3.tar"
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_dir_array",
+ "type": {
+ "items": "Directory",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_dir_array": [
+ {
+ "basename": "outdir2",
+ "class": "Directory",
+ "location": "outdir2"
+ },
+ {
+ "basename": "outdir3",
+ "class": "Directory",
+ "location": "outdir3"
+ }
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_int_array",
+ "type": {
+ "items": "int",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_int_array": [
+ 10,
+ 11,
+ 12
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_long_array",
+ "type": {
+ "items": "long",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_long_array": [
+ 51,
+ 52
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_float_array",
+ "type": {
+ "items": "float",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_float_array": [
+ 100.2,
+ 100.4,
+ 100.6
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_double_array",
+ "type": {
+ "items": "double",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_double_array": [
+ 100.1,
+ 100.2,
+ 100.3
+ ]
+ }
+ },
+ {
+ definition: {
+ "id": "#main/output_string_array",
+ "type": {
+ "items": "string",
+ "type": "array"
+ }
+ },
+ output: {
+ "output_string_array": [
+ "Hello",
+ "Output",
+ "!"
+ ]
+ }
+ }
+ ];
+
+ const verifyParameter = (name, doc, val) => {
+ cy.get('table tr').contains(name).parents('tr').within(() => {
+ doc && cy.contains(doc);
+ val && cy.contains(val);
+ });
+ };
+
+ const verifyImage = (name, url) => {
+ cy.get('table tr').contains(name).parents('tr').within(() => {
+ cy.get('[alt="Inline Preview"]')
+ .should('be.visible')
+ .and(($img) => {
+ expect($img[0].naturalWidth).to.be.greaterThan(0);
+ expect($img[0].src).contains(url);
+ })
+ });
+ }
+
+ // Create output collection for real files
+ cy.createCollection(adminUser.token, {
+ name: `Test collection ${Math.floor(Math.random() * 999999)}`,
+ owner_uuid: activeUser.user.uuid,
+ }).then((testOutputCollection) => {
+ cy.loginAs(activeUser);
+
+ cy.goToPath(`/collections/${testOutputCollection.uuid}`);
+
+ cy.get('[data-cy=upload-button]').click();
+
+ cy.fixture('files/cat.png', 'base64').then(content => {
+ cy.get('[data-cy=drag-and-drop]').upload(content, 'cat.png');
+ cy.get('[data-cy=form-submit-btn]').click();
+ cy.waitForDom().get('[data-cy=form-submit-btn]').should('not.exist');
+ // Confirm final collection state.
+ cy.get('[data-cy=collection-files-panel]')
+ .contains('cat.png').should('exist');
+ });
+
+ cy.getCollection(activeUser.token, testOutputCollection.uuid).as('testOutputCollection');
+ });
+
+ // Get updated collection pdh
+ cy.getAll('@testOutputCollection').then(([testOutputCollection]) => {
+ // Add output uuid and inputs to container request
+ cy.intercept({method: 'GET', url: '**/arvados/v1/container_requests/*'}, (req) => {
+ req.reply((res) => {
+ res.body.output_uuid = testOutputCollection.uuid;
+ res.body.mounts["/var/lib/cwl/cwl.input.json"] = {
+ content: testInputs.map((param) => (param.input)).reduce((acc, val) => (Object.assign(acc, val)), {})
+ };
+ res.body.mounts["/var/lib/cwl/workflow.json"] = {
+ content: {
+ $graph: [{
+ id: "#main",
+ inputs: testInputs.map((input) => (input.definition)),
+ outputs: testOutputs.map((output) => (output.definition))
+ }]
+ }
+ };
+ });
+ });
+
+ // Stub fake output collection
+ cy.intercept({method: 'GET', url: `**/arvados/v1/collections/${testOutputCollection.uuid}*`}, {
+ statusCode: 200,
+ body: {
+ uuid: testOutputCollection.uuid,
+ portable_data_hash: testOutputCollection.portable_data_hash,
+ }
+ });
+
+ // Stub fake output json
+ cy.intercept({method: 'GET', url: '**/c%3Dzzzzz-4zz18-zzzzzzzzzzzzzzz/cwl.output.json'}, {
+ statusCode: 200,
+ body: testOutputs.map((param) => (param.output)).reduce((acc, val) => (Object.assign(acc, val)), {})
+ });
+
+ // Stub webdav response, points to output json
+ cy.intercept({method: 'PROPFIND', url: '*'}, {
+ fixture: 'webdav-propfind-outputs.xml',
+ });
+ });
+
+ createContainerRequest(
+ activeUser,
+ 'test_container_request',
+ 'arvados/jobs',
+ ['echo', 'hello world'],
+ false, 'Committed')
+ .as('containerRequest');
+
+ cy.getAll('@containerRequest', '@testOutputCollection').then(function([containerRequest, testOutputCollection]) {
+ cy.goToPath(`/processes/${containerRequest.uuid}`);
+ cy.get('[data-cy=process-io-card] h6').contains('Inputs')
+ .parents('[data-cy=process-io-card]').within(() => {
+ cy.wait(2000);
+ cy.waitForDom();
+ verifyParameter('input_file', "Label Description", 'keep:00000000000000000000000000000000+01/input1.tar');
+ verifyParameter('input_file', "Label Description", 'keep:00000000000000000000000000000000+01/input1-2.txt');
+ verifyParameter('input_file', "Label Description", 'keep:00000000000000000000000000000000+01/input1-3.txt');
+ verifyParameter('input_file', "Label Description", 'keep:00000000000000000000000000000000+01/input1-4.txt');
+ verifyParameter('input_dir', "Doc Description", 'keep:11111111111111111111111111111111+01/');
+ verifyParameter('input_bool', "Doc desc 1, Doc desc 2", 'true');
+ verifyParameter('input_int', null, '1');
+ verifyParameter('input_long', null, '1');
+ verifyParameter('input_float', null, '1.5');
+ verifyParameter('input_double', null, '1.3');
+ verifyParameter('input_string', null, 'Hello World');
+ verifyParameter('input_file_array', null, 'keep:00000000000000000000000000000000+02/input2.tar');
+ verifyParameter('input_file_array', null, 'keep:00000000000000000000000000000000+03/input3.tar');
+ verifyParameter('input_file_array', null, 'keep:00000000000000000000000000000000+03/input3-2.txt');
+ verifyParameter('input_dir_array', null, 'keep:11111111111111111111111111111111+02/');
+ verifyParameter('input_dir_array', null, 'keep:11111111111111111111111111111111+03/');
+ verifyParameter('input_int_array', null, '1, 3, 5');
+ verifyParameter('input_long_array', null, '10, 20');
+ verifyParameter('input_float_array', null, '10.2, 10.4, 10.6');
+ verifyParameter('input_double_array', null, '20.1, 20.2, 20.3');
+ verifyParameter('input_string_array', null, 'Hello, World, !');
+ });
+ cy.get('[data-cy=process-io-card] h6').contains('Outputs')
+ .parents('[data-cy=process-io-card]').within((ctx) => {
+ cy.get(ctx).scrollIntoView();
+ const outPdh = testOutputCollection.portable_data_hash;
+
+ verifyParameter('output_file', "Label Description", `keep:${outPdh}/cat.png`);
+ verifyImage('output_file', `/c=${outPdh}/cat.png`);
+ verifyParameter('output_file_with_secondary', "Doc Description", `keep:${outPdh}/main.dat`);
+ verifyParameter('output_file_with_secondary', "Doc Description", `keep:${outPdh}/secondary.dat`);
+ verifyParameter('output_file_with_secondary', "Doc Description", `keep:${outPdh}/secondary2.dat`);
+ verifyParameter('output_dir', "Doc desc 1, Doc desc 2", `keep:${outPdh}/outdir1`);
+ verifyParameter('output_bool', null, 'true');
+ verifyParameter('output_int', null, '1');
+ verifyParameter('output_long', null, '1');
+ verifyParameter('output_float', null, '100.5');
+ verifyParameter('output_double', null, '100.3');
+ verifyParameter('output_string', null, 'Hello output');
+ verifyParameter('output_file_array', null, `keep:${outPdh}/output2.tar`);
+ verifyParameter('output_file_array', null, `keep:${outPdh}/output3.tar`);
+ verifyParameter('output_dir_array', null, `keep:${outPdh}/outdir2`);
+ verifyParameter('output_dir_array', null, `keep:${outPdh}/outdir3`);
+ verifyParameter('output_int_array', null, '10, 11, 12');
+ verifyParameter('output_long_array', null, '51, 52');
+ verifyParameter('output_float_array', null, '100.2, 100.4, 100.6');
+ verifyParameter('output_double_array', null, '100.1, 100.2, 100.3');
+ verifyParameter('output_string_array', null, 'Hello, Output, !');
+ });
+ });
+ });
+
});
commit 7f1fc8720518f4f712d49def31b76b6af1b6ceab
Author: Stephen Smith <stephen at curii.com>
Date: Tue Jul 19 10:04:09 2022 -0400
16073: Use workflow output definition fields for output type and doc info
Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen at curii.com>
diff --git a/src/models/workflow.ts b/src/models/workflow.ts
index 12f253ac..e85dce7a 100644
--- a/src/models/workflow.ts
+++ b/src/models/workflow.ts
@@ -4,6 +4,7 @@
import { Resource, ResourceKind } from "./resource";
import { safeLoad } from 'js-yaml';
+import { CommandOutputParameter } from "cwlts/mappings/v1.0/CommandOutputParameter";
export interface WorkflowResource extends Resource {
kind: ResourceKind.WORKFLOW;
@@ -152,11 +153,18 @@ export const getWorkflowInputs = (workflowDefinition: WorkflowResourceDefinition
: undefined;
};
+export const getWorkflowOutputs = (workflowDefinition: WorkflowResourceDefinition) => {
+ if (!workflowDefinition) { return undefined; }
+ return getWorkflow(workflowDefinition)
+ ? getWorkflow(workflowDefinition)!.outputs
+ : undefined;
+};
+
export const getInputLabel = (input: CommandInputParameter) => {
return `${input.label || input.id.split('/').pop()}`;
};
-export const getInputId = (input: CommandInputParameter) => {
+export const getIOParamId = (input: CommandInputParameter | CommandOutputParameter) => {
return `${input.id.split('/').pop()}`;
};
diff --git a/src/store/processes/processes-actions.ts b/src/store/processes/processes-actions.ts
index ddf71e77..3a4c6063 100644
--- a/src/store/processes/processes-actions.ts
+++ b/src/store/processes/processes-actions.ts
@@ -17,9 +17,10 @@ import { initialize } from "redux-form";
import { RUN_PROCESS_BASIC_FORM, RunProcessBasicFormData } from "views/run-process-panel/run-process-basic-form";
import { RunProcessAdvancedFormData, RUN_PROCESS_ADVANCED_FORM } from "views/run-process-panel/run-process-advanced-form";
import { MOUNT_PATH_CWL_WORKFLOW, MOUNT_PATH_CWL_INPUT } from 'models/process';
-import { CommandInputParameter, getWorkflow, getWorkflowInputs } from "models/workflow";
+import { CommandInputParameter, getWorkflow, getWorkflowInputs, getWorkflowOutputs } from "models/workflow";
import { ProjectResource } from "models/project";
import { UserResource } from "models/user";
+import { CommandOutputParameter } from "cwlts/mappings/v1.0/CommandOutputParameter";
export const loadProcess = (containerRequestUuid: string) =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository): Promise<Process> => {
@@ -102,6 +103,21 @@ export const getInputs = (data: any): CommandInputParameter[] => {
) : [];
};
+export const getOutputParameters = (data: any): CommandOutputParameter[] => {
+ if (!data || !data.mounts || !data.mounts[MOUNT_PATH_CWL_WORKFLOW]) { return []; }
+ const outputs = getWorkflowOutputs(data.mounts[MOUNT_PATH_CWL_WORKFLOW].content);
+ return outputs ? outputs.map(
+ (it: any) => (
+ {
+ type: it.type,
+ id: it.id,
+ label: it.label,
+ doc: it.doc
+ }
+ )
+ ) : [];
+};
+
export const openRemoveProcessDialog = (uuid: string) =>
(dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
dispatch(dialogActions.OPEN_DIALOG({
diff --git a/src/views/process-panel/process-io-card.tsx b/src/views/process-panel/process-io-card.tsx
index 6f932187..6426f2bd 100644
--- a/src/views/process-panel/process-io-card.tsx
+++ b/src/views/process-panel/process-io-card.tsx
@@ -115,7 +115,7 @@ export const ProcessIOCard = withStyles(styles)(
setTabState(value);
}
- return <Card className={classes.card}>
+ return <Card className={classes.card} data-cy="process-io-card">
<CardHeader
className={classes.header}
classes={{
@@ -217,8 +217,11 @@ const ProcessIORaw = withStyles(styles)(
</Paper>
);
-// secondaryFiles File[] is not part of CommandOutputParameter so we pass in an extra param
-export const getInputDisplayValue = (auth: AuthState, input: CommandInputParameter | CommandOutputParameter, pdh?: string, secondaryFiles: File[] = []): ProcessIOValue[] => {
+type FileWithSecondaryFiles = {
+ secondaryFiles: File[];
+}
+
+export const getInputDisplayValue = (auth: AuthState, input: CommandInputParameter | CommandOutputParameter, pdh?: string): ProcessIOValue[] => {
switch (true) {
case isPrimitiveOfType(input, CWLType.BOOLEAN):
return [{display: String((input as BooleanCommandInputParameter).value)}];
@@ -236,6 +239,8 @@ export const getInputDisplayValue = (auth: AuthState, input: CommandInputParamet
case isPrimitiveOfType(input, CWLType.FILE):
const mainFile = (input as FileCommandInputParameter).value;
+ // secondaryFiles: File[] is not part of CommandOutputParameter so we cast to access secondaryFiles
+ const secondaryFiles = ((mainFile as unknown) as FileWithSecondaryFiles)?.secondaryFiles || [];
const files = [
...(mainFile ? [mainFile] : []),
...secondaryFiles
@@ -263,7 +268,17 @@ export const getInputDisplayValue = (auth: AuthState, input: CommandInputParamet
return [{ display: ((input as FloatArrayCommandInputParameter).value || []).join(', ') }];
case isArrayOfType(input, CWLType.FILE):
- return ((input as FileArrayCommandInputParameter).value || [])
+ const fileArrayMainFile = ((input as FileArrayCommandInputParameter).value || []);
+ const fileArraySecondaryFiles = fileArrayMainFile.map((file) => (
+ ((file as unknown) as FileWithSecondaryFiles)?.secondaryFiles || []
+ )).reduce((acc: File[], params: File[]) => (acc.concat(params)), []);
+
+ const fileArrayFiles = [
+ ...fileArrayMainFile,
+ ...fileArraySecondaryFiles
+ ];
+
+ return fileArrayFiles
.map(file => fileToProcessIOValue(file, auth, pdh));
case isArrayOfType(input, CWLType.DIRECTORY):
diff --git a/src/views/process-panel/process-panel-root.tsx b/src/views/process-panel/process-panel-root.tsx
index 3447dc2a..950418fb 100644
--- a/src/views/process-panel/process-panel-root.tsx
+++ b/src/views/process-panel/process-panel-root.tsx
@@ -17,8 +17,8 @@ import { getInputDisplayValue, ProcessIOCard, ProcessIOParameter } from './proce
import { getProcessPanelLogs, ProcessLogsPanel } from 'store/process-logs-panel/process-logs-panel';
import { ProcessLogsCard } from './process-log-card';
import { FilterOption } from 'views/process-panel/process-log-form';
-import { getInputs } from 'store/processes/processes-actions';
-import { CommandInputParameter, getInputId } from 'models/workflow';
+import { getInputs, getOutputParameters } from 'store/processes/processes-actions';
+import { CommandInputParameter, getIOParamId } from 'models/workflow';
import { CommandOutputParameter } from 'cwlts/mappings/v1.0/CommandOutputParameter';
import { AuthState } from 'store/auth/auth-reducer';
@@ -83,12 +83,13 @@ export const ProcessPanelRoot = withStyles(styles)(
}, [outputUuid, fetchOutputs]);
React.useEffect(() => {
- if (outputDetails.rawOutputs) {
- setProcessedOutputs(formatOutputData(outputDetails.rawOutputs, outputDetails.pdh, auth));
+ if (outputDetails.rawOutputs && process) {
+ const outputDefinitions = getOutputParameters(process.containerRequest);
+ setProcessedOutputs(formatOutputData(outputDefinitions, outputDetails.rawOutputs, outputDetails.pdh, auth));
} else {
setProcessedOutputs([]);
}
- }, [outputDetails, auth]);
+ }, [outputDetails, auth, process]);
React.useEffect(() => {
if (process) {
@@ -154,33 +155,22 @@ export const ProcessPanelRoot = withStyles(styles)(
const formatInputData = (inputs: CommandInputParameter[], auth: AuthState): ProcessIOParameter[] => {
return inputs.map(input => {
+ const doc = Array.isArray(input.doc) ? input.doc.join(', ') : input.doc;
return {
- id: getInputId(input),
- doc: input.label || "",
+ id: getIOParamId(input),
+ doc: input.label || doc || "",
value: getInputDisplayValue(auth, input)
};
});
};
-const formatOutputData = (rawData: any, pdh: string | undefined, auth: AuthState): ProcessIOParameter[] => {
- if (!rawData) { return []; }
- return Object.keys(rawData).map((id): ProcessIOParameter => {
- const multiple = rawData[id].length > 0;
- const outputArray = multiple ? rawData[id] : [rawData[id]];
+const formatOutputData = (definitions: CommandOutputParameter[], values: any, pdh: string | undefined, auth: AuthState): ProcessIOParameter[] => {
+ return definitions.map(output => {
+ const doc = Array.isArray(output.doc) ? output.doc.join(', ') : output.doc;
return {
- id,
- doc: outputArray.map((outputParam: CommandOutputParameter) => (outputParam.doc))
- // Doc can be string or string[], concat conveniently works with both
- .reduce((acc: string[], input: string | string[]) => (acc.concat(input)), [])
- // Remove undefined and empty doc strings
- .filter(str => str)
- .join(", "),
- value: outputArray.map(outputParam => getInputDisplayValue(auth, {
- type: outputParam.class,
- value: outputParam,
- ...outputParam
- }, pdh, outputParam.secondaryFiles))
- .reduce((acc: ProcessIOParameter[], params: ProcessIOParameter[]) => (acc.concat(params)), [])
+ id: getIOParamId(output),
+ doc: output.label || doc || "",
+ value: getInputDisplayValue(auth, Object.assign(output, { value: values[getIOParamId(output)] }), pdh)
};
});
};
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list