1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import React, { useState } from 'react';
17 } from '@material-ui/core';
18 import { useAsyncInterval } from 'common/use-async-interval';
19 import { ArvadosTheme } from 'common/custom-theme';
31 } from 'components/icon/icon';
32 import { Process, isProcessRunning } from 'store/processes/process';
33 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
37 } from 'views/process-panel/process-log-form';
38 import { ProcessLogCodeSnippet } from 'views/process-panel/process-log-code-snippet';
39 import { DefaultView } from 'components/default-view/default-view';
40 import { CodeSnippetDataProps } from 'components/code-snippet/code-snippet';
41 import CopyToClipboard from 'react-copy-to-clipboard';
43 type CssRules = 'card' | 'content' | 'title' | 'iconHeader' | 'header' | 'root' | 'logViewer' | 'logViewerContainer';
45 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
50 paddingTop: theme.spacing.unit,
51 paddingBottom: theme.spacing.unit,
54 padding: theme.spacing.unit * 0,
59 overflowY: 'scroll', // Required for MacOS's Safari -- See #19687
66 paddingTop: theme.spacing.unit * 0.5,
67 color: theme.customs.colors.greyD
71 color: theme.customs.colors.greyL
78 export interface ProcessLogsCardDataProps {
80 selectedFilter: FilterOption;
81 filters: FilterOption[];
84 export interface ProcessLogsCardActionProps {
85 onLogFilterChange: (filter: FilterOption) => void;
86 navigateToLog: (uuid: string) => void;
87 onCopy: (text: string) => void;
88 pollProcessLogs: (processUuid: string) => Promise<void>;
91 type ProcessLogsCardProps = ProcessLogsCardDataProps
92 & ProcessLogsCardActionProps
93 & CodeSnippetDataProps
94 & WithStyles<CssRules>
97 export const ProcessLogsCard = withStyles(styles)(
98 ({ classes, process, filters, selectedFilter, lines,
99 onLogFilterChange, navigateToLog, onCopy, pollProcessLogs,
100 doHidePanel, doMaximizePanel, doUnMaximizePanel, panelMaximized, panelName }: ProcessLogsCardProps) => {
101 const [wordWrap, setWordWrap] = useState<boolean>(true);
102 const [fontSize, setFontSize] = useState<number>(3);
103 const fontBaseSize = 10;
104 const fontStepSize = 1;
106 useAsyncInterval(() => (
107 pollProcessLogs(process.containerRequest.uuid)
108 ), isProcessRunning(process) ? 2000 : null);
110 return <Grid item className={classes.root} xs={12}>
111 <Card className={classes.card}>
112 <CardHeader className={classes.header}
113 avatar={<LogIcon className={classes.iconHeader} />}
114 action={<Grid container direction='row' alignItems='center'>
116 <ProcessLogForm selectedFilter={selectedFilter}
117 filters={filters} onChange={onLogFilterChange} />
120 <Tooltip title="Decrease font size" disableFocusListener>
121 <IconButton onClick={() => fontSize > 1 && setFontSize(fontSize-1)}>
127 <Tooltip title="Increase font size" disableFocusListener>
128 <IconButton onClick={() => fontSize < 5 && setFontSize(fontSize+1)}>
134 <Tooltip title="Copy to clipboard" disableFocusListener>
136 <CopyToClipboard text={lines.join()} onCopy={() => onCopy("Log copied to clipboard")}>
143 <Tooltip title={`${wordWrap ? 'Disable' : 'Enable'} word wrapping`} disableFocusListener>
144 <IconButton onClick={() => setWordWrap(!wordWrap)}>
145 {wordWrap ? <WordWrapOffIcon /> : <WordWrapOnIcon />}
150 <Tooltip title="Go to Log collection" disableFocusListener>
151 <IconButton onClick={() => navigateToLog(process.containerRequest.logUuid!)}>
156 { doUnMaximizePanel && panelMaximized &&
157 <Tooltip title={`Unmaximize ${panelName || 'panel'}`} disableFocusListener>
158 <IconButton onClick={doUnMaximizePanel}><UnMaximizeIcon /></IconButton>
160 { doMaximizePanel && !panelMaximized &&
161 <Tooltip title={`Maximize ${panelName || 'panel'}`} disableFocusListener>
162 <IconButton onClick={doMaximizePanel}><MaximizeIcon /></IconButton>
165 <Tooltip title={`Close ${panelName || 'panel'}`} disableFocusListener>
166 <IconButton disabled={panelMaximized} onClick={doHidePanel}><CloseIcon /></IconButton>
170 <Typography noWrap variant='h6' className={classes.title}>
174 <CardContent className={classes.content}>
177 className={classes.logViewerContainer}
181 <Grid className={classes.logViewer} item xs>
182 <ProcessLogCodeSnippet fontSize={fontBaseSize+(fontStepSize*fontSize)} wordWrap={wordWrap} lines={lines} />
187 messages={['No logs yet']} />