Merge branch 'origin/master' into 14478-log-in-into-clusters
[arvados-workbench2.git] / src / views / site-manager-panel / site-manager-panel-root.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from 'react';
6 import {
7     Card,
8     CardContent,
9     CircularProgress,
10     Grid,
11     StyleRulesCallback,
12     Table,
13     TableBody,
14     TableCell,
15     TableHead,
16     TableRow,
17     Typography,
18     WithStyles,
19     withStyles
20 } from '@material-ui/core';
21 import { ArvadosTheme } from '~/common/custom-theme';
22 import { Session, SessionStatus } from "~/models/session";
23 import Button from "@material-ui/core/Button";
24 import { User } from "~/models/user";
25 import { compose } from "redux";
26 import { Field, FormErrors, InjectedFormProps, reduxForm, reset, stopSubmit } from "redux-form";
27 import { TextField } from "~/components/text-field/text-field";
28 import { addSession } from "~/store/auth/auth-action-session";
29 import { SITE_MANAGER_REMOTE_HOST_VALIDATION } from "~/validators/validators";
30
31 type CssRules = 'root' | 'link' | 'buttonContainer' | 'table' | 'tableRow' |
32     'remoteSiteInfo' | 'buttonAdd' | 'buttonLoggedIn' | 'buttonLoggedOut' |
33     'statusCell';
34
35 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
36     root: {
37        width: '100%',
38        overflow: 'auto'
39     },
40     link: {
41         color: theme.palette.primary.main,
42         textDecoration: 'none',
43         margin: '0px 4px'
44     },
45     buttonContainer: {
46         textAlign: 'right'
47     },
48     table: {
49         marginTop: theme.spacing.unit
50     },
51     tableRow: {
52         '& td, th': {
53             whiteSpace: 'nowrap'
54         }
55     },
56     statusCell: {
57         minWidth: 160
58     },
59     remoteSiteInfo: {
60         marginTop: 20
61     },
62     buttonAdd: {
63         marginLeft: 10,
64         marginTop: theme.spacing.unit * 3
65     },
66     buttonLoggedIn: {
67         minHeight: theme.spacing.unit,
68         padding: 5,
69         color: '#fff',
70         backgroundColor: '#009966',
71         '&:hover': {
72             backgroundColor: '#008450',
73         }
74     },
75     buttonLoggedOut: {
76         minHeight: theme.spacing.unit,
77         padding: 5,
78         color: '#000',
79         backgroundColor: '#FFC414',
80         '&:hover': {
81             backgroundColor: '#eaaf14',
82         }
83     }
84 });
85
86 export interface SiteManagerPanelRootActionProps {
87     toggleSession: (session: Session) => void;
88 }
89
90 export interface SiteManagerPanelRootDataProps {
91     sessions: Session[];
92     user: User;
93 }
94
95 type SiteManagerPanelRootProps = SiteManagerPanelRootDataProps & SiteManagerPanelRootActionProps & WithStyles<CssRules> & InjectedFormProps;
96 const SITE_MANAGER_FORM_NAME = 'siteManagerForm';
97
98 export const SiteManagerPanelRoot = compose(
99     reduxForm<{remoteHost: string}>({
100         form: SITE_MANAGER_FORM_NAME,
101         touchOnBlur: false,
102         onSubmit: (data, dispatch) => {
103             dispatch<any>(addSession(data.remoteHost)).then(() => {
104                 dispatch(reset(SITE_MANAGER_FORM_NAME));
105             }).catch((e: any) => {
106                 const errors = {
107                     remoteHost: e
108                 } as FormErrors;
109                 dispatch(stopSubmit(SITE_MANAGER_FORM_NAME, errors));
110             });
111         }
112     }),
113     withStyles(styles))
114     (({ classes, sessions, handleSubmit, toggleSession }: SiteManagerPanelRootProps) =>
115         <Card className={classes.root}>
116             <CardContent>
117                 <Grid container direction="row">
118                     <Grid item xs={12}>
119                         <Typography variant='body1' paragraph={true} >
120                             You can log in to multiple Arvados sites here, then use the multi-site search page to search collections and projects on all sites at once.
121                         </Typography>
122                     </Grid>
123                 </Grid>
124                 <Grid item xs={12}>
125                     {sessions.length > 0 && <Table className={classes.table}>
126                         <TableHead>
127                             <TableRow className={classes.tableRow}>
128                                 <TableCell>Cluster ID</TableCell>
129                                 <TableCell>Username</TableCell>
130                                 <TableCell>Email</TableCell>
131                                 <TableCell>Status</TableCell>
132                             </TableRow>
133                         </TableHead>
134                         <TableBody>
135                             {sessions.map((session, index) => {
136                                 const validating = session.status === SessionStatus.BEING_VALIDATED;
137                                 return <TableRow key={index} className={classes.tableRow}>
138                                     <TableCell>{session.clusterId}</TableCell>
139                                     <TableCell>{validating ? <CircularProgress size={20}/> : session.username}</TableCell>
140                                     <TableCell>{validating ? <CircularProgress size={20}/> : session.email}</TableCell>
141                                     <TableCell className={classes.statusCell}>
142                                         <Button fullWidth
143                                             disabled={validating || session.status === SessionStatus.INVALIDATED || session.active}
144                                             className={session.loggedIn ? classes.buttonLoggedIn : classes.buttonLoggedOut}
145                                             onClick={() => toggleSession(session)}>
146                                             {validating ? "Validating" : (session.loggedIn ? "Logged in" : "Logged out")}
147                                         </Button>
148                                     </TableCell>
149                                 </TableRow>;
150                             })}
151                         </TableBody>
152                     </Table>}
153                 </Grid>
154                 <form onSubmit={handleSubmit}>
155                     <Grid container direction="row">
156                         <Grid item xs={12}>
157                             <Typography variant='body1' paragraph={true} className={classes.remoteSiteInfo}>
158                                 To add a remote Arvados site, paste the remote site's host here (see "ARVADOS_API_HOST" on the "current token" page).
159                             </Typography>
160                         </Grid>
161                         <Grid item xs={8}>
162                             <Field
163                                 name='remoteHost'
164                                 validate={SITE_MANAGER_REMOTE_HOST_VALIDATION}
165                                 component={TextField}
166                                 placeholder="zzzz.arvadosapi.com"
167                                 margin="normal"
168                                 label="New cluster"
169                                 autoFocus/>
170                         </Grid>
171                         <Grid item xs={3}>
172                             <Button type="submit" variant="contained" color="primary"
173                                 className={classes.buttonAdd}>
174                                 {"ADD"}</Button>
175                         </Grid>
176                     </Grid>
177                 </form>
178             </CardContent>
179         </Card>
180     );