Merge branch '21128-toolbar-context-menu'
[arvados-workbench2.git] / src / views / process-panel / process-resource-card.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React from 'react';
6 import {
7     StyleRulesCallback,
8     WithStyles,
9     withStyles,
10     Card,
11     CardHeader,
12     IconButton,
13     CardContent,
14     Tooltip,
15     Typography,
16     Grid,
17 } from '@material-ui/core';
18 import { ArvadosTheme } from 'common/custom-theme';
19 import {
20     CloseIcon,
21     MaximizeIcon,
22     MemoryIcon,
23     UnMaximizeIcon,
24 } from 'components/icon/icon';
25 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
26 import { connect } from 'react-redux';
27 import { Process } from 'store/processes/process';
28 import { NodeInstanceType } from 'store/process-panel/process-panel';
29 import { DetailsAttribute } from "components/details-attribute/details-attribute";
30 import { formatFileSize } from "common/formatters";
31 import { MountKind } from 'models/mount-types';
32
33 interface ProcessResourceCardDataProps {
34     process: Process;
35     nodeInfo: NodeInstanceType | null;
36 }
37
38 type CssRules = "card" | "header" | "title" | "avatar" | "iconHeader" | "content" | "sectionH3";
39
40 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
41     card: {
42         height: '100%'
43     },
44     header: {
45         paddingBottom: "0px"
46     },
47     title: {
48         paddingTop: theme.spacing.unit * 0.5
49     },
50     avatar: {
51         paddingTop: theme.spacing.unit * 0.5
52     },
53     iconHeader: {
54         fontSize: '1.875rem',
55         color: theme.customs.colors.greyL,
56     },
57     content: {
58         paddingTop: "0px",
59         maxHeight: `calc(100% - ${theme.spacing.unit * 7.5}px)`,
60         overflow: "auto"
61     },
62     sectionH3: {
63         margin: "0.5em",
64         color: theme.customs.colors.greyD,
65         fontSize: "0.8125rem",
66         textTransform: "uppercase",
67     }
68 });
69
70 type ProcessResourceCardProps = ProcessResourceCardDataProps & WithStyles<CssRules> & MPVPanelProps;
71
72 export const ProcessResourceCard = withStyles(styles)(connect()(
73     ({ classes, nodeInfo, doHidePanel, doMaximizePanel, doUnMaximizePanel, panelMaximized, panelName, process, }: ProcessResourceCardProps) => {
74         let diskRequest = 0;
75         if (process.container?.mounts) {
76             for (const mnt in process.container.mounts) {
77                 const mp = process.container.mounts[mnt];
78                 if (mp.kind === MountKind.TEMPORARY_DIRECTORY) {
79                     diskRequest += mp.capacity;
80                 }
81             }
82         }
83
84         return <Card className={classes.card} data-cy="process-resources-card">
85             <CardHeader
86                 className={classes.header}
87                 classes={{
88                     content: classes.title,
89                     avatar: classes.avatar,
90                 }}
91                 avatar={<MemoryIcon className={classes.iconHeader} />}
92                 title={
93                     <Typography noWrap variant='h6' color='inherit'>
94                         Resources
95                     </Typography>
96                 }
97                 action={
98                     <div>
99                         {doUnMaximizePanel && panelMaximized &&
100                             <Tooltip title={`Unmaximize ${panelName || 'panel'}`} disableFocusListener>
101                                 <IconButton onClick={doUnMaximizePanel}><UnMaximizeIcon /></IconButton>
102                             </Tooltip>}
103                         {doMaximizePanel && !panelMaximized &&
104                             <Tooltip title={`Maximize ${panelName || 'panel'}`} disableFocusListener>
105                                 <IconButton onClick={doMaximizePanel}><MaximizeIcon /></IconButton>
106                             </Tooltip>}
107                         {doHidePanel &&
108                             <Tooltip title={`Close ${panelName || 'panel'}`} disableFocusListener>
109                                 <IconButton disabled={panelMaximized} onClick={doHidePanel}><CloseIcon /></IconButton>
110                             </Tooltip>}
111                     </div>
112                 } />
113             <CardContent className={classes.content}>
114                 <Grid container>
115                     <Grid item xs={4}>
116                         <h3 className={classes.sectionH3}>Requested Resources</h3>
117                         <Grid container>
118                             <Grid item xs={12}>
119                                 <DetailsAttribute label="Cores" value={process.container?.runtimeConstraints.vcpus} />
120                             </Grid>
121                             <Grid item xs={12}>
122                                 <DetailsAttribute label="RAM*" value={formatFileSize(process.container?.runtimeConstraints.ram)} />
123                             </Grid>
124                             <Grid item xs={12}>
125                                 <DetailsAttribute label="Disk" value={formatFileSize(diskRequest)} />
126                             </Grid>
127
128                             {process.container?.runtimeConstraints.cuda &&
129                                 process.container?.runtimeConstraints.cuda.device_count > 0 ?
130                                 <>
131                                     <Grid item xs={12}>
132                                         <DetailsAttribute label="CUDA devices" value={process.container?.runtimeConstraints.cuda.device_count} />
133                                     </Grid>
134                                     <Grid item xs={12}>
135                                         <DetailsAttribute label="CUDA driver version" value={process.container?.runtimeConstraints.cuda.driver_version} />
136                                     </Grid>
137                                     <Grid item xs={12}>
138                                         <DetailsAttribute label="CUDA hardware capability" value={process.container?.runtimeConstraints.cuda.hardware_capability} />
139                                     </Grid>
140                                 </> : null}
141
142                             {process.container?.runtimeConstraints.keep_cache_ram &&
143                                 process.container?.runtimeConstraints.keep_cache_ram > 0 ?
144                                 <Grid item xs={12}>
145                                     <DetailsAttribute label="Keep cache (RAM)" value={formatFileSize(process.container?.runtimeConstraints.keep_cache_ram)} />
146                                 </Grid> : null}
147
148                             {process.container?.runtimeConstraints.keep_cache_disk &&
149                                 process.container?.runtimeConstraints.keep_cache_disk > 0 ?
150                                 <Grid item xs={12}>
151                                     <DetailsAttribute label="Keep cache (disk)" value={formatFileSize(process.container?.runtimeConstraints.keep_cache_disk)} />
152                                 </Grid> : null}
153
154                             {process.container?.runtimeConstraints.API ? <Grid item xs={12}>
155                                 <DetailsAttribute label="API access" value={process.container?.runtimeConstraints.API.toString()} />
156                             </Grid> : null}
157
158                         </Grid>
159                     </Grid>
160
161
162                     <Grid item xs={8}>
163                         <h3 className={classes.sectionH3}>Assigned Instance Type</h3>
164                         {nodeInfo === null ? <Grid item xs={8}>
165                             No instance type recorded
166                         </Grid>
167                             :
168                             <Grid container>
169                                 <Grid item xs={6}>
170                                     <DetailsAttribute label="Cores" value={nodeInfo.VCPUs} />
171                                 </Grid>
172
173                                 <Grid item xs={6}>
174                                     <DetailsAttribute label="Provider type" value={nodeInfo.ProviderType} />
175                                 </Grid>
176
177                                 <Grid item xs={6}>
178                                     <DetailsAttribute label="RAM" value={formatFileSize(nodeInfo.RAM)} />
179                                 </Grid>
180
181                                 <Grid item xs={6}>
182                                     <DetailsAttribute label="Price" value={"$" + nodeInfo.Price.toString()} />
183                                 </Grid>
184
185                                 <Grid item xs={6}>
186                                     <DetailsAttribute label="Disk" value={formatFileSize(nodeInfo.IncludedScratch + nodeInfo.AddedScratch)} />
187                                 </Grid>
188
189                                 <Grid item xs={6}>
190                                     <DetailsAttribute label="Preemptible" value={nodeInfo.Preemptible.toString()} />
191                                 </Grid>
192
193                                 {nodeInfo.CUDA && nodeInfo.CUDA.DeviceCount > 0 &&
194                                     <>
195                                         <Grid item xs={6}>
196                                             <DetailsAttribute label="CUDA devices" value={nodeInfo.CUDA.DeviceCount} />
197                                         </Grid>
198
199                                         <Grid item xs={6}>
200                                         </Grid>
201
202                                         <Grid item xs={6}>
203                                             <DetailsAttribute label="CUDA driver version" value={nodeInfo.CUDA.DriverVersion} />
204                                         </Grid>
205
206                                         <Grid item xs={6}>
207                                         </Grid>
208
209                                         <Grid item xs={6}>
210                                             <DetailsAttribute label="CUDA hardware capability" value={nodeInfo.CUDA.HardwareCapability} />
211                                         </Grid>
212                                     </>
213                                 }
214                             </Grid>}
215                     </Grid>
216                 </Grid>
217                 <Typography>* RAM available to the program is limited to Requested RAM, not Instance RAM</Typography>
218             </CardContent>
219         </Card >;
220     }
221 ));