15530: Config takes precedence over local storage sessions
[arvados-workbench2.git] / src / views / link-account-panel / link-account-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     StyleRulesCallback,
8     WithStyles,
9     withStyles,
10     Card,
11     CardContent,
12     Button,
13     Grid,
14     Select,
15     CircularProgress
16 } from '@material-ui/core';
17 import { ArvadosTheme } from '~/common/custom-theme';
18 import { UserResource } from "~/models/user";
19 import { LinkAccountType } from "~/models/link-account";
20 import { formatDate } from "~/common/formatters";
21 import { LinkAccountPanelStatus, LinkAccountPanelError } from "~/store/link-account-panel/link-account-panel-reducer";
22
23 type CssRules = 'root';
24
25 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
26     root: {
27         width: '100%',
28         overflow: 'auto'
29     }
30 });
31
32 export interface LinkAccountPanelRootDataProps {
33     targetUser?: UserResource;
34     userToLink?: UserResource;
35     remoteHosts: { [key: string]: string };
36     hasRemoteHosts: boolean;
37     localCluster: string;
38     loginCluster: string;
39     status: LinkAccountPanelStatus;
40     error: LinkAccountPanelError;
41     selectedCluster?: string;
42     isProcessing: boolean;
43 }
44
45 export interface LinkAccountPanelRootActionProps {
46     startLinking: (type: LinkAccountType) => void;
47     cancelLinking: () => void;
48     linkAccount: () => void;
49     setSelectedCluster: (cluster: string) => void;
50 }
51
52 function displayUser(user: UserResource, showCreatedAt: boolean = false, showCluster: boolean = false) {
53     const disp = [];
54     disp.push(<span><b>{user.email}</b> ({user.username}, {user.uuid})</span>);
55     if (showCluster) {
56         const homeCluster = user.uuid.substr(0, 5);
57         disp.push(<span> hosted on cluster <b>{homeCluster}</b> and </span>);
58     }
59     if (showCreatedAt) {
60         disp.push(<span> created on <b>{formatDate(user.createdAt)}</b></span>);
61     }
62     return disp;
63 }
64
65 function isLocalUser(uuid: string, localCluster: string) {
66     return uuid.substring(0, 5) === localCluster;
67 }
68
69 type LinkAccountPanelRootProps = LinkAccountPanelRootDataProps & LinkAccountPanelRootActionProps & WithStyles<CssRules>;
70
71 export const LinkAccountPanelRoot = withStyles(styles)(
72     ({ classes, targetUser, userToLink, status, isProcessing, error, startLinking, cancelLinking, linkAccount,
73         remoteHosts, hasRemoteHosts, selectedCluster, setSelectedCluster, localCluster, loginCluster }: LinkAccountPanelRootProps) => {
74         return <Card className={classes.root}>
75             <CardContent>
76                 {isProcessing && <Grid container item direction="column" alignContent="center" spacing={24}>
77                     <Grid item>
78                         Loading user info. Please wait.
79                        </Grid>
80                     <Grid item style={{ alignSelf: 'center' }}>
81                         <CircularProgress />
82                     </Grid>
83                 </Grid>}
84                 {!isProcessing && status === LinkAccountPanelStatus.INITIAL && targetUser && <div>
85                     {isLocalUser(targetUser.uuid, localCluster) ? <Grid container spacing={24}>
86                         <Grid container item direction="column" spacing={24}>
87                             <Grid item>
88                                 You are currently logged in as {displayUser(targetUser, true)}
89                             </Grid>
90                             <Grid item>
91                                 You can link Arvados accounts. After linking, either login will take you to the same account.
92                                </Grid >
93                         </Grid>
94                         <Grid container item direction="row" spacing={24}>
95                             <Grid item>
96                                 <Button disabled={!targetUser.isActive} color="primary" variant="contained" onClick={() => startLinking(LinkAccountType.ADD_OTHER_LOGIN)}>
97                                     Add another login to this account
98                                    </Button>
99                             </Grid>
100                             <Grid item>
101                                 <Button color="primary" variant="contained" onClick={() => startLinking(LinkAccountType.ACCESS_OTHER_ACCOUNT)}>
102                                     Use this login to access another account
103                                    </Button>
104                             </Grid>
105                         </Grid>
106                         {hasRemoteHosts && selectedCluster && <Grid container item direction="column" spacing={24}>
107                             <Grid item>
108                                 You can also link {displayUser(targetUser, false)} with an account from a remote cluster.
109                                </Grid>
110                             <Grid item>
111                                 Please select the cluster that hosts the account you want to link with:
112                                    <Select id="remoteHostsDropdown" native defaultValue={selectedCluster} style={{ marginLeft: "1em" }}
113                                     onChange={(event) => setSelectedCluster(event.target.value)}>
114                                     {Object.keys(remoteHosts).map((k) => k !== localCluster ? <option key={k} value={k}>{k}</option> : null)}
115                                 </Select>
116                             </Grid>
117                             <Grid item>
118                                 <Button color="primary" variant="contained" onClick={() => startLinking(LinkAccountType.ACCESS_OTHER_REMOTE_ACCOUNT)}>
119                                     Link with an account on&nbsp;{hasRemoteHosts ? <label>{selectedCluster} </label> : null}
120                                 </Button>
121                             </Grid>
122                         </Grid>}
123                     </Grid> :
124                         <Grid container spacing={24}>
125                             <Grid container item direction="column" spacing={24}>
126                                 <Grid item>
127                                     You are currently logged in as {displayUser(targetUser, true, true)}
128                                 </Grid>
129                                 {targetUser.isActive ? (loginCluster === "" ?
130                                     <> <Grid item>
131                                         This a remote account. You can link a local Arvados account to this one. After linking, you can access the local account's data by logging into the <b>{localCluster}</b> cluster as user <b>{targetUser.email}</b> from <b>{targetUser.uuid.substr(0, 5)}</b>.
132                                      </Grid >
133                                         <Grid item>
134                                             <Button color="primary" variant="contained" onClick={() => startLinking(LinkAccountType.ADD_LOCAL_TO_REMOTE)}>
135                                                 Link an account from {localCluster} to this account
136                                          </Button>
137                                         </Grid> </>
138                                     : <Grid item>Must perform account linking on login cluster <b>{loginCluster}</b></Grid>
139                                 )
140                                     : <Grid item>
141                                         This an inactive remote account. An administrator must activate your account before you can proceed. After your accounts is activated, you can link a local Arvados account hosted by the <b>{localCluster}</b> cluster to this one.
142                                  </Grid >}
143                             </Grid>
144                         </Grid>}
145                 </div>}
146                 {!isProcessing && (status === LinkAccountPanelStatus.LINKING || status === LinkAccountPanelStatus.ERROR) && userToLink && targetUser &&
147                     <Grid container spacing={24}>
148                         {status === LinkAccountPanelStatus.LINKING && <Grid container item direction="column" spacing={24}>
149                             <Grid item>
150                                 Clicking 'Link accounts' will link {displayUser(userToLink, true, !isLocalUser(targetUser.uuid, localCluster))} to {displayUser(targetUser, true, !isLocalUser(targetUser.uuid, localCluster))}.
151                             </Grid>
152                             {(isLocalUser(targetUser.uuid, localCluster)) && <Grid item>
153                                 After linking, logging in as {displayUser(userToLink)} will log you into the same account as {displayUser(targetUser)}.
154                             </Grid>}
155                             <Grid item>
156                                 Any object owned by {displayUser(userToLink)} will be transfered to {displayUser(targetUser)}.
157                             </Grid>
158                             {!isLocalUser(targetUser.uuid, localCluster) && <Grid item>
159                                 You can access <b>{userToLink.email}</b> data by logging into <b>{localCluster}</b> with the <b>{targetUser.email}</b> account.
160                             </Grid>}
161                         </Grid>}
162                         {error === LinkAccountPanelError.NON_ADMIN && <Grid item>
163                             Cannot link admin account {displayUser(userToLink)} to non-admin account {displayUser(targetUser)}.
164                         </Grid>}
165                         {error === LinkAccountPanelError.SAME_USER && <Grid item>
166                             Cannot link {displayUser(targetUser)} to the same account.
167                         </Grid>}
168                         {error === LinkAccountPanelError.INACTIVE && <Grid item>
169                             Cannot link account {displayUser(userToLink)} to inactive account {displayUser(targetUser)}.
170                         </Grid>}
171                         <Grid container item direction="row" spacing={24}>
172                             <Grid item>
173                                 <Button variant="contained" onClick={() => cancelLinking()}>
174                                     Cancel
175                                 </Button>
176                             </Grid>
177                             <Grid item>
178                                 <Button disabled={status === LinkAccountPanelStatus.ERROR} color="primary" variant="contained" onClick={() => linkAccount()}>
179                                     Link accounts
180                                 </Button>
181                             </Grid>
182                         </Grid>
183                     </Grid>}
184             </CardContent>
185         </Card>;
186     });