// Copyright (C) The Arvados Authors. All rights reserved. // // SPDX-License-Identifier: AGPL-3.0 import React from 'react'; import { Dialog, DialogTitle, Button, Grid, DialogContent, CircularProgress, Paper, Tabs, Tab, Checkbox, FormControlLabel, Typography, Tooltip, } from '@material-ui/core'; import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles'; import { DialogActions } from 'components/dialog-actions/dialog-actions'; import { SharingURLsContent } from './sharing-urls'; import { extractUuidObjectType, ResourceObjectType } from 'models/resource'; import { SharingInvitationForm } from './sharing-invitation-form'; import { SharingManagementForm } from './sharing-management-form'; import { BasePicker, Calendar, MuiPickersUtilsProvider, TimePickerView } from 'material-ui-pickers'; import DateFnsUtils from "@date-io/date-fns"; import moment from 'moment'; import { SharingPublicAccessForm } from './sharing-public-access-form'; import { AddIcon } from 'components/icon/icon'; export interface SharingDialogDataProps { open: boolean; loading: boolean; saveEnabled: boolean; sharedResourceUuid: string; sharingURLsNr: number; privateAccess: boolean; sharingURLsDisabled: boolean; permissions: any[]; } export interface SharingDialogActionProps { onClose: () => void; onSave: () => void; onCreateSharingToken: (d: Date | undefined) => () => void; refreshPermissions: () => void; } enum SharingDialogTab { PERMISSIONS = 0, URLS = 1, } export type SharingDialogComponentProps = SharingDialogDataProps & SharingDialogActionProps; export default (props: SharingDialogComponentProps) => { const { open, loading, saveEnabled, sharedResourceUuid, sharingURLsNr, privateAccess, sharingURLsDisabled, permissions, onClose, onSave, onCreateSharingToken, refreshPermissions } = props; const showTabs = !sharingURLsDisabled && extractUuidObjectType(sharedResourceUuid) === ResourceObjectType.COLLECTION; const [tabNr, setTabNr] = React.useState<number>(SharingDialogTab.PERMISSIONS); const [expDate, setExpDate] = React.useState<Date>(); const [withExpiration, setWithExpiration] = React.useState<boolean>(false); // Sets up the dialog depending on the resource type if (!showTabs && tabNr !== SharingDialogTab.PERMISSIONS) { setTabNr(SharingDialogTab.PERMISSIONS); } React.useEffect(() => { if (!withExpiration) { setExpDate(undefined); } else { setExpDate(moment().add(2, 'hour').minutes(0).seconds(0).toDate()); } }, [withExpiration]); return <Dialog {...{ open, onClose }} className="sharing-dialog" fullWidth maxWidth='sm' disableBackdropClick={saveEnabled} disableEscapeKeyDown={saveEnabled}> <DialogTitle> Sharing settings </DialogTitle> {showTabs && <Tabs value={tabNr} onChange={(_, tb) => { if (tb === SharingDialogTab.PERMISSIONS) { refreshPermissions(); } setTabNr(tb) } }> <Tab label="With users/groups" /> <Tab label={`Sharing URLs ${sharingURLsNr > 0 ? '(' + sharingURLsNr + ')' : ''}`} disabled={saveEnabled} /> </Tabs> } <DialogContent> {tabNr === SharingDialogTab.PERMISSIONS && <Grid container direction='column' spacing={24}> <Grid item> <SharingInvitationForm onSave={onSave} saveEnabled={saveEnabled} /> </Grid> <Grid item> <SharingManagementForm onSave={onSave} /> </Grid> <Grid item> <SharingPublicAccessForm onSave={onSave} /> </Grid> </Grid> } {tabNr === SharingDialogTab.URLS && <SharingURLsContent uuid={sharedResourceUuid} /> } </DialogContent> <DialogActions> <Grid container spacing={8}> {tabNr === SharingDialogTab.URLS && withExpiration && <> <Grid item container direction='row' md={12}> <MuiPickersUtilsProvider utils={DateFnsUtils}> <BasePicker autoOk value={expDate} onChange={setExpDate}> {({ date, handleChange }) => (<> <Grid item md={6}> <Calendar date={date} minDate={new Date()} maxDate={undefined} onChange={handleChange} /> </Grid> <Grid item md={6}> <TimePickerView type="hours" date={date} ampm={false} onMinutesChange={() => { }} onSecondsChange={() => { }} onHourChange={handleChange} /> </Grid> </>)} </BasePicker> </MuiPickersUtilsProvider> </Grid> <Grid item md={12}> <Typography variant='caption' align='center'> Maximum expiration date may be limited by the cluster configuration. </Typography> </Grid> </> } {tabNr === SharingDialogTab.PERMISSIONS && !sharingURLsDisabled && privateAccess && sharingURLsNr > 0 && <Grid item md={12}> <Typography variant='caption' align='center' color='error'> Although there aren't specific permissions set, this is publicly accessible via Sharing URL(s). </Typography> </Grid> } <Grid item xs /> {tabNr === SharingDialogTab.URLS && <> <Grid item><FormControlLabel control={<Checkbox color="primary" checked={withExpiration} onChange={(e) => setWithExpiration(e.target.checked)} />} label="With expiration" /> </Grid> <Grid item> <Button variant="contained" color="primary" disabled={expDate !== undefined && expDate <= new Date()} onClick={onCreateSharingToken(expDate)}> Create sharing URL </Button> </Grid> </> } <Grid item> <Button onClick={() => { onClose(); setWithExpiration(false); }}> Close </Button> </Grid> </Grid> </DialogActions> { loading && <LoadingIndicator /> } </Dialog>; }; const loadingIndicatorStyles: StyleRulesCallback<'root'> = theme => ({ root: { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgba(255, 255, 255, 0.8)', }, }); const LoadingIndicator = withStyles(loadingIndicatorStyles)( (props: WithStyles<'root'>) => <Paper classes={props.classes}> <CircularProgress /> </Paper> );