From: Peter Amstutz Date: Tue, 24 May 2022 20:35:30 +0000 (-0400) Subject: Merge branch '19069-workflow-launching' into 19143-project-list-workflows X-Git-Tag: 2.4.1~1^2~1^2~3 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/e3064da256b0c0f78e97bfe53825a5c0bf11a4cb?hp=ea78e1afd181e1e6bf667cce24ad101e39d78b78 Merge branch '19069-workflow-launching' into 19143-project-list-workflows Arvados-DCO-1.1-Signed-off-by: Peter Amstutz --- diff --git a/src/common/labels.ts b/src/common/labels.ts index 682513fb..e784cec0 100644 --- a/src/common/labels.ts +++ b/src/common/labels.ts @@ -23,6 +23,8 @@ export const resourceLabel = (type: string, subtype = '') => { return "Group"; case ResourceKind.VIRTUAL_MACHINE: return "Virtual Machine"; + case ResourceKind.WORKFLOW: + return "Workflow"; default: return "Unknown"; } diff --git a/src/index.tsx b/src/index.tsx index f928ea8a..03840d49 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -62,6 +62,7 @@ import { linkActionSet } from 'views-components/context-menu/action-sets/link-ac import { loadFileViewersConfig } from 'store/file-viewers/file-viewers-actions'; import { filterGroupAdminActionSet, projectAdminActionSet } from 'views-components/context-menu/action-sets/project-admin-action-set'; import { permissionEditActionSet } from 'views-components/context-menu/action-sets/permission-edit-action-set'; +import { workflowActionSet } from 'views-components/context-menu/action-sets/workflow-action-set'; import { snackbarActions, SnackbarKind } from "store/snackbar/snackbar-actions"; import { openNotFoundDialog } from './store/not-found-panel/not-found-panel-action'; import { storeRedirects } from './common/redirect-to'; @@ -102,6 +103,7 @@ addMenuActionSet(ContextMenuKind.PROCESS_ADMIN, processResourceAdminActionSet); addMenuActionSet(ContextMenuKind.PROJECT_ADMIN, projectAdminActionSet); addMenuActionSet(ContextMenuKind.FILTER_GROUP_ADMIN, filterGroupAdminActionSet); addMenuActionSet(ContextMenuKind.PERMISSION_EDIT, permissionEditActionSet); +addMenuActionSet(ContextMenuKind.WORKFLOW, workflowActionSet); storeRedirects(); diff --git a/src/models/details.ts b/src/models/details.ts index 150b6940..b6eabd70 100644 --- a/src/models/details.ts +++ b/src/models/details.ts @@ -7,5 +7,6 @@ import { CollectionResource } from "./collection"; import { ProcessResource } from "./process"; import { EmptyResource } from "./empty"; import { CollectionFile, CollectionDirectory } from 'models/collection-file'; +import { WorkflowResource } from 'models/workflow'; -export type DetailsResource = ProjectResource | CollectionResource | ProcessResource | EmptyResource | CollectionFile | CollectionDirectory; +export type DetailsResource = ProjectResource | CollectionResource | ProcessResource | EmptyResource | CollectionFile | CollectionDirectory | WorkflowResource; diff --git a/src/store/context-menu/context-menu-actions.ts b/src/store/context-menu/context-menu-actions.ts index bc7f94b0..3e239fee 100644 --- a/src/store/context-menu/context-menu-actions.ts +++ b/src/store/context-menu/context-menu-actions.ts @@ -261,6 +261,8 @@ export const resourceUuidToContextMenuKind = (uuid: string, readonly = false) => return ContextMenuKind.ROOT_PROJECT; case ResourceKind.LINK: return ContextMenuKind.LINK; + case ResourceKind.WORKFLOW: + return ContextMenuKind.WORKFLOW; default: return; } diff --git a/src/store/navigation/navigation-action.ts b/src/store/navigation/navigation-action.ts index 9a4f31fd..c8811bf4 100644 --- a/src/store/navigation/navigation-action.ts +++ b/src/store/navigation/navigation-action.ts @@ -8,6 +8,7 @@ import { ResourceKind, extractUuidKind } from 'models/resource'; import { SidePanelTreeCategory } from '../side-panel-tree/side-panel-tree-actions'; import { Routes, getGroupUrl, getNavUrl, getUserProfileUrl } from 'routes/routes'; import { RootState } from 'store/store'; +import { openDetailsPanel } from 'store/details-panel/details-panel-action'; import { ServiceRepository } from 'services/services'; import { pluginConfig } from 'plugins'; import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions'; @@ -40,6 +41,9 @@ export const navigateTo = (uuid: string) => case ResourceKind.VIRTUAL_MACHINE: dispatch(navigateToAdminVirtualMachines); return; + case ResourceKind.WORKFLOW: + dispatch(openDetailsPanel(uuid)); + return; } switch (uuid) { diff --git a/src/store/processes/processes-actions.ts b/src/store/processes/processes-actions.ts index 6bd2976c..213e292b 100644 --- a/src/store/processes/processes-actions.ts +++ b/src/store/processes/processes-actions.ts @@ -18,6 +18,8 @@ import { RUN_PROCESS_BASIC_FORM, RunProcessBasicFormData } from "views/run-proce 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 { getWorkflow, getWorkflowInputs } from "models/workflow"; +import { ProjectResource } from "models/project"; +import { UserResource } from "models/user"; export const loadProcess = (containerRequestUuid: string) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository): Promise => { @@ -60,7 +62,8 @@ export const reRunProcess = (processUuid: string, workflowUuid: string) => const stringifiedDefinition = JSON.stringify(process.mounts[MOUNT_PATH_CWL_WORKFLOW].content); const newWorkflow = { ...workflow, definition: stringifiedDefinition }; - const basicInitialData: RunProcessBasicFormData = { name: `Copy of: ${process.name}`, description: process.description }; + const owner = getResource(workflow.ownerUuid)(getState().resources); + const basicInitialData: RunProcessBasicFormData = { name: `Copy of: ${process.name}`, description: process.description, owner }; dispatch(initialize(RUN_PROCESS_BASIC_FORM, basicInitialData)); const advancedInitialData: RunProcessAdvancedFormData = { diff --git a/src/store/resource-type-filters/resource-type-filters.ts b/src/store/resource-type-filters/resource-type-filters.ts index 0539cefe..64a391ca 100644 --- a/src/store/resource-type-filters/resource-type-filters.ts +++ b/src/store/resource-type-filters/resource-type-filters.ts @@ -27,6 +27,7 @@ export enum ObjectTypeFilter { PROJECT = 'Project', PROCESS = 'Process', COLLECTION = 'Data collection', + WORKFLOW = 'Workflow', } export enum GroupTypeFilter { @@ -63,6 +64,7 @@ export const getSimpleObjectTypeFilters = pipe( initFilter(ObjectTypeFilter.PROJECT), initFilter(ObjectTypeFilter.PROCESS), initFilter(ObjectTypeFilter.COLLECTION), + initFilter(ObjectTypeFilter.WORKFLOW), ); // Using pipe() with more than 7 arguments makes the return type be 'any', @@ -86,6 +88,8 @@ export const getInitialResourceTypeFilters = pipe( initFilter(CollectionTypeFilter.INTERMEDIATE_COLLECTION, ObjectTypeFilter.COLLECTION), initFilter(CollectionTypeFilter.LOG_COLLECTION, ObjectTypeFilter.COLLECTION), ), + initFilter(ObjectTypeFilter.WORKFLOW) + ); export const getInitialProcessTypeFilters = pipe( @@ -133,6 +137,8 @@ const objectTypeToResourceKind = (type: ObjectTypeFilter) => { return ResourceKind.PROCESS; case ObjectTypeFilter.COLLECTION: return ResourceKind.COLLECTION; + case ObjectTypeFilter.WORKFLOW: + return ResourceKind.WORKFLOW; } }; diff --git a/src/store/run-process-panel/run-process-panel-actions.ts b/src/store/run-process-panel/run-process-panel-actions.ts index f3352eb4..e0dada5c 100644 --- a/src/store/run-process-panel/run-process-panel-actions.ts +++ b/src/store/run-process-panel/run-process-panel-actions.ts @@ -21,6 +21,9 @@ import { } from 'views/run-process-panel/run-process-advanced-form'; import { dialogActions } from 'store/dialog/dialog-actions'; import { setBreadcrumbs } from 'store/breadcrumbs/breadcrumbs-actions'; +import { getResource } from 'store/resources/resources'; +import { ProjectResource } from "models/project"; +import { UserResource } from "models/user"; export const runProcessPanelActions = unionize({ SET_PROCESS_PATHNAME: ofType(), @@ -48,7 +51,7 @@ export type RunProcessPanelAction = UnionOf; export const loadRunProcessPanel = () => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { try { - dispatch(setBreadcrumbs([{ label: 'Run workflow' }])); + dispatch(setBreadcrumbs([{ label: 'Run Process' }])); const response = await services.workflowService.list(); dispatch(runProcessPanelActions.SET_WORKFLOWS(response.items)); } catch (e) { @@ -99,17 +102,23 @@ export const setWorkflow = (workflow: WorkflowResource, isWorkflowChanged = true const advancedFormValues = getWorkflowRunnerSettings(workflow); + let owner = getResource(getState().runProcessPanel.processOwnerUuid)(getState().resources); + const userUuid = getUserUuid(getState()); + if (!owner || !userUuid || owner.writableBy.indexOf(userUuid) === -1) { + owner = undefined; + } + if (isStepChanged && isWorkflowChanged) { dispatch(runProcessPanelActions.SET_STEP_CHANGED(false)); dispatch(runProcessPanelActions.SET_SELECTED_WORKFLOW(workflow)); dispatch(loadPresets(workflow.uuid)); - dispatch(initialize(RUN_PROCESS_BASIC_FORM, { name: workflow.name })); + dispatch(initialize(RUN_PROCESS_BASIC_FORM, { name: workflow.name, owner })); dispatch(initialize(RUN_PROCESS_ADVANCED_FORM, advancedFormValues)); } if (!isWorkflowChanged) { dispatch(runProcessPanelActions.SET_SELECTED_WORKFLOW(workflow)); dispatch(loadPresets(workflow.uuid)); - dispatch(initialize(RUN_PROCESS_BASIC_FORM, { name: workflow.name })); + dispatch(initialize(RUN_PROCESS_BASIC_FORM, { name: workflow.name, owner })); dispatch(initialize(RUN_PROCESS_ADVANCED_FORM, advancedFormValues)); } }; @@ -146,7 +155,7 @@ export const runProcess = async (dispatch: Dispatch, getState: () => RootSt const userUuid = getUserUuid(getState()); if (!userUuid) { return; } const { processOwnerUuid, selectedWorkflow } = state.runProcessPanel; - const ownerUUid = processOwnerUuid ? processOwnerUuid : userUuid; + const ownerUUid = basicForm.owner ? basicForm.owner.uuid : (processOwnerUuid ? processOwnerUuid : userUuid); if (selectedWorkflow) { const advancedForm = getFormValues(RUN_PROCESS_ADVANCED_FORM)(state) as RunProcessAdvancedFormData || getWorkflowRunnerSettings(selectedWorkflow); const newProcessData = { diff --git a/src/store/workflow-panel/workflow-panel-actions.ts b/src/store/workflow-panel/workflow-panel-actions.ts index b533717e..7c90fa6b 100644 --- a/src/store/workflow-panel/workflow-panel-actions.ts +++ b/src/store/workflow-panel/workflow-panel-actions.ts @@ -15,6 +15,10 @@ import { initialize } from 'redux-form'; import { RUN_PROCESS_BASIC_FORM } from 'views/run-process-panel/run-process-basic-form'; import { RUN_PROCESS_INPUTS_FORM } from 'views/run-process-panel/run-process-inputs-form'; import { RUN_PROCESS_ADVANCED_FORM } from 'views/run-process-panel/run-process-advanced-form'; +import { getResource, ResourcesState } from 'store/resources/resources'; +import { ProjectResource } from 'models/project'; +import { UserResource } from 'models/user'; +import { getUserUuid } from "common/getuser"; export const WORKFLOW_PANEL_ID = "workflowPanel"; const UUID_PREFIX_PROPERTY_NAME = 'uuidPrefix'; @@ -50,12 +54,21 @@ export const openRunProcess = (workflowUuid: string, ownerUuid?: string, name?: dispatch(loadPresets(workflow.uuid)); dispatch(initialize(RUN_PROCESS_ADVANCED_FORM, getWorkflowRunnerSettings(workflow))); + let owner; if (ownerUuid) { - dispatch(runProcessPanelActions.SET_PROCESS_OWNER_UUID(ownerUuid)); + // Must be writable. + const userUuid = getUserUuid(getState()); + owner = getResource(ownerUuid)(getState().resources); + if (!owner || !userUuid || owner.writableBy.indexOf(userUuid) === -1) { + owner = undefined; + } } - if (name) { - dispatch(initialize(RUN_PROCESS_BASIC_FORM, { name })); + if (owner) { + dispatch(runProcessPanelActions.SET_PROCESS_OWNER_UUID(owner.uuid)); } + + dispatch(initialize(RUN_PROCESS_BASIC_FORM, { name, owner })); + if (inputObj) { dispatch(initialize(RUN_PROCESS_INPUTS_FORM, inputObj)); } diff --git a/src/views-components/context-menu/action-sets/workflow-action-set.ts b/src/views-components/context-menu/action-sets/workflow-action-set.ts new file mode 100644 index 00000000..2aa78904 --- /dev/null +++ b/src/views-components/context-menu/action-sets/workflow-action-set.ts @@ -0,0 +1,15 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { ContextMenuActionSet } from "views-components/context-menu/context-menu-action-set"; +import { openRunProcess } from "store/workflow-panel/workflow-panel-actions"; + +export const workflowActionSet: ContextMenuActionSet = [[ + { + name: "Run", + execute: (dispatch, resource) => { + dispatch(openRunProcess(resource.uuid, resource.ownerUuid, resource.name)); + } + }, +]]; diff --git a/src/views-components/context-menu/context-menu.tsx b/src/views-components/context-menu/context-menu.tsx index 6f3a4389..4766259a 100644 --- a/src/views-components/context-menu/context-menu.tsx +++ b/src/views-components/context-menu/context-menu.tsx @@ -70,7 +70,7 @@ export const addMenuActionSet = (name: string, itemSet: ContextMenuActionSet) => const emptyActionSet: ContextMenuActionSet = []; const getMenuActionSet = (resource?: ContextMenuResource): ContextMenuActionSet => ( - resource ? menuActionSets.get(resource.menuKind) || emptyActionSet : emptyActionSet + resource ? menuActionSets.get(resource.menuKind) || emptyActionSet : emptyActionSet ); export enum ContextMenuKind { @@ -110,4 +110,5 @@ export enum ContextMenuKind { GROUP_MEMBER = "GroupMember", PERMISSION_EDIT = "PermissionEdit", LINK = "Link", + WORKFLOW = "Workflow", } diff --git a/src/views-components/details-panel/details-panel.tsx b/src/views-components/details-panel/details-panel.tsx index 399f4ef4..adbbab79 100644 --- a/src/views-components/details-panel/details-panel.tsx +++ b/src/views-components/details-panel/details-panel.tsx @@ -18,6 +18,7 @@ import { ProjectDetails } from "./project-details"; import { CollectionDetails } from "./collection-details"; import { ProcessDetails } from "./process-details"; import { EmptyDetails } from "./empty-details"; +import { WorkflowDetails } from "./workflow-details"; import { DetailsData } from "./details-data"; import { DetailsResource } from "models/details"; import { Config } from 'common/config'; @@ -71,6 +72,8 @@ const getItem = (res: DetailsResource): DetailsData => { return new CollectionDetails(res); case ResourceKind.PROCESS: return new ProcessDetails(res); + case ResourceKind.WORKFLOW: + return new WorkflowDetails(res); default: return new EmptyDetails(res); } @@ -152,9 +155,9 @@ export const DetailsPanel = withStyles(styles)( let shouldShowInlinePreview = false; if (!('kind' in res)) { shouldShowInlinePreview = isInlineFileUrlSafe( - res ? res.url : "", - authConfig.keepWebServiceUrl, - authConfig.keepWebInlineServiceUrl + res ? res.url : "", + authConfig.keepWebServiceUrl, + authConfig.keepWebInlineServiceUrl ) || authConfig.clusterConfig.Collections.TrustAllContent; } @@ -191,14 +194,14 @@ export const DetailsPanel = withStyles(styles)( = tabNr+1) ? tabNr : 0}> - { item.getTabLabels().map((tabLabel, idx) => + value={(item.getTabLabels().length >= tabNr + 1) ? tabNr : 0}> + {item.getTabLabels().map((tabLabel, idx) => ) } - {item.getDetails({tabNr, showPreview: shouldShowInlinePreview})} + {item.getDetails({ tabNr, showPreview: shouldShowInlinePreview })} ; } diff --git a/src/views-components/details-panel/workflow-details.tsx b/src/views-components/details-panel/workflow-details.tsx new file mode 100644 index 00000000..7076823c --- /dev/null +++ b/src/views-components/details-panel/workflow-details.tsx @@ -0,0 +1,88 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import React from 'react'; +import { DefaultIcon, WorkflowIcon } from 'components/icon/icon'; +import { WorkflowResource } from 'models/workflow'; +import { DetailsData } from "./details-data"; +import { DefaultView } from 'components/default-view/default-view'; +import { DetailsAttribute } from 'components/details-attribute/details-attribute'; +import { ResourceOwnerWithName } from 'views-components/data-explorer/renderers'; +import { formatDate } from "common/formatters"; +import { Grid } from '@material-ui/core'; +import { withStyles, StyleRulesCallback, WithStyles, Button } from '@material-ui/core'; +import { openRunProcess } from "store/workflow-panel/workflow-panel-actions"; +import { Dispatch } from 'redux'; +import { connect } from 'react-redux'; +import { ArvadosTheme } from 'common/custom-theme'; + +export interface WorkflowDetailsCardDataProps { + workflow?: WorkflowResource; +} + +export interface WorkflowDetailsCardActionProps { + onClick: (wf: WorkflowResource) => () => void; +} + +const mapDispatchToProps = (dispatch: Dispatch) => ({ + onClick: (wf: WorkflowResource) => + () => wf && dispatch(openRunProcess(wf.uuid, wf.ownerUuid, wf.name)), +}); + +type CssRules = 'runButton'; + +const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ + runButton: { + boxShadow: 'none', + padding: '2px 10px 2px 5px', + fontSize: '0.75rem' + }, +}); + +export const WorkflowDetailsAttributes = connect(null, mapDispatchToProps)( + withStyles(styles)( + ({ workflow, onClick, classes }: WorkflowDetailsCardDataProps & WorkflowDetailsCardActionProps & WithStyles) => { + return + + {workflow && workflow.description !== "" && + + } + + + + + } /> + + + + + + + + + } /> + + ; + })); + +export class WorkflowDetails extends DetailsData { + getIcon(className?: string) { + return ; + } + + getDetails() { + return ; + } +} diff --git a/src/views/run-process-panel/inputs/project-input.tsx b/src/views/run-process-panel/inputs/project-input.tsx new file mode 100644 index 00000000..7b45a6d1 --- /dev/null +++ b/src/views/run-process-panel/inputs/project-input.tsx @@ -0,0 +1,136 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import React from 'react'; +import { connect, DispatchProp } from 'react-redux'; +import { Field } from 'redux-form'; +import { Input, Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@material-ui/core'; +import { + GenericCommandInputParameter +} from 'models/workflow'; +import { GenericInput, GenericInputProps } from './generic-input'; +import { ProjectsTreePicker } from 'views-components/projects-tree-picker/projects-tree-picker'; +import { initProjectsTreePicker } from 'store/tree-picker/tree-picker-actions'; +import { TreeItem } from 'components/tree/tree'; +import { ProjectsTreePickerItem } from 'views-components/projects-tree-picker/generic-projects-tree-picker'; +import { ProjectResource } from 'models/project'; +import { ResourceKind } from 'models/resource'; +import { RootState } from 'store/store'; +import { getUserUuid } from 'common/getuser'; + +export type ProjectCommandInputParameter = GenericCommandInputParameter; + +const require: any = (value?: ProjectResource) => (value === undefined); + +export interface ProjectInputProps { + input: ProjectCommandInputParameter; + options?: { showOnlyOwned: boolean, showOnlyWritable: boolean }; +} +export const ProjectInput = ({ input, options }: ProjectInputProps) => + ; + +const format = (value?: ProjectResource) => value ? value.name : ''; + +interface ProjectInputComponentState { + open: boolean; + project?: ProjectResource; +} + +interface HasUserUuid { + userUuid: string; +}; + +const mapStateToProps = (state: RootState) => ({ userUuid: getUserUuid(state) }); + +export const ProjectInputComponent = connect(mapStateToProps)( + class ProjectInputComponent extends React.Component { + state: ProjectInputComponentState = { + open: false, + }; + + componentDidMount() { + this.props.dispatch( + initProjectsTreePicker(this.props.commandInput.id)); + } + + render() { + return <> + {this.renderInput()} + {this.renderDialog()} + ; + } + + openDialog = () => { + this.setState({ open: true }); + } + + closeDialog = () => { + this.setState({ open: false }); + } + + submit = () => { + this.closeDialog(); + this.props.input.onChange(this.state.project); + } + + setProject = (_: {}, { data }: TreeItem) => { + if ('kind' in data && data.kind === ResourceKind.PROJECT) { + this.setState({ project: data }); + } else { + this.setState({ project: undefined }); + } + } + + invalid = () => (!this.state.project || this.state.project.writableBy.indexOf(this.props.userUuid) === -1); + + renderInput() { + return + } + {...this.props} />; + } + + renderDialog() { + return + Choose a project + + + + + + + + ; + } + + }); diff --git a/src/views/run-process-panel/run-process-basic-form.tsx b/src/views/run-process-panel/run-process-basic-form.tsx index 13d882ba..32a126a4 100644 --- a/src/views/run-process-panel/run-process-basic-form.tsx +++ b/src/views/run-process-panel/run-process-basic-form.tsx @@ -6,14 +6,19 @@ import React from 'react'; import { reduxForm, Field } from 'redux-form'; import { Grid } from '@material-ui/core'; import { TextField } from 'components/text-field/text-field'; +import { ProjectInput, ProjectCommandInputParameter } from 'views/run-process-panel/inputs/project-input'; import { PROCESS_NAME_VALIDATION } from 'validators/validators'; +import { ProjectResource } from 'models/project'; +import { UserResource } from 'models/user'; export const RUN_PROCESS_BASIC_FORM = 'runProcessBasicForm'; export interface RunProcessBasicFormData { name: string; description: string; + owner?: ProjectResource | UserResource; } + export const RunProcessBasicForm = reduxForm({ form: RUN_PROCESS_BASIC_FORM @@ -24,7 +29,7 @@ export const RunProcessBasicForm = @@ -32,7 +37,14 @@ export const RunProcessBasicForm = + label="Optional description of this workflow run" /> + + + ); diff --git a/src/views/workflow-panel/workflow-description-card.tsx b/src/views/workflow-panel/workflow-description-card.tsx index d03f46e4..df1b2811 100644 --- a/src/views/workflow-panel/workflow-description-card.tsx +++ b/src/views/workflow-panel/workflow-description-card.tsx @@ -15,15 +15,12 @@ import { TableCell, TableBody, TableRow, - Grid, } from '@material-ui/core'; 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, parseWorkflowDefinition, getWorkflowInputs, getInputLabel, stringifyInputType } from 'models/workflow'; -import { DetailsAttribute } from 'components/details-attribute/details-attribute'; -import { ResourceOwnerWithName } from 'views-components/data-explorer/renderers'; -import { formatDate } from "common/formatters"; +import { parseWorkflowDefinition, getWorkflowInputs, getInputLabel, stringifyInputType } from 'models/workflow'; +import { WorkflowDetailsCardDataProps, WorkflowDetailsAttributes } from 'views-components/details-panel/workflow-details'; export type CssRules = 'root' | 'tab' | 'inputTab' | 'graphTab' | 'graphTabWithChosenWorkflow' | 'descriptionTab' | 'inputsTable'; @@ -57,10 +54,6 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ }, }); -interface WorkflowDetailsCardDataProps { - workflow?: WorkflowResource; -} - type WorkflowDetailsCardProps = WorkflowDetailsCardDataProps & WithStyles; export const WorkflowDetailsCard = withStyles(styles)( @@ -140,29 +133,3 @@ export const WorkflowDetailsCard = withStyles(styles)( ; } }); - -export const WorkflowDetailsAttributes = ({ workflow }: WorkflowDetailsCardDataProps) => { - return - - - - - } /> - - - - - - - - - } /> - - ; -};