1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import React from 'react';
17 } from '@material-ui/core';
18 import { ArvadosTheme } from 'common/custom-theme';
19 import { CloseIcon, CommandIcon, CopyIcon } from 'components/icon/icon';
20 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
21 import { DefaultVirtualCodeSnippet } from 'components/default-code-snippet/default-virtual-code-snippet';
22 import { Process } from 'store/processes/process';
23 import shellescape from 'shell-escape';
24 import CopyResultToClipboard from 'components/copy-to-clipboard/copy-result-to-clipboard';
26 type CssRules = 'card' | 'content' | 'title' | 'header' | 'avatar' | 'iconHeader';
28 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
33 paddingTop: theme.spacing.unit,
38 color: theme.customs.colors.greyL,
41 alignSelf: 'flex-start',
42 paddingTop: theme.spacing.unit * 0.5
45 height: `calc(100% - ${theme.spacing.unit * 6}px)`,
46 padding: theme.spacing.unit * 1.0,
49 paddingBottom: theme.spacing.unit * 1,
54 paddingTop: theme.spacing.unit * 0.5,
55 color: theme.customs.colors.greyD,
60 interface ProcessCmdCardDataProps {
62 onCopy: (text: string) => void;
65 type ProcessCmdCardProps = ProcessCmdCardDataProps & WithStyles<CssRules> & MPVPanelProps;
67 export const ProcessCmdCard = withStyles(styles)(
73 }: ProcessCmdCardProps) => {
75 const formatLine = (lines: string[], index: number): string => {
76 // Escape each arg separately
77 let line = shellescape([lines[index]])
78 // Indent lines after the first
79 const indent = index > 0 ? ' ' : '';
80 // Add backslash "escaped linebreak"
81 const lineBreak = lines.length > 1 && index < lines.length - 1 ? ' \\' : '';
83 return `${indent}${line}${lineBreak}`;
86 const formatClipboardText = (command: string[]) => (): string => (
88 shellescape([v]) // Escape each arg separately
93 <Card className={classes.card}>
95 className={classes.header}
97 content: classes.title,
98 avatar: classes.avatar,
100 avatar={<CommandIcon className={classes.iconHeader} />}
102 <Typography noWrap variant="h6" color="inherit">
107 <Grid container direction="row" alignItems="center">
109 <Tooltip title="Copy link to clipboard" disableFocusListener>
111 <CopyResultToClipboard
112 getText={formatClipboardText(process.containerRequest.command)}
113 onCopy={() => onCopy("Command copied to clipboard")}
116 </CopyResultToClipboard>
123 title={`Close Command Panel`}
126 <IconButton onClick={doHidePanel}>
135 <CardContent className={classes.content}>
136 <DefaultVirtualCodeSnippet
137 lines={process.containerRequest.command}
138 lineFormatter={formatLine}