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