b54b3455399477224ee8f867ecd6bffbadf7a936
[arvados-workbench2.git] / src / views-components / sharing-dialog / sharing-dialog-component.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 {
7     Dialog,
8     DialogTitle,
9     Button,
10     Grid,
11     DialogContent,
12     CircularProgress,
13     Paper,
14     Tabs,
15     Tab,
16     Checkbox,
17     FormControlLabel,
18     Typography,
19 } from '@material-ui/core';
20 import {
21     StyleRulesCallback,
22     WithStyles,
23     withStyles
24 } from '@material-ui/core/styles';
25 import { DialogActions } from 'components/dialog-actions/dialog-actions';
26 import { SharingURLsContent } from './sharing-urls';
27 import {
28     extractUuidObjectType,
29     ResourceObjectType
30 } from 'models/resource';
31 import { SharingInvitationForm } from './sharing-invitation-form';
32 import { SharingManagementForm } from './sharing-management-form';
33 import {
34     BasePicker,
35     Calendar,
36     MuiPickersUtilsProvider,
37     TimePickerView
38 } from 'material-ui-pickers';
39 import DateFnsUtils from "@date-io/date-fns";
40 import moment from 'moment';
41 import { SharingPublicAccessForm } from './sharing-public-access-form';
42
43 export interface SharingDialogDataProps {
44     open: boolean;
45     loading: boolean;
46     saveEnabled: boolean;
47     sharedResourceUuid: string;
48 }
49 export interface SharingDialogActionProps {
50     onClose: () => void;
51     onSave: () => void;
52     onCreateSharingToken: (d: Date | undefined) => () => void;
53     refreshPermissions: () => void;
54 }
55 enum SharingDialogTab {
56     PERMISSIONS = 0,
57     URLS = 1,
58 }
59 export default (props: SharingDialogDataProps & SharingDialogActionProps) => {
60     const { open, loading, saveEnabled, sharedResourceUuid,
61         onClose, onSave, onCreateSharingToken, refreshPermissions } = props;
62     const showTabs = extractUuidObjectType(sharedResourceUuid) === ResourceObjectType.COLLECTION;
63     const [tabNr, setTabNr] = React.useState<number>(SharingDialogTab.PERMISSIONS);
64     const [expDate, setExpDate] = React.useState<Date>();
65     const [withExpiration, setWithExpiration] = React.useState<boolean>(false);
66
67     // Sets up the dialog depending on the resource type
68     if (!showTabs && tabNr !== SharingDialogTab.PERMISSIONS) {
69         setTabNr(SharingDialogTab.PERMISSIONS);
70     }
71
72     React.useEffect(() => {
73         if (!withExpiration) {
74             setExpDate(undefined);
75         } else {
76             setExpDate(moment().add(2, 'hour').minutes(0).seconds(0).toDate());
77         }
78     }, [withExpiration]);
79
80     return <Dialog
81         {...{ open, onClose }}
82         className="sharing-dialog"
83         fullWidth
84         maxWidth='sm'
85         disableBackdropClick={saveEnabled}
86         disableEscapeKeyDown={saveEnabled}>
87         <DialogTitle>
88             Sharing settings
89         </DialogTitle>
90         { showTabs &&
91         <Tabs value={tabNr}
92             onChange={(_, tb) => {
93                 if (tb === SharingDialogTab.PERMISSIONS) {
94                     refreshPermissions();
95                 }
96                 setTabNr(tb)}
97             }>
98             <Tab label="With users/groups" />
99             <Tab label="Sharing URLs" disabled={saveEnabled} />
100         </Tabs>
101         }
102         <DialogContent>
103             { tabNr === SharingDialogTab.PERMISSIONS &&
104             <Grid container direction='column' spacing={24}>
105                 <Grid item>
106                     <SharingPublicAccessForm />
107                 </Grid>
108                 <Grid item>
109                     <SharingManagementForm />
110                 </Grid>
111             </Grid>
112             }
113             { tabNr === SharingDialogTab.URLS &&
114             <SharingURLsContent uuid={sharedResourceUuid} />
115             }
116         </DialogContent>
117         <DialogActions>
118             <Grid container spacing={8}>
119                 { tabNr === SharingDialogTab.PERMISSIONS &&
120                 <Grid item md={12}>
121                     <SharingInvitationForm />
122                 </Grid> }
123                 { tabNr === SharingDialogTab.URLS && withExpiration && <>
124                 <Grid item container direction='row' md={12}>
125                     <MuiPickersUtilsProvider utils={DateFnsUtils}>
126                         <BasePicker autoOk value={expDate} onChange={setExpDate}>
127                         {({ date, handleChange }) => (<>
128                             <Grid item md={6}>
129                                 <Calendar date={date} minDate={new Date()} maxDate={undefined}
130                                     onChange={handleChange} />
131                             </Grid>
132                             <Grid item md={6}>
133                                 <TimePickerView type="hours" date={date} ampm={false}
134                                     onMinutesChange={() => {}}
135                                     onSecondsChange={() => {}}
136                                     onHourChange={handleChange}
137                                 />
138                             </Grid>
139                         </>)}
140                         </BasePicker>
141                     </MuiPickersUtilsProvider>
142                 </Grid>
143                 <Grid item md={12}>
144                     <Typography variant='caption' align='center'>
145                         Maximum expiration date may be limited by the cluster configuration.
146                     </Typography>
147                 </Grid>
148                 </> }
149                 <Grid item xs />
150                 { tabNr === SharingDialogTab.URLS && <>
151                 <Grid item><FormControlLabel
152                     control={<Checkbox color="primary" checked={withExpiration}
153                         onChange={(e) => setWithExpiration(e.target.checked)} />}
154                     label="With expiration" />
155                 </Grid>
156                 <Grid item>
157                     <Button variant="contained" color="primary"
158                         disabled={expDate !== undefined && expDate <= new Date()}
159                         onClick={onCreateSharingToken(expDate)}>
160                         Create sharing URL
161                     </Button>
162                 </Grid>
163                 </>}
164                 { tabNr === SharingDialogTab.PERMISSIONS &&
165                 <Grid item>
166                     <Button onClick={onSave} variant="contained" color="primary"
167                         disabled={!saveEnabled}>
168                         Save changes
169                     </Button>
170                 </Grid>
171                 }
172                 <Grid item>
173                     <Button onClick={() => {
174                         onClose();
175                         setWithExpiration(false);
176                     }}>
177                         Close
178                     </Button>
179                 </Grid>
180             </Grid>
181         </DialogActions>
182         {
183             loading && <LoadingIndicator />
184         }
185     </Dialog>;
186 };
187
188 const loadingIndicatorStyles: StyleRulesCallback<'root'> = theme => ({
189     root: {
190         position: 'absolute',
191         top: 0,
192         right: 0,
193         bottom: 0,
194         left: 0,
195         display: 'flex',
196         alignItems: 'center',
197         justifyContent: 'center',
198         backgroundColor: 'rgba(255, 255, 255, 0.8)',
199     },
200 });
201
202 const LoadingIndicator = withStyles(loadingIndicatorStyles)(
203     (props: WithStyles<'root'>) =>
204         <Paper classes={props.classes}>
205             <CircularProgress />
206         </Paper>
207 );