1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import React from 'react';
6 import { CustomStyleRulesCallback } from 'common/custom-theme';
7 import { Card, CardHeader, IconButton, CardContent, Tooltip, Typography, Grid } from '@mui/material';
8 import { WithStyles } from '@mui/styles';
9 import withStyles from '@mui/styles/withStyles';
10 import { ArvadosTheme } from 'common/custom-theme';
11 import { CloseIcon, CommandIcon, CopyIcon } from 'components/icon/icon';
12 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
13 import { DefaultVirtualCodeSnippet } from 'components/default-code-snippet/default-virtual-code-snippet';
14 import { Process } from 'store/processes/process';
15 import shellescape from 'shell-escape';
16 import CopyResultToClipboard from 'components/copy-to-clipboard/copy-result-to-clipboard';
18 type CssRules = 'card' | 'content' | 'title' | 'header' | 'avatar' | 'iconHeader';
20 const styles: CustomStyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
25 paddingTop: theme.spacing(1),
30 color: theme.customs.colors.greyL,
33 alignSelf: 'flex-start',
34 paddingTop: theme.spacing(0.5)
37 height: `calc(100% - ${theme.spacing(6)})`,
38 padding: theme.spacing(1),
41 paddingBottom: theme.spacing(1),
46 paddingTop: theme.spacing(0.5),
47 color: theme.customs.colors.greyD,
52 interface ProcessCmdCardDataProps {
54 onCopy: (text: string) => void;
57 type ProcessCmdCardProps = ProcessCmdCardDataProps & WithStyles<CssRules> & MPVPanelProps;
59 export const ProcessCmdCard = withStyles(styles)(
65 }: ProcessCmdCardProps) => {
67 const formatLine = (lines: string[], index: number): string => {
68 // Escape each arg separately
69 let line = shellescape([lines[index]])
70 // Indent lines after the first
71 const indent = index > 0 ? ' ' : '';
72 // Add backslash "escaped linebreak"
73 const lineBreak = lines.length > 1 && index < lines.length - 1 ? ' \\' : '';
75 return `${indent}${line}${lineBreak}`;
78 const formatClipboardText = (command: string[]) => (): string => (
80 shellescape([v]) // Escape each arg separately
85 <Card className={classes.card}>
87 className={classes.header}
89 content: classes.title,
90 avatar: classes.avatar,
92 avatar={<CommandIcon className={classes.iconHeader} />}
94 <Typography noWrap variant="h6" color="inherit">
99 <Grid container direction="row" alignItems="center">
101 <Tooltip title="Copy link to clipboard" disableFocusListener>
102 <IconButton size="large">
103 <CopyResultToClipboard
104 getText={formatClipboardText(process.containerRequest.command)}
105 onCopy={() => onCopy("Command copied to clipboard")}
108 </CopyResultToClipboard>
115 title={`Close Command Panel`}
118 <IconButton onClick={doHidePanel} size="large">
127 <CardContent className={classes.content}>
128 <DefaultVirtualCodeSnippet
129 lines={process.containerRequest.command}
130 lineFormatter={formatLine}