16672: Adds font size control to the log viewer.
[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     TextDecreaseIcon,
25     TextIncreaseIcon,
26     WordWrapIcon
27 } from 'components/icon/icon';
28 import { Process } from 'store/processes/process';
29 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
30 import {
31     FilterOption,
32     ProcessLogForm
33 } from 'views/process-panel/process-log-form';
34 import { ProcessLogCodeSnippet } from 'views/process-panel/process-log-code-snippet';
35 import { DefaultView } from 'components/default-view/default-view';
36 import { CodeSnippetDataProps } from 'components/code-snippet/code-snippet';
37
38 type CssRules = 'card' | 'content' | 'title' | 'iconHeader' | 'header' | 'root' | 'logViewer' | 'logViewerContainer';
39
40 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
41     card: {
42         height: '100%'
43     },
44     header: {
45         paddingTop: theme.spacing.unit,
46         paddingBottom: theme.spacing.unit,
47     },
48     content: {
49         padding: theme.spacing.unit * 0,
50         height: '100%',
51     },
52     logViewer: {
53         height: '100%',
54     },
55     logViewerContainer: {
56         height: '100%',
57     },
58     title: {
59         overflow: 'hidden',
60         paddingTop: theme.spacing.unit * 0.5
61     },
62     iconHeader: {
63         fontSize: '1.875rem',
64         color: theme.customs.colors.green700
65     },
66     root: {
67         height: '100%',
68     },
69 });
70
71 export interface ProcessLogsCardDataProps {
72     process: Process;
73     selectedFilter: FilterOption;
74     filters: FilterOption[];
75 }
76
77 export interface ProcessLogsCardActionProps {
78     onLogFilterChange: (filter: FilterOption) => void;
79     navigateToLog: (uuid: string) => void;
80 }
81
82 type ProcessLogsCardProps = ProcessLogsCardDataProps
83     & ProcessLogsCardActionProps
84     & CodeSnippetDataProps
85     & WithStyles<CssRules>
86     & MPVPanelProps;
87
88 export const ProcessLogsCard = withStyles(styles)(
89     ({ classes, process, filters, selectedFilter, lines, onLogFilterChange, navigateToLog,
90         doHidePanel, doMaximizePanel, panelMaximized, panelName }: ProcessLogsCardProps) => {
91         const [wordWrapToggle, setWordWrapToggle] = useState<boolean>(true);
92         const [fontSize, setFontSize] = useState<number>(3);
93         const fontBaseSize = 10;
94         const fontStepSize = 1;
95
96         return <Grid item className={classes.root} xs={12}>
97             <Card className={classes.card}>
98                 <CardHeader className={classes.header}
99                     avatar={<LogIcon className={classes.iconHeader} />}
100                     action={<Grid container direction='row' alignItems='center'>
101                         <Grid item>
102                             <ProcessLogForm selectedFilter={selectedFilter}
103                                 filters={filters} onChange={onLogFilterChange} />
104                         </Grid>
105                         <Grid item>
106                             <Tooltip title="Decrease font size" disableFocusListener>
107                                 <IconButton onClick={() => fontSize > 1 && setFontSize(fontSize-1)}>
108                                     <TextDecreaseIcon />
109                                 </IconButton>
110                             </Tooltip>
111                         </Grid>
112                         <Grid item>
113                             <Tooltip title="Increase font size" disableFocusListener>
114                                 <IconButton onClick={() => fontSize < 5 && setFontSize(fontSize+1)}>
115                                     <TextIncreaseIcon />
116                                 </IconButton>
117                             </Tooltip>
118                         </Grid>
119                         <Grid item>
120                             <Tooltip title="Toggle word wrapping" disableFocusListener>
121                                 <IconButton onClick={() => setWordWrapToggle(!wordWrapToggle)}>
122                                     <WordWrapIcon />
123                                 </IconButton>
124                             </Tooltip>
125                         </Grid>
126                         <Grid item>
127                             <Tooltip title="Go to Log collection" disableFocusListener>
128                                 <IconButton onClick={() => navigateToLog(process.containerRequest.logUuid!)}>
129                                     <CollectionIcon />
130                                 </IconButton>
131                             </Tooltip>
132                         </Grid>
133                         { doMaximizePanel && !panelMaximized &&
134                         <Tooltip title={`Maximize ${panelName || 'panel'}`} disableFocusListener>
135                             <IconButton onClick={doMaximizePanel}><MaximizeIcon /></IconButton>
136                         </Tooltip> }
137                         { doHidePanel && <Grid item>
138                             <Tooltip title={`Close ${panelName || 'panel'}`} disableFocusListener>
139                                 <IconButton onClick={doHidePanel}><CloseIcon /></IconButton>
140                             </Tooltip>
141                         </Grid> }
142                     </Grid>}
143                     title={
144                         <Typography noWrap variant='h6' className={classes.title}>
145                             Logs
146                         </Typography>}
147                 />
148                 <CardContent className={classes.content}>
149                     {lines.length > 0
150                         ? < Grid
151                             className={classes.logViewerContainer}
152                             container
153                             spacing={24}
154                             direction='column'>
155                             <Grid className={classes.logViewer} item xs>
156                                 <ProcessLogCodeSnippet fontSize={fontBaseSize+(fontStepSize*fontSize)} wordWrap={wordWrapToggle} lines={lines} />
157                             </Grid>
158                         </Grid>
159                         : <DefaultView
160                             icon={LogIcon}
161                             messages={['No logs yet']} />
162                     }
163                 </CardContent>
164             </Card>
165         </Grid >
166 });
167