21224: set up user card Arvados-DCO-1.1-Signed-off-by: Lisa Knox <lisa.knox@curii...
[arvados.git] / services / workbench2 / src / views-components / project-details-card / project-details-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 { Card, CardHeader, WithStyles, withStyles, Typography, CardContent } from '@material-ui/core';
7 import { StyleRulesCallback } from '@material-ui/core';
8 import { ArvadosTheme } from 'common/custom-theme';
9 import { RootState } from 'store/store';
10 import { connect } from 'react-redux';
11 import { getResource } from 'store/resources/resources';
12 import { MultiselectToolbar } from 'components/multiselect-toolbar/MultiselectToolbar';
13 import { DetailsAttribute } from 'components/details-attribute/details-attribute';
14 import { RichTextEditorLink } from 'components/rich-text-editor-link/rich-text-editor-link';
15 import { getPropertyChip } from '../resource-properties-form/property-chip';
16 import { ProjectResource } from 'models/project';
17 import { GroupClass } from 'models/group';
18 import { ResourceWithName } from 'views-components/data-explorer/renderers';
19 import { formatDate } from 'common/formatters';
20 import { resourceLabel } from 'common/labels';
21 import { ResourceKind } from 'models/resource';
22 import { UserResource } from 'models/user';
23 import { UserResourceAccountStatus } from 'views-components/data-explorer/renderers';
24
25
26
27 type CssRules = 'root' | 'cardheader' | 'fadeout' | 'nameContainer' | 'activeIndicator' | 'cardcontent' | 'attributesection' | 'attribute' | 'chipsection' | 'tag';
28
29 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
30     root: {
31         width: '100%',
32         marginBottom: '1rem',
33     },
34     fadeout: {
35         maxWidth: '30rem',
36         minWdidth: '18rem',
37         height: '2.5rem',
38         overflow: 'hidden',
39         WebkitMaskImage: '-webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,1)), to(rgba(0,0,0,0)))',
40     },
41     nameContainer: {
42         display: 'flex',
43     },
44     activeIndicator: {
45         margin: '0.3rem auto auto 1rem',
46     },
47     cardheader: {
48         paddingTop: '0.4rem',
49     },
50     cardcontent: {
51         display: 'flex',
52         flexDirection: 'column',
53         marginTop: '-1rem',
54     },
55     attributesection: {
56         display: 'flex',
57         flexWrap: 'wrap',
58     },
59     attribute: {
60         marginBottom: '0.5rem',
61         marginRight: '1rem',
62         border: '1px solid lightgrey',
63         padding: '0.5rem',
64         borderRadius: '5px',
65     },
66     chipsection: {
67         display: 'flex',
68         flexWrap: 'wrap',
69     },
70     tag: {
71         marginRight: '1rem',
72         marginTop: '0.5rem',
73     },
74 });
75
76 const mapStateToProps = (state: RootState) => {
77     const currentRoute = state.router.location?.pathname.split('/') || [];
78     const currentItemUuid = currentRoute[currentRoute.length - 1];
79     const currentResource = getResource(currentItemUuid)(state.resources);
80     return {
81         currentResource,
82     };
83 };
84
85 type DetailsCardProps = {
86     currentResource: ProjectResource | UserResource;
87 };
88
89 export const ProjectDetailsCard = connect(mapStateToProps)(
90     withStyles(styles)((props: DetailsCardProps & WithStyles<CssRules>) => {
91         const { currentResource } = props;
92         return (currentResource.kind as string) === ResourceKind.USER ? <UserCard props={props} /> : <ProjectCard props={props} />;
93     })
94 );
95
96 const UserCard = ({ props }) => {
97     const { classes, currentResource } = props;
98     const { fullName, uuid, username, email, isAdmin } = currentResource as UserResource & { fullName: string };
99
100     return (
101         <Card className={classes.root}>
102             <CardHeader
103                 className={classes.cardheader}
104                 title={
105                     <section className={classes.nameContainer}>
106                         <Typography
107                             noWrap
108                             variant='h6'
109                             >
110                             {fullName}
111                         </Typography>
112                         <Typography
113                             className={classes.activeIndicator}
114                         >
115                             <UserResourceAccountStatus uuid={uuid} />
116                         </Typography>
117                     </section>
118                 }
119                 action={
120                 <MultiselectToolbar inputSelectedUuid={uuid} />
121                 }
122             />
123             <CardContent className={classes.cardcontent}>
124                 <section className={classes.attributesection}>
125                     <Typography
126                         component='div'
127                         className={classes.attribute}
128                     >
129                         <DetailsAttribute
130                             label='Username'
131                             value={username}
132                         />
133                     </Typography>
134                     <Typography
135                         component='div'
136                         className={classes.attribute}
137                     >
138                         <DetailsAttribute
139                             label='Email'
140                             value={email}
141                         />
142                     </Typography>
143                     <Typography
144                         component='div'
145                         className={classes.attribute}
146                     >
147                         <DetailsAttribute
148                             label='Admin'
149                             value={isAdmin ? 'Yes' : 'No'}
150                         />
151                     </Typography>
152                     <Typography
153                         component='div'
154                         className={classes.attribute}
155                     >
156                         <DetailsAttribute
157                             label='UUID'
158                             linkToUuid={currentResource.uuid}
159                             value={currentResource.uuid}
160                         />
161                     </Typography>
162                 </section>
163             </CardContent>
164         </Card>
165     );
166 };
167
168 const ProjectCard = ({ props }) => {
169     const { classes, currentResource } = props;
170     const { name, uuid, description } = currentResource as ProjectResource;
171     return (
172         <Card className={classes.root}>
173             <CardHeader
174                 className={classes.cardheader}
175                 title={
176                     <Typography
177                         noWrap
178                         variant='h6'
179                     >
180                         {name}
181                     </Typography>
182                 }
183                 subheader={
184                     description ? (
185                         <section>
186                             <Typography className={classes.fadeout}>{description.replace(/<[^>]*>/g, '')}</Typography>
187                             <RichTextEditorLink
188                                 title={`Description of ${name}`}
189                                 content={description}
190                                 label='Show full description'
191                             />
192                         </section>
193                     ) : (
194                         'no description available'
195                     )
196                 }
197                 action={<MultiselectToolbar inputSelectedUuid={uuid} />}
198                 
199             />
200             <CardContent className={classes.cardcontent}>
201                 <section className={classes.attributesection}>
202                     <Typography
203                         component='div'
204                         className={classes.attribute}
205                     >
206                         <DetailsAttribute
207                             label='Type'
208                             value={currentResource.groupClass === GroupClass.FILTER ? 'Filter group' : resourceLabel(ResourceKind.PROJECT)}
209                         />
210                     </Typography>
211                     <Typography
212                         component='div'
213                         className={classes.attribute}
214                     >
215                         <DetailsAttribute
216                             label='Owner'
217                             linkToUuid={currentResource.ownerUuid}
218                             uuidEnhancer={(uuid: string) => <ResourceWithName uuid={uuid} />}
219                         />
220                     </Typography>
221                     <Typography
222                         component='div'
223                         className={classes.attribute}
224                     >
225                         <DetailsAttribute
226                             label='Last modified'
227                             value={formatDate(currentResource.modifiedAt)}
228                         />
229                     </Typography>
230                     <Typography
231                         component='div'
232                         className={classes.attribute}
233                     >
234                         <DetailsAttribute
235                             label='Created at'
236                             value={formatDate(currentResource.createdAt)}
237                         />
238                     </Typography>
239                     <Typography
240                         component='div'
241                         className={classes.attribute}
242                     >
243                         <DetailsAttribute
244                             label='UUID'
245                             linkToUuid={currentResource.uuid}
246                             value={currentResource.uuid}
247                         />
248                     </Typography>
249                 </section>
250                 <section className={classes.chipsection}>
251                     <Typography component='div'>
252                         {typeof currentResource.properties === 'object' &&
253                             Object.keys(currentResource.properties).map((k) =>
254                                 Array.isArray(currentResource.properties[k])
255                                     ? currentResource.properties[k].map((v: string) => getPropertyChip(k, v, undefined, classes.tag))
256                                     : getPropertyChip(k, currentResource.properties[k], undefined, classes.tag)
257                             )}
258                     </Typography>
259                 </section>
260             </CardContent>
261         </Card>
262     );
263 };