// Copyright (C) The Arvados Authors. All rights reserved. // // SPDX-License-Identifier: AGPL-3.0 import React from "react"; import { StyleRulesCallback, WithStyles, withStyles } from "@material-ui/core"; import { ProcessIcon } from "components/icon/icon"; import { Process } from "store/processes/process"; import { SubprocessPanel } from "views/subprocess-panel/subprocess-panel"; import { SubprocessFilterDataProps } from "components/subprocess-filter/subprocess-filter"; import { MPVContainer, MPVPanelContent, MPVPanelState } from "components/multi-panel-view/multi-panel-view"; import { ArvadosTheme } from "common/custom-theme"; import { ProcessDetailsCard } from "./process-details-card"; import { ProcessIOCard, ProcessIOCardType, ProcessIOParameter } from "./process-io-card"; import { ProcessResourceCard } from "./process-resource-card"; 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 { getInputCollectionMounts } from "store/processes/processes-actions"; import { WorkflowInputsData } from "models/workflow"; import { CommandOutputParameter } from "cwlts/mappings/v1.0/CommandOutputParameter"; import { AuthState } from "store/auth/auth-reducer"; import { ProcessCmdCard } from "./process-cmd-card"; import { ContainerRequestResource } from "models/container-request"; import { OutputDetails, NodeInstanceType } from "store/process-panel/process-panel"; import { NotFoundView } from 'views/not-found-panel/not-found-panel'; type CssRules = "root"; const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({ root: { width: "100%", }, }); export interface ProcessPanelRootDataProps { process?: Process; subprocesses: Array<Process>; filters: Array<SubprocessFilterDataProps>; processLogsPanel: ProcessLogsPanel; auth: AuthState; inputRaw: WorkflowInputsData | null; inputParams: ProcessIOParameter[] | null; outputData: OutputDetails | null; outputDefinitions: CommandOutputParameter[]; outputParams: ProcessIOParameter[] | null; nodeInfo: NodeInstanceType | null; usageReport: string | null; } export interface ProcessPanelRootActionProps { onContextMenu: (event: React.MouseEvent<HTMLElement>, process: Process) => void; onToggle: (status: string) => void; cancelProcess: (uuid: string) => void; startProcess: (uuid: string) => void; resumeOnHoldWorkflow: (uuid: string) => void; onLogFilterChange: (filter: FilterOption) => void; navigateToLog: (uuid: string) => void; onCopyToClipboard: (uuid: string) => void; loadInputs: (containerRequest: ContainerRequestResource) => void; loadOutputs: (containerRequest: ContainerRequestResource) => void; loadNodeJson: (containerRequest: ContainerRequestResource) => void; loadOutputDefinitions: (containerRequest: ContainerRequestResource) => void; updateOutputParams: () => void; pollProcessLogs: (processUuid: string) => Promise<void>; } export type ProcessPanelRootProps = ProcessPanelRootDataProps & ProcessPanelRootActionProps & WithStyles<CssRules>; const panelsData: MPVPanelState[] = [ { name: "Details" }, { name: "Logs", visible: true }, { name: "Subprocesses" }, { name: "Outputs" }, { name: "Inputs" }, { name: "Command" }, { name: "Resources" }, ]; export const ProcessPanelRoot = withStyles(styles)( ({ process, auth, processLogsPanel, inputRaw, inputParams, outputData, outputDefinitions, outputParams, nodeInfo, usageReport, loadInputs, loadOutputs, loadNodeJson, loadOutputDefinitions, updateOutputParams, ...props }: ProcessPanelRootProps) => { const outputUuid = process?.containerRequest.outputUuid; const containerRequest = process?.containerRequest; const inputMounts = getInputCollectionMounts(process?.containerRequest); React.useEffect(() => { if (containerRequest) { // Load inputs from mounts or props loadInputs(containerRequest); // Fetch raw output (loads from props or keep) loadOutputs(containerRequest); // Loads output definitions from mounts into store loadOutputDefinitions(containerRequest); // load the assigned instance type from node.json in // the log collection loadNodeJson(containerRequest); } }, [containerRequest, loadInputs, loadOutputs, loadOutputDefinitions, loadNodeJson]); const maxHeight = "100%"; // Trigger processing output params when raw or definitions change React.useEffect(() => { updateOutputParams(); }, [outputData, outputDefinitions, updateOutputParams]); return process ? ( <MPVContainer className={props.classes.root} spacing={8} panelStates={panelsData} justify-content="flex-start" direction="column" wrap="nowrap"> <MPVPanelContent forwardProps xs="auto" data-cy="process-details"> <ProcessDetailsCard process={process} onContextMenu={event => props.onContextMenu(event, process)} cancelProcess={props.cancelProcess} startProcess={props.startProcess} resumeOnHoldWorkflow={props.resumeOnHoldWorkflow} /> </MPVPanelContent> <MPVPanelContent forwardProps xs minHeight={maxHeight} maxHeight={maxHeight} data-cy="process-logs"> <ProcessLogsCard onCopy={props.onCopyToClipboard} process={process} lines={getProcessPanelLogs(processLogsPanel)} selectedFilter={{ label: processLogsPanel.selectedFilter, value: processLogsPanel.selectedFilter, }} filters={processLogsPanel.filters.map(filter => ({ label: filter, value: filter }))} onLogFilterChange={props.onLogFilterChange} navigateToLog={props.navigateToLog} pollProcessLogs={props.pollProcessLogs} /> </MPVPanelContent> <MPVPanelContent forwardProps xs maxHeight={maxHeight} data-cy="process-children"> <SubprocessPanel process={process} /> </MPVPanelContent> <MPVPanelContent forwardProps xs maxHeight={maxHeight} data-cy="process-outputs"> <ProcessIOCard label={ProcessIOCardType.OUTPUT} process={process} params={outputParams} raw={outputData?.raw} outputUuid={outputUuid || ""} /> </MPVPanelContent> <MPVPanelContent forwardProps xs maxHeight={maxHeight} data-cy="process-inputs"> <ProcessIOCard label={ProcessIOCardType.INPUT} process={process} params={inputParams} raw={inputRaw} mounts={inputMounts} /> </MPVPanelContent> <MPVPanelContent forwardProps xs="auto" maxHeight={"50%"} data-cy="process-cmd"> <ProcessCmdCard onCopy={props.onCopyToClipboard} process={process} /> </MPVPanelContent> <MPVPanelContent forwardProps xs data-cy="process-resources"> <ProcessResourceCard process={process} nodeInfo={nodeInfo} usageReport={usageReport} /> </MPVPanelContent> </MPVContainer> ) : ( <NotFoundView icon={ProcessIcon} messages={["Process not found"]} /> ); } );