bbb4ff9dc62e126ba04d83aebaa566f733b094fc
[arvados-workbench2.git] / src / views / process-panel / process-log-card.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React, { useState } from 'react';
6 import {
7     StyleRulesCallback,
8     WithStyles,
9     withStyles,
10     Card,
11     CardHeader,
12     IconButton,
13     CardContent,
14     Tooltip,
15     Grid,
16     Typography,
17 } from '@material-ui/core';
18 import { ArvadosTheme } from 'common/custom-theme';
19 import {
20     CloseIcon,
21     CollectionIcon,
22     LogIcon,
23     MaximizeIcon,
24     WordWrapIcon
25 } from 'components/icon/icon';
26 import { Process } from 'store/processes/process';
27 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
28 import {
29     FilterOption,
30     ProcessLogForm
31 } from 'views/process-panel/process-log-form';
32 import { ProcessLogCodeSnippet } from 'views/process-panel/process-log-code-snippet';
33 import { DefaultView } from 'components/default-view/default-view';
34 import { CodeSnippetDataProps } from 'components/code-snippet/code-snippet';
35
36 type CssRules = 'card' | 'content' | 'title' | 'iconHeader' | 'header' | 'root' | 'logViewer' | 'logViewerContainer';
37
38 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
39     card: {
40         height: '100%'
41     },
42     header: {
43         paddingTop: theme.spacing.unit,
44         paddingBottom: theme.spacing.unit,
45     },
46     content: {
47         padding: theme.spacing.unit * 0,
48         height: '100%',
49     },
50     logViewer: {
51         height: '100%',
52     },
53     logViewerContainer: {
54         height: '100%',
55     },
56     title: {
57         overflow: 'hidden',
58         paddingTop: theme.spacing.unit * 0.5
59     },
60     iconHeader: {
61         fontSize: '1.875rem',
62         color: theme.customs.colors.green700
63     },
64     root: {
65         height: '100%',
66     },
67 });
68
69 export interface ProcessLogsCardDataProps {
70     process: Process;
71     selectedFilter: FilterOption;
72     filters: FilterOption[];
73 }
74
75 export interface ProcessLogsCardActionProps {
76     onLogFilterChange: (filter: FilterOption) => void;
77     navigateToLog: (uuid: string) => void;
78 }
79
80 type ProcessLogsCardProps = ProcessLogsCardDataProps
81     & ProcessLogsCardActionProps
82     & CodeSnippetDataProps
83     & WithStyles<CssRules>
84     & MPVPanelProps;
85
86 export const ProcessLogsCard = withStyles(styles)(
87     ({ classes, process, filters, selectedFilter, lines, onLogFilterChange, navigateToLog,
88         doHidePanel, doMaximizePanel, panelMaximized, panelName }: ProcessLogsCardProps) => {
89         const [wordWrapToggle, setWordWrapToggle] = useState<boolean>(true);
90         return <Grid item className={classes.root} xs={12}>
91             <Card className={classes.card}>
92                 <CardHeader className={classes.header}
93                     avatar={<LogIcon className={classes.iconHeader} />}
94                     action={<Grid container direction='row' alignItems='center'>
95                         <Grid item>
96                             <ProcessLogForm selectedFilter={selectedFilter}
97                                 filters={filters} onChange={onLogFilterChange} />
98                         </Grid>
99                         <Grid item>
100                             <Tooltip title="Toggle word wrapping" disableFocusListener>
101                                 <IconButton onClick={() => setWordWrapToggle(!wordWrapToggle)}>
102                                     <WordWrapIcon />
103                                 </IconButton>
104                             </Tooltip>
105                         </Grid>
106                         <Grid item>
107                             <Tooltip title="Go to Log collection" disableFocusListener>
108                                 <IconButton onClick={() => navigateToLog(process.containerRequest.logUuid!)}>
109                                     <CollectionIcon />
110                                 </IconButton>
111                             </Tooltip>
112                         </Grid>
113                         { doMaximizePanel && !panelMaximized &&
114                         <Tooltip title={`Maximize ${panelName || 'panel'}`} disableFocusListener>
115                             <IconButton onClick={doMaximizePanel}><MaximizeIcon /></IconButton>
116                         </Tooltip> }
117                         { doHidePanel && <Grid item>
118                             <Tooltip title={`Close ${panelName || 'panel'}`} disableFocusListener>
119                                 <IconButton onClick={doHidePanel}><CloseIcon /></IconButton>
120                             </Tooltip>
121                         </Grid> }
122                     </Grid>}
123                     title={
124                         <Typography noWrap variant='h6' className={classes.title}>
125                             Logs
126                         </Typography>}
127                 />
128                 <CardContent className={classes.content}>
129                     {lines.length > 0
130                         ? < Grid
131                             className={classes.logViewerContainer}
132                             container
133                             spacing={24}
134                             direction='column'>
135                             <Grid className={classes.logViewer} item xs>
136                                 <ProcessLogCodeSnippet wordWrap={wordWrapToggle} lines={lines} />
137                             </Grid>
138                         </Grid>
139                         : <DefaultView
140                             icon={LogIcon}
141                             messages={['No logs yet']} />
142                     }
143                 </CardContent>
144             </Card>
145         </Grid >
146 });
147