16115: Updates the sharing dialog to support sharing URLs.
authorLucas Di Pentima <lucas.dipentima@curii.com>
Fri, 13 May 2022 13:44:30 +0000 (10:44 -0300)
committerLucas Di Pentima <lucas.dipentima@curii.com>
Fri, 13 May 2022 13:44:30 +0000 (10:44 -0300)
* When dealing with collections, adds a new tab for sharing URLs.
* Removes the "Advanced" mode and always show the permissions.
* Moves the "invitation form" to the dialog's action section so that it
  keeps being visible when lots of permissions are set.
* Allow closing the dialog by clicking away or using the Esc key when no
  pending changes need saving.

Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima@curii.com>

src/store/sharing-dialog/sharing-dialog-actions.ts
src/views-components/sharing-dialog/advanced-view-switch.tsx [deleted file]
src/views-components/sharing-dialog/sharing-dialog-component.tsx
src/views-components/sharing-dialog/sharing-dialog-content.tsx
src/views-components/sharing-dialog/sharing-dialog.tsx

index 53c751e17d0999e5521dd0732314abec3700fa2c..bb3b692f926261f18e4d1edd890b774f02dc80a0 100644 (file)
@@ -20,7 +20,6 @@ import { withProgress } from "store/progress-indicator/with-progress";
 import { progressIndicatorActions } from 'store/progress-indicator/progress-indicator-actions';
 import { snackbarActions, SnackbarKind } from "../snackbar/snackbar-actions";
 import { extractUuidKind, extractUuidObjectType, ResourceKind, ResourceObjectType } from "models/resource";
-import { ApiClientAuthorizationService } from "services/api-client-authorization-service/api-client-authorization-service";
 import { resourcesActions } from "store/resources/resources-actions";
 
 export const openSharingDialog = (resourceUuid: string, refresh?: () => void) =>
diff --git a/src/views-components/sharing-dialog/advanced-view-switch.tsx b/src/views-components/sharing-dialog/advanced-view-switch.tsx
deleted file mode 100644 (file)
index 969128b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import React from 'react';
-
-export interface AdvancedViewSwitchInjectedProps {
-    toggleAdvancedView: () => void;
-    advancedViewOpen: boolean;
-}
-
-export const connectAdvancedViewSwitch = (Component: React.ComponentType<AdvancedViewSwitchInjectedProps>) =>
-    class extends React.Component<{}, { advancedViewOpen: boolean }> {
-
-        state = { advancedViewOpen: false };
-
-        toggleAdvancedView = () => {
-            this.setState(({ advancedViewOpen }) => ({ advancedViewOpen: !advancedViewOpen }));
-        }
-
-        render() {
-            return <Component {...this.state} {...this} />;
-        }
-    };
-    
\ No newline at end of file
index be15cce63e082e1cf048bf374704a9b9f9d6b39f..eca6dc2c3c068ac0001acd33a4cf6338d3db8b0c 100644 (file)
@@ -3,56 +3,99 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import React from 'react';
-import { Dialog, DialogTitle, Button, Grid, DialogContent, CircularProgress, Paper } from '@material-ui/core';
+import {
+    Dialog,
+    DialogTitle,
+    Button,
+    Grid,
+    DialogContent,
+    CircularProgress,
+    Paper,
+    Tabs,
+    Tab,
+} from '@material-ui/core';
+import {
+    StyleRulesCallback,
+    WithStyles,
+    withStyles
+} from '@material-ui/core/styles';
 import { DialogActions } from 'components/dialog-actions/dialog-actions';
-import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
-
+import { SharingDialogContent } from './sharing-dialog-content';
+import { SharingURLsContent } from './sharing-urls';
+import {
+    extractUuidObjectType,
+    ResourceObjectType
+} from 'models/resource';
+import { SharingInvitationForm } from './sharing-invitation-form';
 
 export interface SharingDialogDataProps {
     open: boolean;
     loading: boolean;
     saveEnabled: boolean;
-    advancedEnabled: boolean;
-    children: React.ReactNode;
+    sharedResourceUuid: string;
 }
 export interface SharingDialogActionProps {
     onClose: () => void;
-    onExited: () => void;
     onSave: () => void;
-    onAdvanced: () => void;
+    onCreateSharingToken: () => void;
+}
+enum SharingDialogTab {
+    PERMISSIONS = 0,
+    URLS = 1,
 }
 export default (props: SharingDialogDataProps & SharingDialogActionProps) => {
-    const { children, open, loading, advancedEnabled, saveEnabled, onAdvanced, onClose, onExited, onSave } = props;
+    const { open, loading, saveEnabled, sharedResourceUuid,
+        onClose, onSave, onCreateSharingToken } = props;
+    const showTabs = extractUuidObjectType(sharedResourceUuid) === ResourceObjectType.COLLECTION;
+    const [tabNr, setTabNr] = React.useState<number>(SharingDialogTab.PERMISSIONS);
+
+    // Sets up the dialog depending on the resource type
+    if (!showTabs && tabNr !== SharingDialogTab.PERMISSIONS) {
+        setTabNr(SharingDialogTab.PERMISSIONS);
+    }
+
     return <Dialog
-        {...{ open, onClose, onExited }}
+        {...{ open, onClose }}
         className="sharing-dialog"
         fullWidth
         maxWidth='sm'
-        disableBackdropClick
-        disableEscapeKeyDown>
+        disableBackdropClick={saveEnabled}
+        disableEscapeKeyDown={saveEnabled}>
         <DialogTitle>
             Sharing settings
-            </DialogTitle>
+        </DialogTitle>
+        { showTabs &&
+        <Tabs value={tabNr} onChange={(_, tb) => setTabNr(tb)}>
+            <Tab label="With users/groups" />
+            <Tab label="Sharing URLs" disabled={saveEnabled} />
+        </Tabs>
+        }
         <DialogContent>
-            {children}
+            { tabNr === SharingDialogTab.PERMISSIONS &&
+            <SharingDialogContent />
+            }
+            { tabNr === SharingDialogTab.URLS &&
+            <SharingURLsContent uuid={sharedResourceUuid} />
+            }
         </DialogContent>
         <DialogActions>
             <Grid container spacing={8}>
-                {advancedEnabled &&
-                    <Grid item>
-                        <Button
-                            color='primary'
-                            onClick={onAdvanced}>
-                            Advanced
-                    </Button>
-                    </Grid>
-                }
-                <Grid item xs />
+                { tabNr === SharingDialogTab.PERMISSIONS &&
+                <Grid item md={12}>
+                    <SharingInvitationForm />
+                </Grid> }
+                { tabNr === SharingDialogTab.URLS &&
                 <Grid item>
-                    <Button onClick={onClose}>
-                        Close
+                    <Button
+                        variant="contained"
+                        color="primary"
+                        onClick={onCreateSharingToken}>
+                        Create sharing URL
                     </Button>
                 </Grid>
+                }
+                <Grid item xs />
+                { tabNr === SharingDialogTab.PERMISSIONS &&
                 <Grid item>
                     <Button
                         variant='contained'
@@ -62,6 +105,12 @@ export default (props: SharingDialogDataProps & SharingDialogActionProps) => {
                         Save
                     </Button>
                 </Grid>
+                }
+                <Grid item>
+                    <Button onClick={onClose}>
+                        Close
+                    </Button>
+                </Grid>
             </Grid>
         </DialogActions>
         {
index 15df22456e2a1ab74b3d1d0fb7a832e69bf6cd4f..ee1ccf87e7d9ab52d866b3310470e041ce6c1e26 100644 (file)
@@ -3,26 +3,13 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import React from 'react';
-import { Grid, Typography } from '@material-ui/core';
+import { Grid } from '@material-ui/core';
 
-import { SharingInvitationForm } from './sharing-invitation-form';
 import { SharingManagementForm } from './sharing-management-form';
-import { SharingPublicAccessForm } from './sharing-public-access-form';
 
-export const SharingDialogContent = (props: { advancedViewOpen: boolean }) =>
+export const SharingDialogContent = () =>
     <Grid container direction='column' spacing={24}>
-        {props.advancedViewOpen &&
-            <>
-                <Grid item>
-                    <Typography variant='subtitle1'>
-                        Who can access
-                    </Typography>
-                    <SharingPublicAccessForm />
-                    <SharingManagementForm />
-                </Grid>
-            </>
-        }
         <Grid item>
-            <SharingInvitationForm />
+            <SharingManagementForm />
         </Grid>
     </Grid>;
index fe3b8396aa52e306d38e2e74a8ab346458b14adc..a077f7ee4f00da87922885cf008a1482cc9470cb 100644 (file)
@@ -4,48 +4,50 @@
 
 import { compose, Dispatch } from 'redux';
 import { connect } from 'react-redux';
-
-import React from 'react';
-import { connectSharingDialog, saveSharingDialogChanges, connectSharingDialogProgress, sendSharingInvitations } from 'store/sharing-dialog/sharing-dialog-actions';
-import { WithDialogProps } from 'store/dialog/with-dialog';
 import { RootState } from 'store/store';
-
-import SharingDialogComponent, { SharingDialogDataProps, SharingDialogActionProps } from './sharing-dialog-component';
-import { SharingDialogContent } from './sharing-dialog-content';
-import { connectAdvancedViewSwitch, AdvancedViewSwitchInjectedProps } from './advanced-view-switch';
-import { hasChanges } from 'store/sharing-dialog/sharing-dialog-types';
+import {
+    connectSharingDialog,
+    saveSharingDialogChanges,
+    connectSharingDialogProgress,
+    SharingDialogData,
+    createSharingToken
+} from 'store/sharing-dialog/sharing-dialog-actions';
+import { WithDialogProps } from 'store/dialog/with-dialog';
+import SharingDialogComponent, {
+    SharingDialogDataProps,
+    SharingDialogActionProps
+} from './sharing-dialog-component';
+import {
+    hasChanges,
+    SHARING_DIALOG_NAME
+} from 'store/sharing-dialog/sharing-dialog-types';
 import { WithProgressStateProps } from 'store/progress-indicator/with-progress';
+import { getDialog } from 'store/dialog/dialog-reducer';
 
-type Props = WithDialogProps<string> & AdvancedViewSwitchInjectedProps & WithProgressStateProps;
+type Props = WithDialogProps<string> & WithProgressStateProps;
 
-const mapStateToProps = (state: RootState, { advancedViewOpen, working, ...props }: Props): SharingDialogDataProps => ({
+const mapStateToProps = (state: RootState, { working, ...props }: Props): SharingDialogDataProps => {
+    const dialog = getDialog<SharingDialogData>(state.dialog, SHARING_DIALOG_NAME);
+    return ({
     ...props,
     saveEnabled: hasChanges(state),
     loading: working,
-    advancedEnabled: !advancedViewOpen,
-    children: <SharingDialogContent {...{ advancedViewOpen }} />,
-});
+    sharedResourceUuid: dialog?.data.resourceUuid || '',
+    })
+};
 
-const mapDispatchToProps = (dispatch: Dispatch, { toggleAdvancedView, advancedViewOpen, ...props }: Props): SharingDialogActionProps => ({
+const mapDispatchToProps = (dispatch: Dispatch, { ...props }: Props): SharingDialogActionProps => ({
     ...props,
     onClose: props.closeDialog,
-    onExited: () => {
-        if (advancedViewOpen) {
-            toggleAdvancedView();
-        }
-    },
     onSave: () => {
-        if (advancedViewOpen) {
-            dispatch<any>(saveSharingDialogChanges);
-        } else {
-            dispatch<any>(sendSharingInvitations);
-        }
+        dispatch<any>(saveSharingDialogChanges);
     },
-    onAdvanced: toggleAdvancedView,
+    onCreateSharingToken: () => {
+        dispatch<any>(createSharingToken);
+    }
 });
 
 export const SharingDialog = compose(
-    connectAdvancedViewSwitch,
     connectSharingDialog,
     connectSharingDialogProgress,
     connect(mapStateToProps, mapDispatchToProps)