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