]> git.arvados.org - arvados.git/blob - services/workbench2/src/components/overview-panel/overview-panel.tsx
23063: combined property chip generation to eliminate duplicate code
[arvados.git] / services / workbench2 / src / components / overview-panel / overview-panel.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 { connect } from 'react-redux';
7 import { Grid, Typography } from '@mui/material';
8 import { RootState } from 'store/store';
9 import { CustomStyleRulesCallback } from 'common/custom-theme';
10 import { ArvadosTheme } from 'common/custom-theme';
11 import withStyles from '@mui/styles/withStyles';
12 import { WithStyles } from '@mui/styles';
13 import { getResource } from 'store/resources/resources';
14 import { DetailsAttribute } from 'components/details-attribute/details-attribute';
15 import { getPropertyChip } from 'views-components/resource-properties-form/property-chip';
16 import { ExpandChevronRight } from 'components/expand-chevron-right/expand-chevron-right';
17 import { CollapsibleDescription } from 'components/collapsible-description/collapsible-description';
18 import { CollectionResource } from 'models/collection';
19 import { ProjectResource } from 'models/project';
20 import { WorkflowResource } from 'models/workflow';
21 import { ResourceKind } from 'models/resource';
22 import { Process, getProcess } from 'store/processes/process';
23 import { ContainerRequestResource } from 'models/container-request';
24 import { ContainerResource } from 'models/container';
25 import { ProcessRuntimeStatus } from 'views-components/process-runtime-status/process-runtime-status';
26 import { isUserResource } from 'models/user';
27 import { getRegisteredWorkflowPanelData } from 'views-components/details-panel/workflow-details';
28 import { AuthState } from 'store/auth/auth-reducer';
29 import { DataTableDefaultView } from 'components/data-table-default-view/data-table-default-view';
30 import { getPropertyChips } from 'views-components/property-chips/get-property-chips';
31
32 type CssRules = 'root' | 'tag';
33
34 const styles: CustomStyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
35     root: {
36         width: '100%',
37         height: '100%',
38         display: 'flex',
39         flexDirection: 'column',
40         justifyContent: 'space-between',
41         padding: theme.spacing(1),
42     },
43     tag: {
44         marginRight: theme.spacing(0.5),
45         marginBottom: theme.spacing(0.5),
46     },
47 });
48
49 type OverviewPanelProps = {
50     auth: AuthState;
51     resource: ProjectResource | CollectionResource | ContainerRequestResource | WorkflowResource | undefined;
52     process?: Process;
53     container?: ContainerResource;
54     detailsElement: React.ReactNode;
55     progressIndicator: string[];
56 } & WithStyles<CssRules>;
57
58 const mapStateToProps = (state: RootState): Pick<OverviewPanelProps, 'auth' |'resource' | 'container' | 'progressIndicator'> => {
59     const resource = getResource<any>(state.properties.currentRouteUuid)(state.resources);
60     const process = getProcess(resource?.uuid)(state.resources) || undefined;
61     return {
62         auth: state.auth,
63         resource: resource?.containerRequest ? process : resource,
64         container: process?.container,
65         progressIndicator: state.progressIndicator
66     };
67 };
68
69 export const OverviewPanel = connect(mapStateToProps)(withStyles(styles)((({ auth,resource, container, detailsElement, progressIndicator, classes }: OverviewPanelProps) => {
70     const working = progressIndicator.length > 0;
71     if (isUserResource(resource)) {
72         return null
73     };
74     if (!resource) {
75         if (!working) {
76             return <DataTableDefaultView />
77         };
78         return null;
79     }
80     const hasDescription = resource.description && resource.description.length > 0;
81     const [showDescription, setShowDescription] = useState(false);
82
83     React.useEffect(() => {
84         setShowDescription(false);
85     }, [resource]);
86
87     return (
88         <section className={classes.root}>
89             <section>
90                 {resource.kind === ResourceKind.CONTAINER_REQUEST && <Grid item xs={12}>
91                     <ProcessRuntimeStatus runtimeStatus={container?.runtimeStatus} containerCount={resource.containerCount} />
92                 </Grid>}
93                 <Grid item xs={12} md={12}>
94                     <DetailsAttribute
95                         label={'Description'}
96                         button={hasDescription
97                                     ? <ExpandChevronRight expanded={showDescription} onClick={() => setShowDescription(!showDescription)} />
98                                     : undefined}>
99                         {hasDescription
100                             ? <CollapsibleDescription description={resource.description} showDescription={showDescription} />
101                             : <Typography>No description available</Typography>}
102                     </DetailsAttribute>
103                     <section data-cy='details-element'>
104                         {detailsElement}
105                     </section>
106                 </Grid>
107             </section>
108             <PropertiesElement auth={auth} resource={resource} classes={classes} />
109         </section>
110     );
111 })));
112
113 const PropertiesElement = ({auth, resource, classes}: { auth: AuthState, resource: ProjectResource | CollectionResource | ContainerRequestResource | WorkflowResource | undefined, classes: any }) => {
114     if (!resource) {
115         return null;
116     }
117     if (resource.kind === ResourceKind.WORKFLOW) {
118         const wfData = getRegisteredWorkflowPanelData(resource, auth);
119         if (Object.keys(wfData.gitprops).length === 0) {
120             return null;
121         }
122         return <section data-cy='resource-properties'>
123             {Object.keys(wfData.gitprops).map(k =>
124                 getPropertyChip(k, wfData.gitprops[k], undefined, classes.tag)
125             )}
126         </section>;
127     }
128     if (typeof resource.properties === 'object' && Object.keys(resource.properties).length > 0) {
129         return getPropertyChips(resource, classes);
130     }
131     return null;
132 }