initWebSocket(config, services.authService, store);
await store.dispatch(loadWorkbench());
addRouteChangeHandlers(history, store);
- // createSampleProcess(services);
}
};
};
// SPDX-License-Identifier: AGPL-3.0
import { Resource, ResourceKind } from "./resource";
+import { safeLoad } from 'js-yaml';
export interface WorkflowResource extends Resource {
kind: ResourceKind.WORKFLOW;
name: string;
description: string;
definition: string;
-}
\ No newline at end of file
+}
+export interface WorkflowResoruceDefinition {
+ cwlVersion: string;
+ $graph: Array<Workflow | CommandLineTool>;
+}
+export interface Workflow {
+ class: 'Workflow';
+ doc?: string;
+ id?: string;
+ inputs: CommandInputParameter[];
+ outputs: any[];
+ steps: any[];
+}
+
+export interface CommandLineTool {
+ class: 'CommandLineTool';
+ id: string;
+ inputs: CommandInputParameter[];
+ outputs: any[];
+}
+
+export interface CommandInputParameter {
+ id: string;
+ label?: string;
+ doc?: string | string[];
+ default?: any;
+ type?: CWLType | CWLType[] | CommandInputEnumSchema | CommandInputArraySchema;
+}
+
+export enum CWLType {
+ NULL = 'null',
+ BOOLEAN = 'boolean',
+ INT = 'int',
+ LONG = 'long',
+ FLOAT = 'float',
+ DOUBLE = 'double',
+ STRING = 'string',
+ FILE = 'File',
+ DIRECTORY = 'Directory',
+}
+
+export interface CommandInputEnumSchema {
+ symbols: string[];
+ type: 'enum';
+ label?: string;
+ name?: string;
+}
+
+export interface CommandInputArraySchema {
+ items: CWLType;
+ type: 'array';
+ label?: string;
+}
+
+export interface File {
+ class: CWLType.FILE;
+ location?: string;
+ path?: string;
+ basename?: string;
+}
+
+export interface Directory {
+ class: CWLType.DIRECTORY;
+ location?: string;
+ path?: string;
+ basename?: string;
+}
+
+export const parseWorkflowDefinition = (workflow: WorkflowResource): WorkflowResoruceDefinition => {
+ const definition = safeLoad(workflow.definition);
+ return definition;
+};
+
+export const getWorkflowInputs = (workflowDefinition: WorkflowResoruceDefinition) => {
+ const mainWorkflow = workflowDefinition.$graph.find(item => item.class === 'Workflow' && item.id === '#main');
+ return mainWorkflow
+ ? mainWorkflow.inputs
+ : undefined;
+};
+
+export const stringifyInputType = ({ type }: CommandInputParameter) => {
+ if (typeof type === 'string') {
+ return type;
+ } else if (type instanceof Array) {
+ return type.join(' | ');
+ } else if (typeof type === 'object') {
+ if (type.type === 'enum') {
+ return 'enum';
+ } else if (type.type === 'array') {
+ return `${type.items}[]`;
+ } else {
+ return 'unknown';
+ }
+ } else {
+ return 'unknown';
+ }
+};
import { ServiceRepository } from '~/services/services';
import { bindDataExplorerActions } from '~/store/data-explorer/data-explorer-action';
import { propertiesActions } from '~/store/properties/properties-actions';
+import { getResource } from '../resources/resources';
+import { getProperty } from '~/store/properties/properties';
+import { WorkflowResource } from '../../models/workflow';
export const WORKFLOW_PANEL_ID = "workflowPanel";
const UUID_PREFIX_PROPERTY_NAME = 'uuidPrefix';
-
+const WORKFLOW_PANEL_DETAILS_UUID = 'workflowPanelDetailsUuid';
export const workflowPanelActions = bindDataExplorerActions(WORKFLOW_PANEL_ID);
export const loadWorkflowPanel = () =>
export const setUuidPrefix = (uuidPrefix: string) =>
propertiesActions.SET_PROPERTY({ key: UUID_PREFIX_PROPERTY_NAME, value: uuidPrefix });
-export const getUuidPrefix = (state: RootState) =>{
+export const getUuidPrefix = (state: RootState) => {
return state.properties.uuidPrefix;
-};
\ No newline at end of file
+};
+
+export const showWorkflowDetails = (uuid: string) =>
+ propertiesActions.SET_PROPERTY({ key: WORKFLOW_PANEL_DETAILS_UUID, value: uuid });
+
+export const getWorkflowDetails = (state: RootState) => {
+ const uuid = getProperty<string>(WORKFLOW_PANEL_DETAILS_UUID)(state.properties);
+ return uuid ? getResource<WorkflowResource>(uuid)(state.resources) : undefined;
+};
import { ArvadosTheme } from '~/common/custom-theme';
import { WorkflowIcon } from '~/components/icon/icon';
import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
-import { WorkflowResource } from '~/models/workflow';
+import { WorkflowResource, parseWorkflowDefinition, getWorkflowInputs, stringifyInputType } from '~/models/workflow';
+import { DetailsAttribute } from '~/components/details-attribute/details-attribute';
export type CssRules = 'root' | 'tab';
}
render() {
- const { classes } = this.props;
+ const { classes, workflow } = this.props;
const { value } = this.state;
return <Paper className={classes.root}>
<Tabs value={value} onChange={this.handleChange} centered={true}>
<Tab className={classes.tab} label="Inputs" />
</Tabs>
{value === 0 && <CardContent>
- Description
- <DataTableDefaultView
- icon={WorkflowIcon}
- messages={['Please select a workflow to see its description.']} />
+ {workflow
+ ? workflow.description
+ : <DataTableDefaultView
+ icon={WorkflowIcon}
+ messages={['Please select a workflow to see its description.']} />}
</CardContent>}
{value === 1 && <CardContent>
- Inputs
+ {workflow && this.inputs
+ ? this.inputs.map(input => <DetailsAttribute key={input.id} label={input.label || ''} value={stringifyInputType(input)} />)
+ : <DataTableDefaultView
+ icon={WorkflowIcon}
+ messages={['Please select a workflow to see its description.']} />}
</CardContent>}
</Paper>;
}
+
+ get inputs() {
+ if (this.props.workflow) {
+ const definition = parseWorkflowDefinition(this.props.workflow);
+ if (definition) {
+ return getWorkflowInputs(definition);
+ }
+ }
+ return;
+ }
});
\ No newline at end of file
import { DataExplorer } from "~/views-components/data-explorer/data-explorer";
import { WorkflowIcon } from '~/components/icon/icon';
import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
-import { WORKFLOW_PANEL_ID } from '~/store/workflow-panel/workflow-panel-actions';
+import { WORKFLOW_PANEL_ID, workflowPanelActions } from '~/store/workflow-panel/workflow-panel-actions';
import {
ResourceLastModifiedDate,
RosurceWorkflowName,
import { DataTableFilterItem } from '~/components/data-table-filters/data-table-filters';
import { Grid } from '@material-ui/core';
import { WorkflowDetailsCard } from './workflow-description-card';
+import { WorkflowResource } from '../../models/workflow';
export enum WorkflowPanelColumnNames {
NAME = "Name",
type: ResourceStatus;
}
-interface WorkflowPanelDataProps {
- handleRowDoubleClick: any;
- handleRowClick: any;
+export interface WorkflowPanelDataProps {
+ workflow?: WorkflowResource;
}
+export interface WorfklowPanelActionProps {
+ handleRowDoubleClick: (workflowUuid: string) => void;
+ handleRowClick: (workflowUuid: string) => void;
+}
+
+export type WorkflowPanelProps = WorkflowPanelDataProps & WorfklowPanelActionProps;
+
export enum ResourceStatus {
PUBLIC = "Public",
PRIVATE = "Private",
}
];
-export const WorkflowPanelView = ({...props}) => {
+export const WorkflowPanelView = (props: WorkflowPanelProps) => {
return <Grid container spacing={16}>
<Grid item xs={6}>
<DataExplorer
dataTableDefaultView={<DataTableDefaultView icon={WorkflowIcon} />} />
</Grid>
<Grid item xs={6}>
- <WorkflowDetailsCard />
+ <WorkflowDetailsCard workflow={props.workflow} />
</Grid>
</Grid>;
};
\ No newline at end of file
//
// SPDX-License-Identifier: AGPL-3.0
-import * as React from "react";
import { Dispatch } from "redux";
import { connect } from "react-redux";
import { navigateTo } from '~/store/navigation/navigation-action';
-import { loadDetailsPanel } from '~/store/details-panel/details-panel-action';
import { WorkflowPanelView } from '~/views/workflow-panel/workflow-panel-view';
+import { WorfklowPanelActionProps, WorkflowPanelDataProps } from './workflow-panel-view';
+import { showWorkflowDetails, getWorkflowDetails } from '../../store/workflow-panel/workflow-panel-actions';
+import { RootState } from '~/store/store';
-const mapDispatchToProps = (dispatch: Dispatch) => ({
+const mapStateToProps = (state: RootState): WorkflowPanelDataProps => ({
+ workflow: getWorkflowDetails(state)
+});
+
+const mapDispatchToProps = (dispatch: Dispatch): WorfklowPanelActionProps => ({
handleRowDoubleClick: (uuid: string) => {
dispatch<any>(navigateTo(uuid));
},
-
+
handleRowClick: (uuid: string) => {
- dispatch(loadDetailsPanel(uuid));
+ dispatch(showWorkflowDetails(uuid));
}
});
-export const WorkflowPanel= connect(undefined, mapDispatchToProps)(
- (props) => <WorkflowPanelView {...props}/>);
\ No newline at end of file
+export const WorkflowPanel = connect(mapStateToProps, mapDispatchToProps)(WorkflowPanelView);
\ No newline at end of file