21762: added trycatch to observer callback
[arvados.git] / services / workbench2 / src / views-components / details-card / user-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 { StyleRulesCallback, Card, CardHeader, WithStyles, withStyles, Typography, Grid } from '@material-ui/core';
7 import { ArvadosTheme } from 'common/custom-theme';
8 import { UserResource } from 'models/user';
9 import { connect } from 'react-redux';
10 import { getResource } from 'store/resources/resources';
11 import { UserResourceAccountStatus } from 'views-components/data-explorer/renderers';
12 import { MultiselectToolbar } from 'components/multiselect-toolbar/MultiselectToolbar';
13 import { RootState } from 'store/store';
14 import { Dispatch } from 'redux';
15 import { loadDetailsPanel } from 'store/details-panel/details-panel-action';
16 import { setSelectedResourceUuid } from 'store/selected-resource/selected-resource-actions';
17 import { deselectAllOthers } from 'store/multiselect/multiselect-actions';
18 import { Resource } from 'models/resource';
19 import { ProjectResource } from 'models/project';
20
21 type CssRules = 'root' | 'cardHeaderContainer' | 'cardHeader' | 'userNameContainer' | 'accountStatusSection';
22
23 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
24     root: {
25         width: '100%',
26         marginBottom: '1rem',
27         flex: '0 0 auto',
28         padding: 0,
29         minHeight: '3rem',
30     },
31     userNameContainer: {
32         display: 'flex',
33         alignItems: 'center',
34         minHeight: '2.7rem',
35     },
36     cardHeaderContainer: {
37         width: '100%',
38         display: 'flex',
39         flexDirection: 'row',
40         alignItems: 'center',
41         justifyContent: 'space-between',
42     },
43     cardHeader: {
44         minWidth: '30rem',
45         padding: '0.2rem 0.4rem 0.2rem 1rem',
46     },
47     accountStatusSection: {
48         display: 'flex',
49         flexDirection: 'row',
50         alignItems: 'center',
51         paddingLeft: '1rem',
52     },
53 });
54
55 const mapStateToProps = ({ auth, selectedResourceUuid, resources, properties }: RootState) => {
56     const currentResource = getResource(properties.currentRouteUuid)(resources);
57     const frozenByUser = currentResource && getResource((currentResource as ProjectResource).frozenByUuid as string)(resources);
58     const frozenByFullName = frozenByUser && (frozenByUser as Resource & { fullName: string }).fullName;
59     const isSelected = selectedResourceUuid === properties.currentRouteUuid;
60
61     return {
62         isAdmin: auth.user?.isAdmin,
63         currentResource,
64         frozenByFullName,
65         isSelected,
66     };
67 };
68
69 const mapDispatchToProps = (dispatch: Dispatch) => ({
70     handleCardClick: (uuid: string) => {
71         dispatch<any>(loadDetailsPanel(uuid));
72         dispatch<any>(setSelectedResourceUuid(uuid));
73         dispatch<any>(deselectAllOthers(uuid));
74     },
75 });
76
77 type UserCardProps = WithStyles<CssRules> & {
78     currentResource: UserResource;
79     isAdmin: boolean;
80     isSelected: boolean;
81     handleCardClick: (resource: any) => void;
82 };
83
84 export const UserCard = connect(
85     mapStateToProps,
86     mapDispatchToProps
87 )(
88     withStyles(styles)((props: UserCardProps) => {
89         const { classes, currentResource, handleCardClick, isSelected } = props;
90         const { fullName, uuid } = currentResource as UserResource & { fullName: string };
91
92         return (
93             <Card
94                 className={classes.root}
95                 onClick={() => handleCardClick(uuid)}
96                 data-cy='user-details-card'
97             >
98                 <Grid
99                     container
100                     wrap='nowrap'
101                     className={classes.cardHeaderContainer}
102                 >
103                     <CardHeader
104                         className={classes.cardHeader}
105                         title={
106                             <section className={classes.userNameContainer}>
107                                 <Typography
108                                     noWrap
109                                     variant='h6'
110                                 >
111                                     {fullName}
112                                 </Typography>
113                                 <section className={classes.accountStatusSection}>
114                                     {!currentResource.isActive && (
115                                         <Typography>
116                                             <UserResourceAccountStatus uuid={uuid} />
117                                         </Typography>
118                                     )}
119                                 </section>
120                             </section>
121                         }
122                     />
123                     {isSelected && <MultiselectToolbar />}
124                 </Grid>
125             </Card>
126         );
127     })
128 );