'bar' // make sure we can go back to the original name as a last step
];
eachPair(names, (from, to) => {
- cy.get('[data-cy=collection-files-panel]')
- .contains(`${from}`).rightclick({force: true});
+ cy.waitForDom().get('[data-cy=collection-files-panel]')
+ .contains(`${from}`).rightclick();
cy.get('[data-cy=context-menu]')
.contains('Rename')
.click();
.then(function(containerRequest) {
cy.loginAs(activeUser);
cy.goToPath(`/processes/${containerRequest.uuid}`);
- cy.get('[data-cy=process-info]').should('contain', crName);
+ cy.get('[data-cy=process-details]').should('contain', crName);
cy.get('[data-cy=process-logs]')
.should('contain', 'No logs yet')
.and('not.contain', 'hello world');
.and('contain', 'No additional warning details available');
});
});
-});
\ No newline at end of file
+});
const blob = new Blob(byteArrays, { type: contentType });
return blob
}
+
+// From https://github.com/cypress-io/cypress/issues/7306#issuecomment-1076451070=
+// This command requires the async package (https://www.npmjs.com/package/async)
+Cypress.Commands.add('waitForDom', () => {
+ cy.window().then(win => {
+ let timeElapsed = 0;
+
+ cy.log("Waiting for DOM mutations to complete");
+
+ return new Cypress.Promise((resolve) => {
+ // set the required variables
+ let async = require("async");
+ let observerConfig = { attributes: true, childList: true, subtree: true };
+ let items = Array.apply(null, { length: 50 }).map(Number.call, Number);
+ win.mutationCount = 0;
+ win.previousMutationCount = null;
+
+ // create an observer instance
+ let observer = new win.MutationObserver((mutations) => {
+ mutations.forEach((mutation) => {
+ // Only record "attributes" type mutations that are not a "class" mutation.
+ // If the mutation is not an "attributes" type, then we always record it.
+ if (mutation.type === 'attributes' && mutation.attributeName !== 'class') {
+ win.mutationCount += 1;
+ } else if (mutation.type !== 'attributes') {
+ win.mutationCount += 1;
+ }
+ });
+
+ // initialize the previousMutationCount
+ if (win.previousMutationCount == null) win.previousMutationCount = 0;
+ });
+
+ // watch the document body for the specified mutations
+ observer.observe(win.document.body, observerConfig);
+
+ // check the DOM for mutations up to 50 times for a maximum time of 5 seconds
+ async.eachSeries(items, function iteratee(item, callback) {
+ // keep track of the elapsed time so we can log it at the end of the command
+ timeElapsed = timeElapsed + 100;
+
+ // make each iteration of the loop 100ms apart
+ setTimeout(() => {
+ if (win.mutationCount === win.previousMutationCount) {
+ // pass an argument to the async callback to exit the loop
+ return callback('Resolved - DOM changes complete.');
+ } else if (win.previousMutationCount != null) {
+ // only set the previous count if the observer has checked the DOM at least once
+ win.previousMutationCount = win.mutationCount;
+ return callback();
+ } else if (win.mutationCount === 0 && win.previousMutationCount == null && item === 4) {
+ // this is an early exit in case nothing is changing in the DOM. That way we only
+ // wait 500ms instead of the full 5 seconds when no DOM changes are occurring.
+ return callback('Resolved - Exiting early since no DOM changes were detected.');
+ } else {
+ // proceed to the next iteration
+ return callback();
+ }
+ }, 100);
+ }, function done() {
+ // Log the total wait time so users can see it
+ cy.log(`DOM mutations ${timeElapsed >= 5000 ? "did not complete" : "completed"} in ${timeElapsed} ms`);
+
+ // disconnect the observer and resolve the promise
+ observer.disconnect();
+ resolve();
+ });
+ });
+ });
+ });
--- /dev/null
+/**
+ * This command tries to ensure that the elements in the DOM are actually visible
+ * and done (re)rendering. This is due to how React re-renders components.
+ *
+ * IMPORTANT NOTES:
+ * => You should only use this command in instances where a test is failing due
+ * to detached elements. Cypress will probably give you a warning along the lines
+ * of, "Element has an effective width/height of 0". This warning is not very useful
+ * in pointing out it is due to the element being detached from the DOM AFTER the
+ * cy.get command had already retrieved it. This command can save you from that
+ * by explicitly waiting for the DOM to stop changing.
+ * => This command can take anywhere from 100ms to 5 seconds to complete
+ * => This command will exit early (500ms) when no changes are occurring in the DOM.
+ * We wait a minimum of 500ms because sometimes it can take up to around that time
+ * for mutations to start occurring.
+ *
+ * GitHub Issues:
+ * * https://github.com/cypress-io/cypress/issues/695 (Closed - no activity)
+ * * https://github.com/cypress-io/cypress/issues/7306 (Open - re-get detached elements)
+ *
+ * @example Wait for the DOM to stop changing before retrieving an element
+ * cy.waitForDom().get('#an-elements-id')
+ */
+ waitForDom(): Chainable<any>
}
getDetails() {
- return <ProcessDetailsAttributes item={this.item} />;
+ return <ProcessDetailsAttributes request={this.item} />;
}
}
// SPDX-License-Identifier: AGPL-3.0
import React from "react";
-import { Grid } from "@material-ui/core";
+import { Grid, StyleRulesCallback, withStyles } from "@material-ui/core";
+import { Dispatch } from 'redux';
import { formatDate } from "common/formatters";
import { resourceLabel } from "common/labels";
import { DetailsAttribute } from "components/details-attribute/details-attribute";
-import { ProcessResource } from "models/process";
import { ResourceKind } from "models/resource";
-import { ResourceOwnerWithName } from "views-components/data-explorer/renderers";
+import { ContainerRunTime, ResourceOwnerWithName } from "views-components/data-explorer/renderers";
+import { getProcess } from "store/processes/process";
+import { RootState } from "store/store";
+import { connect } from "react-redux";
+import { ProcessResource } from "models/process";
+import { ContainerResource } from "models/container";
+import { openProcessInputDialog } from "store/processes/process-input-actions";
+import { navigateToOutput, openWorkflow } from "store/process-panel/process-panel-actions";
+import { ArvadosTheme } from "common/custom-theme";
+import { ProcessRuntimeStatus } from "views-components/process-runtime-status/process-runtime-status";
+import { getPropertyChip } from "views-components/resource-properties-form/property-chip";
+
+type CssRules = 'link' | 'propertyTag';
-type CssRules = 'label' | 'value';
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+ link: {
+ fontSize: '0.875rem',
+ color: theme.palette.primary.main,
+ '&:hover': {
+ cursor: 'pointer'
+ }
+ },
+ propertyTag: {
+ marginRight: theme.spacing.unit / 2,
+ marginBottom: theme.spacing.unit / 2
+ },
+});
-export const ProcessDetailsAttributes = (props: { item: ProcessResource, twoCol?: boolean, classes?: Record<CssRules, string> }) => {
- const item = props.item;
- const classes = props.classes || { label: '', value: '', button: '' };
- const mdSize = props.twoCol ? 6 : 12;
- return <Grid container>
- <Grid item xs={12} md={mdSize}>
- <DetailsAttribute label='Type' value={resourceLabel(ResourceKind.PROCESS)} />
- </Grid>
- <Grid item xs={12} md={mdSize}>
- <DetailsAttribute classLabel={classes.label} classValue={classes.value}
- label='Owner' linkToUuid={item.ownerUuid}
- uuidEnhancer={(uuid: string) => <ResourceOwnerWithName uuid={uuid} />} />
- </Grid>
- <Grid item xs={12} md={12}>
- <DetailsAttribute label='Status' value={item.state} />
- </Grid>
- <Grid item xs={12} md={mdSize}>
- <DetailsAttribute label='Last modified' value={formatDate(item.modifiedAt)} />
- </Grid>
- <Grid item xs={12} md={mdSize}>
- <DetailsAttribute label='Started at' value={formatDate(item.createdAt)} />
- </Grid>
- <Grid item xs={12} md={mdSize}>
- <DetailsAttribute label='Created at' value={formatDate(item.createdAt)} />
- </Grid>
- <Grid item xs={12} md={mdSize}>
- <DetailsAttribute label='Finished at' value={formatDate(item.expiresAt)} />
- </Grid>
- <Grid item xs={12} md={mdSize}>
- <DetailsAttribute label='Outputs' value={item.outputPath} />
- </Grid>
- <Grid item xs={12} md={mdSize}>
- <DetailsAttribute label='UUID' linkToUuid={item.uuid} value={item.uuid} />
- </Grid>
- <Grid item xs={12} md={mdSize}>
- <DetailsAttribute label='Container UUID' value={item.containerUuid} />
- </Grid>
- <Grid item xs={12} md={mdSize}>
- <DetailsAttribute label='Priority' value={item.priority} />
- </Grid>
- <Grid item xs={12} md={mdSize}>
- <DetailsAttribute label='Runtime Constraints'
- value={JSON.stringify(item.runtimeConstraints)} />
- </Grid>
- <Grid item xs={12} md={mdSize}>
- <DetailsAttribute label='Docker Image locator'
- linkToUuid={item.containerImage} value={item.containerImage} />
- </Grid>
- </Grid>;
+const mapStateToProps = (state: RootState, props: { request: ProcessResource }) => {
+ return {
+ container: getProcess(props.request.uuid)(state.resources)?.container,
+ };
};
+
+interface ProcessDetailsAttributesActionProps {
+ openProcessInputDialog: (uuid: string) => void;
+ navigateToOutput: (uuid: string) => void;
+ openWorkflow: (uuid: string) => void;
+}
+
+const mapDispatchToProps = (dispatch: Dispatch): ProcessDetailsAttributesActionProps => ({
+ openProcessInputDialog: (uuid) => dispatch<any>(openProcessInputDialog(uuid)),
+ navigateToOutput: (uuid) => dispatch<any>(navigateToOutput(uuid)),
+ openWorkflow: (uuid) => dispatch<any>(openWorkflow(uuid)),
+});
+
+export const ProcessDetailsAttributes = withStyles(styles, { withTheme: true })(
+ connect(mapStateToProps, mapDispatchToProps)(
+ (props: { request: ProcessResource, container?: ContainerResource, twoCol?: boolean, hideProcessPanelRedundantFields?: boolean, classes: Record<CssRules, string> } & ProcessDetailsAttributesActionProps) => {
+ const containerRequest = props.request;
+ const container = props.container;
+ const classes = props.classes;
+ const mdSize = props.twoCol ? 6 : 12;
+ return <Grid container>
+ <Grid item xs={12}>
+ <ProcessRuntimeStatus runtimeStatus={container?.runtimeStatus} />
+ </Grid>
+ {!props.hideProcessPanelRedundantFields && <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute label='Type' value={resourceLabel(ResourceKind.PROCESS)} />
+ </Grid>}
+ <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute label='Container Request UUID' linkToUuid={containerRequest.uuid} value={containerRequest.uuid} />
+ </Grid>
+ <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute label='Docker Image locator'
+ linkToUuid={containerRequest.containerImage} value={containerRequest.containerImage} />
+ </Grid>
+ <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute
+ label='Owner' linkToUuid={containerRequest.ownerUuid}
+ uuidEnhancer={(uuid: string) => <ResourceOwnerWithName uuid={uuid} />} />
+ </Grid>
+ <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute label='Container UUID' value={containerRequest.containerUuid} />
+ </Grid>
+ {!props.hideProcessPanelRedundantFields && <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute label='Status' value={containerRequest.state} />
+ </Grid>}
+ <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute label='Created at' value={formatDate(containerRequest.createdAt)} />
+ </Grid>
+ <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute label='Started at' value={container ? formatDate(container.startedAt) : "(none)"} />
+ </Grid>
+ <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute label='Finished at' value={container ? formatDate(container.finishedAt) : "(none)"} />
+ </Grid>
+ <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute label='Container run time'>
+ <ContainerRunTime uuid={containerRequest.uuid} />
+ </DetailsAttribute>
+ </Grid>
+ <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute label='Requesting Container UUID' value={containerRequest.requestingContainerUuid || "(none)"} />
+ </Grid>
+ <Grid item xs={6}>
+ <span onClick={() => props.navigateToOutput(containerRequest.outputUuid!)}>
+ <DetailsAttribute classLabel={classes.link} label='Outputs' />
+ </span>
+ <span onClick={() => props.openProcessInputDialog(containerRequest.uuid)}>
+ <DetailsAttribute classLabel={classes.link} label='Inputs' />
+ </span>
+ </Grid>
+ {containerRequest.properties.workflowUuid &&
+ <Grid item xs={12} md={mdSize}>
+ <span onClick={() => props.openWorkflow(containerRequest.properties.workflowUuid)}>
+ <DetailsAttribute classValue={classes.link}
+ label='Workflow' value={containerRequest.properties.workflowName} />
+ </span>
+ </Grid>}
+ <Grid item xs={12} md={mdSize}>
+ <DetailsAttribute label='Priority' value={containerRequest.priority} />
+ </Grid>
+ {/*
+ NOTE: The property list should be kept at the bottom, because it spans
+ the entire available width, without regards of the twoCol prop.
+ */}
+ <Grid item xs={12} md={12}>
+ <DetailsAttribute label='Properties' />
+ { Object.keys(containerRequest.properties).length > 0
+ ? Object.keys(containerRequest.properties).map(k =>
+ Array.isArray(containerRequest.properties[k])
+ ? containerRequest.properties[k].map((v: string) =>
+ getPropertyChip(k, v, undefined, classes.propertyTag))
+ : getPropertyChip(k, containerRequest.properties[k], undefined, classes.propertyTag))
+ : <div>No properties</div> }
+ </Grid>
+ </Grid>;
+ }
+ )
+);
IconButton,
CardContent,
Tooltip,
+ Typography,
} from '@material-ui/core';
import { ArvadosTheme } from 'common/custom-theme';
-import { CloseIcon } from 'components/icon/icon';
+import { CloseIcon, MoreOptionsIcon, ProcessIcon } from 'components/icon/icon';
import { Process } from 'store/processes/process';
import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
import { ProcessDetailsAttributes } from './process-details-attributes';
+import { ProcessStatus } from 'views-components/data-explorer/renderers';
+import { ContainerState } from 'models/container';
-type CssRules = 'card' | 'content' | 'title' | 'header';
+type CssRules = 'card' | 'content' | 'title' | 'header' | 'cancelButton' | 'avatar' | 'iconHeader';
const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
card: {
paddingTop: theme.spacing.unit,
paddingBottom: theme.spacing.unit,
},
+ iconHeader: {
+ fontSize: '1.875rem',
+ color: theme.customs.colors.green700,
+ },
+ avatar: {
+ alignSelf: 'flex-start',
+ paddingTop: theme.spacing.unit * 0.5
+ },
content: {
'&:last-child': {
paddingBottom: theme.spacing.unit * 2,
overflow: 'hidden',
paddingTop: theme.spacing.unit * 0.5
},
+ cancelButton: {
+ paddingRight: theme.spacing.unit * 2,
+ fontSize: '14px',
+ color: theme.customs.colors.red900,
+ "&:hover": {
+ cursor: 'pointer'
+ }
+ },
});
export interface ProcessDetailsCardDataProps {
process: Process;
+ cancelProcess: (uuid: string) => void;
+ onContextMenu: (event: React.MouseEvent<HTMLElement>) => void;
}
type ProcessDetailsCardProps = ProcessDetailsCardDataProps & WithStyles<CssRules> & MPVPanelProps;
export const ProcessDetailsCard = withStyles(styles)(
- ({ classes, process, doHidePanel, panelName }: ProcessDetailsCardProps) => {
+ ({ cancelProcess, onContextMenu, classes, process, doHidePanel, panelName }: ProcessDetailsCardProps) => {
return <Card className={classes.card}>
<CardHeader
className={classes.header}
classes={{
content: classes.title,
+ avatar: classes.avatar,
}}
- title='Details'
- action={ doHidePanel &&
+ avatar={<ProcessIcon className={classes.iconHeader} />}
+ title={
+ <Tooltip title={process.containerRequest.name} placement="bottom-start">
+ <Typography noWrap variant='h6' color='inherit'>
+ {process.containerRequest.name}
+ </Typography>
+ </Tooltip>
+ }
+ subheader={
+ <Tooltip title={getDescription(process)} placement="bottom-start">
+ <Typography noWrap variant='body1' color='inherit'>
+ {getDescription(process)}
+ </Typography>
+ </Tooltip>}
+ action={
+ <div>
+ {process.container && process.container.state === ContainerState.RUNNING &&
+ <span className={classes.cancelButton} onClick={() => cancelProcess(process.containerRequest.uuid)}>Cancel</span>}
+ <ProcessStatus uuid={process.containerRequest.uuid} />
+ <Tooltip title="More options" disableFocusListener>
+ <IconButton
+ aria-label="More options"
+ onClick={event => onContextMenu(event)}>
+ <MoreOptionsIcon />
+ </IconButton>
+ </Tooltip>
+ { doHidePanel &&
<Tooltip title={`Close ${panelName || 'panel'}`} disableFocusListener>
<IconButton onClick={doHidePanel}><CloseIcon /></IconButton>
- </Tooltip> } />
+ </Tooltip> }
+ </div>
+ } />
<CardContent className={classes.content}>
- <ProcessDetailsAttributes item={process.containerRequest} twoCol />
+ <ProcessDetailsAttributes request={process.containerRequest} twoCol hideProcessPanelRedundantFields />
</CardContent>
</Card>;
}
);
+const getDescription = (process: Process) =>
+ process.containerRequest.description || '(no-description)';
+++ /dev/null
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import React from 'react';
-import {
- StyleRulesCallback,
- WithStyles,
- withStyles,
- Card,
- CardHeader,
- IconButton,
- CardContent,
- Grid,
- Typography,
- Tooltip
-} from '@material-ui/core';
-import { ArvadosTheme } from 'common/custom-theme';
-import { CloseIcon, MoreOptionsIcon, ProcessIcon } from 'components/icon/icon';
-import { DetailsAttribute } from 'components/details-attribute/details-attribute';
-import { Process } from 'store/processes/process';
-import { formatDate } from 'common/formatters';
-import classNames from 'classnames';
-import { ContainerState } from 'models/container';
-import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
-import { ProcessRuntimeStatus } from 'views-components/process-runtime-status/process-runtime-status';
-import { ProcessStatus } from 'views-components/data-explorer/renderers';
-
-type CssRules = 'card' | 'iconHeader' | 'label' | 'value' | 'link' | 'content' | 'title' | 'avatar' | 'cancelButton' | 'header';
-
-const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
- card: {
- height: '100%'
- },
- header: {
- paddingTop: theme.spacing.unit,
- paddingBottom: theme.spacing.unit,
- },
- iconHeader: {
- fontSize: '1.875rem',
- color: theme.customs.colors.green700,
- },
- avatar: {
- alignSelf: 'flex-start',
- paddingTop: theme.spacing.unit * 0.5
- },
- label: {
- display: 'flex',
- justifyContent: 'flex-start',
- fontSize: '0.875rem',
- marginRight: theme.spacing.unit * 3,
- paddingRight: theme.spacing.unit
- },
- value: {
- textTransform: 'none',
- fontSize: '0.875rem',
- },
- link: {
- fontSize: '0.875rem',
- color: theme.palette.primary.main,
- '&:hover': {
- cursor: 'pointer'
- }
- },
- content: {
- paddingTop: '0px',
- paddingLeft: theme.spacing.unit * 1,
- paddingRight: theme.spacing.unit * 1,
- '&:last-child': {
- paddingBottom: theme.spacing.unit * 1,
- }
- },
- title: {
- overflow: 'hidden',
- paddingTop: theme.spacing.unit * 0.5
- },
- cancelButton: {
- paddingRight: theme.spacing.unit * 2,
- fontSize: '14px',
- color: theme.customs.colors.red900,
- "&:hover": {
- cursor: 'pointer'
- }
- }
-});
-
-export interface ProcessInformationCardDataProps {
- process: Process;
- onContextMenu: (event: React.MouseEvent<HTMLElement>) => void;
- openProcessInputDialog: (uuid: string) => void;
- navigateToOutput: (uuid: string) => void;
- openWorkflow: (uuid: string) => void;
- cancelProcess: (uuid: string) => void;
-}
-
-type ProcessInformationCardProps = ProcessInformationCardDataProps & WithStyles<CssRules, true> & MPVPanelProps;
-
-export const ProcessInformationCard = withStyles(styles, { withTheme: true })(
- ({ classes, process, onContextMenu, theme, openProcessInputDialog, navigateToOutput, openWorkflow, cancelProcess, doHidePanel, panelName }: ProcessInformationCardProps) => {
- const { container } = process;
- const startedAt = container ? formatDate(container.startedAt) : 'N/A';
- const finishedAt = container ? formatDate(container.finishedAt) : 'N/A';
- return <Card className={classes.card}>
- <CardHeader
- className={classes.header}
- classes={{
- content: classes.title,
- avatar: classes.avatar
- }}
- avatar={<ProcessIcon className={classes.iconHeader} />}
- action={
- <div>
- {process.container && process.container.state === ContainerState.RUNNING &&
- <span className={classes.cancelButton} onClick={() => cancelProcess(process.containerRequest.uuid)}>Cancel</span>}
- <ProcessStatus uuid={process.containerRequest.uuid} />
- <Tooltip title="More options" disableFocusListener>
- <IconButton
- aria-label="More options"
- onClick={event => onContextMenu(event)}>
- <MoreOptionsIcon />
- </IconButton>
- </Tooltip>
- { doHidePanel &&
- <Tooltip title={`Close ${panelName || 'panel'}`} disableFocusListener>
- <IconButton onClick={doHidePanel}><CloseIcon /></IconButton>
- </Tooltip> }
- </div>
- }
- title={ !!process.containerRequest.name &&
- <Typography noWrap variant='h6' color='inherit'>
- {process.containerRequest.name}
- </Typography>
- }
- subheader={
- <Typography noWrap variant='body1' color='inherit'>
- {process.containerRequest.description}
- </Typography>
- }
- />
- <CardContent className={classes.content}>
- <Grid container>
- <Grid item xs={12}>
- <ProcessRuntimeStatus runtimeStatus={process.container?.runtimeStatus} />
- </Grid>
- <Grid item xs={6}>
- <DetailsAttribute classLabel={classes.label} classValue={classes.value}
- label='Started at'
- value={startedAt} />
- <DetailsAttribute classLabel={classes.label} classValue={classes.value}
- label='Finished at'
- value={finishedAt} />
- {process.containerRequest.properties.workflowUuid &&
- <span onClick={() => openWorkflow(process.containerRequest.properties.workflowUuid)}>
- <DetailsAttribute classLabel={classes.label} classValue={classNames(classes.value, classes.link)}
- label='Workflow' value={process.containerRequest.properties.workflowName} />
- </span>}
- </Grid>
- <Grid item xs={6}>
- <span onClick={() => navigateToOutput(process.containerRequest.outputUuid!)}>
- <DetailsAttribute classLabel={classes.link} label='Outputs' />
- </span>
- <span onClick={() => openProcessInputDialog(process.containerRequest.uuid)}>
- <DetailsAttribute classLabel={classes.link} label='Inputs' />
- </span>
- </Grid>
- </Grid>
- </CardContent>
- </Card>;
- }
-);
import React from 'react';
import { Grid, StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
-import { ProcessInformationCard } from './process-information-card';
import { DefaultView } from 'components/default-view/default-view';
import { ProcessIcon } from 'components/icon/icon';
import { Process } from 'store/processes/process';
export interface ProcessPanelRootActionProps {
onContextMenu: (event: React.MouseEvent<HTMLElement>, process: Process) => void;
onToggle: (status: string) => void;
- openProcessInputDialog: (uuid: string) => void;
- navigateToOutput: (uuid: string) => void;
- navigateToWorkflow: (uuid: string) => void;
cancelProcess: (uuid: string) => void;
onLogFilterChange: (filter: FilterOption) => void;
navigateToLog: (uuid: string) => void;
export type ProcessPanelRootProps = ProcessPanelRootDataProps & ProcessPanelRootActionProps & WithStyles<CssRules>;
const panelsData: MPVPanelState[] = [
- {name: "Info"},
- {name: "Details", visible: false},
+ {name: "Details"},
{name: "Logs", visible: true},
{name: "Subprocesses"},
];
({ process, processLogsPanel, ...props }: ProcessPanelRootProps) =>
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-info">
- <ProcessInformationCard
+ <MPVPanelContent forwardProps xs="auto" data-cy="process-details">
+ <ProcessDetailsCard
process={process}
onContextMenu={event => props.onContextMenu(event, process)}
- openProcessInputDialog={props.openProcessInputDialog}
- navigateToOutput={props.navigateToOutput}
- openWorkflow={props.navigateToWorkflow}
cancelProcess={props.cancelProcess}
/>
</MPVPanelContent>
- <MPVPanelContent forwardProps xs="auto" data-cy="process-details">
- <ProcessDetailsCard process={process} />
- </MPVPanelContent>
<MPVPanelContent forwardProps xs maxHeight='50%' data-cy="process-logs">
<ProcessLogsCard
onCopy={props.onLogCopyToClipboard}
import { groupBy } from 'lodash';
import {
toggleProcessPanelFilter,
- navigateToOutput,
- openWorkflow
} from 'store/process-panel/process-panel-actions';
-import { openProcessInputDialog } from 'store/processes/process-input-actions';
import { cancelRunningWorkflow } from 'store/processes/processes-actions';
import { navigateToLogCollection, setProcessLogsPanelFilter } from 'store/process-logs-panel/process-logs-panel-actions';
import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
onToggle: status => {
dispatch<any>(toggleProcessPanelFilter(status));
},
- openProcessInputDialog: (uuid) => dispatch<any>(openProcessInputDialog(uuid)),
- navigateToOutput: (uuid) => dispatch<any>(navigateToOutput(uuid)),
- navigateToWorkflow: (uuid) => dispatch<any>(openWorkflow(uuid)),
cancelProcess: (uuid) => dispatch<any>(cancelRunningWorkflow(uuid)),
onLogFilterChange: (filter) => dispatch(setProcessLogsPanelFilter(filter.value)),
navigateToLog: (uuid) => dispatch<any>(navigateToLogCollection(uuid)),