Merge branch '19007-file-browser-action-button'. Closes #19007
authorLucas Di Pentima <lucas.dipentima@curii.com>
Thu, 16 Jun 2022 17:26:53 +0000 (14:26 -0300)
committerLucas Di Pentima <lucas.dipentima@curii.com>
Thu, 16 Jun 2022 17:26:53 +0000 (14:26 -0300)
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima@curii.com>

src/common/config.ts
src/store/sharing-dialog/sharing-dialog-actions.ts
src/views-components/sharing-dialog/sharing-dialog-component.test.tsx [new file with mode: 0644]
src/views-components/sharing-dialog/sharing-dialog-component.tsx
src/views-components/sharing-dialog/sharing-dialog.tsx

index 2518c95eda2e799a9156388f8f4d6f46a628203b..2954d70493b31676663cd00586583f4966f06d0a 100644 (file)
@@ -50,6 +50,7 @@ export interface ClusterConfigJSON {
         }
     };
     Workbench: {
+        DisableSharingURLsUI: boolean;
         ArvadosDocsite: string;
         FileViewersConfigURL: string;
         WelcomePageHTML: string;
@@ -233,6 +234,7 @@ export const mockClusterConfigJSON = (config: Partial<ClusterConfigJSON>): Clust
         WebShell: { ExternalURL: "" },
     },
     Workbench: {
+        DisableSharingURLsUI: false,
         ArvadosDocsite: "",
         FileViewersConfigURL: "",
         WelcomePageHTML: "",
index 367eea814281824f8eb161d8afede65639ffc223..cdc6c0c7267d4bab58434999b260d8905de7bc82 100644 (file)
@@ -118,13 +118,14 @@ export const deleteSharingToken = (uuid: string) => async (dispatch: Dispatch, g
 const loadSharingDialog = async (dispatch: Dispatch, getState: () => RootState, { apiClientAuthorizationService }: ServiceRepository) => {
 
     const dialog = getDialog<SharingDialogData>(getState().dialog, SHARING_DIALOG_NAME);
+    const sharingURLsDisabled = getState().auth.config.clusterConfig.Workbench.DisableSharingURLsUI;
     if (dialog) {
         dispatch(progressIndicatorActions.START_WORKING(SHARING_DIALOG_NAME));
         try {
             const resourceUuid = dialog.data.resourceUuid;
             await dispatch<any>(initializeManagementForm);
             // For collections, we need to load the public sharing tokens
-            if (extractUuidObjectType(resourceUuid) === ResourceObjectType.COLLECTION) {
+            if (!sharingURLsDisabled && extractUuidObjectType(resourceUuid) === ResourceObjectType.COLLECTION) {
                 const sharingTokens = await apiClientAuthorizationService.listCollectionSharingTokens(resourceUuid);
                 dispatch(resourcesActions.SET_RESOURCES([...sharingTokens.items]));
             }
diff --git a/src/views-components/sharing-dialog/sharing-dialog-component.test.tsx b/src/views-components/sharing-dialog/sharing-dialog-component.test.tsx
new file mode 100644 (file)
index 0000000..36447a8
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React from 'react';
+import { mount, configure } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { Provider } from 'react-redux';
+import { combineReducers, createStore } from 'redux';
+
+import SharingDialogComponent, {
+    SharingDialogComponentProps,
+} from './sharing-dialog-component';
+import {
+    extractUuidObjectType,
+    ResourceObjectType
+} from 'models/resource';
+
+configure({ adapter: new Adapter() });
+
+describe("<SharingDialogComponent />", () => {
+    let props: SharingDialogComponentProps;
+    let store;
+
+    beforeEach(() => {
+        const initialAuthState = {
+            config: {
+                keepWebServiceUrl: 'http://example.com/',
+                keepWebInlineServiceUrl: 'http://*.collections.example.com/',
+            }
+        }
+        store = createStore(combineReducers({
+            auth: (state: any = initialAuthState, action: any) => state,
+        }));
+
+        props = {
+            open: true,
+            loading: false,
+            saveEnabled: false,
+            sharedResourceUuid: 'zzzzz-4zz18-zzzzzzzzzzzzzzz',
+            privateAccess: true,
+            sharingURLsNr: 2,
+            sharingURLsDisabled: false,
+            onClose: jest.fn(),
+            onSave: jest.fn(),
+            onCreateSharingToken: jest.fn(),
+            refreshPermissions: jest.fn(),
+        };
+    });
+
+    it("show sharing urls tab on collections when not disabled", () => {
+        expect(props.sharingURLsDisabled).toBe(false);
+        expect(props.sharingURLsNr).toBe(2);
+        expect(extractUuidObjectType(props.sharedResourceUuid) === ResourceObjectType.COLLECTION).toBe(true);
+        let wrapper = mount(<Provider store={store}><SharingDialogComponent {...props} /></Provider>);
+        expect(wrapper.html()).toContain('Sharing URLs (2)');
+
+        // disable Sharing URLs UI
+        props.sharingURLsDisabled = true;
+        wrapper = mount(<Provider store={store}><SharingDialogComponent {...props} /></Provider>);
+        expect(wrapper.html()).not.toContain('Sharing URLs');
+    });
+
+    it("does not show sharing urls on non-collection resources", () => {
+        props.sharedResourceUuid = 'zzzzz-j7d0g-0123456789abcde';
+        expect(extractUuidObjectType(props.sharedResourceUuid) === ResourceObjectType.COLLECTION).toBe(false);
+        expect(props.sharingURLsDisabled).toBe(false);
+        let wrapper = mount(<Provider store={store}><SharingDialogComponent {...props} /></Provider>);
+        expect(wrapper.html()).not.toContain('Sharing URLs');
+    });
+});
\ No newline at end of file
index 15d7f660e0638caffaf631f180b70dd9680fd017..b2f313973ea7ef7abb71e0d422877aced717ce47 100644 (file)
@@ -47,6 +47,7 @@ export interface SharingDialogDataProps {
     sharedResourceUuid: string;
     sharingURLsNr: number;
     privateAccess: boolean;
+    sharingURLsDisabled: boolean;
 }
 export interface SharingDialogActionProps {
     onClose: () => void;
@@ -58,11 +59,13 @@ enum SharingDialogTab {
     PERMISSIONS = 0,
     URLS = 1,
 }
-export default (props: SharingDialogDataProps & SharingDialogActionProps) => {
+export type SharingDialogComponentProps = SharingDialogDataProps & SharingDialogActionProps;
+
+export default (props: SharingDialogComponentProps) => {
     const { open, loading, saveEnabled, sharedResourceUuid,
-        sharingURLsNr, privateAccess,
+        sharingURLsNr, privateAccess, sharingURLsDisabled,
         onClose, onSave, onCreateSharingToken, refreshPermissions } = props;
-    const showTabs = extractUuidObjectType(sharedResourceUuid) === ResourceObjectType.COLLECTION;
+    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);
@@ -151,7 +154,8 @@ export default (props: SharingDialogDataProps & SharingDialogActionProps) => {
                 </Grid>
                 </>
                 }
-                { tabNr === SharingDialogTab.PERMISSIONS && privateAccess && sharingURLsNr > 0 &&
+                { 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).
index 6b488e44d482f9108b9c68b107eb697808550693..01cd390b07f7a2263400954fbba3b9c41f17cb5d 100644 (file)
@@ -35,18 +35,21 @@ type Props = WithDialogProps<string> & WithProgressStateProps;
 const mapStateToProps = (state: RootState, { working, ...props }: Props): SharingDialogDataProps => {
     const dialog = getDialog<SharingDialogData>(state.dialog, SHARING_DIALOG_NAME);
     const sharedResourceUuid = dialog?.data.resourceUuid || '';
+    const sharingURLsDisabled = state.auth.config.clusterConfig.Workbench.DisableSharingURLsUI;
     return ({
     ...props,
     saveEnabled: hasChanges(state),
     loading: working,
     sharedResourceUuid,
-    sharingURLsNr: (filterResources(
-        (resource: ApiClientAuthorization) =>
+    sharingURLsDisabled,
+    sharingURLsNr: !sharingURLsDisabled
+        ? (filterResources( (resource: ApiClientAuthorization) =>
             resource.kind === ResourceKind.API_CLIENT_AUTHORIZATION  &&
             resource.scopes.includes(`GET /arvados/v1/collections/${sharedResourceUuid}`) &&
             resource.scopes.includes(`GET /arvados/v1/collections/${sharedResourceUuid}/`) &&
             resource.scopes.includes('GET /arvados/v1/keep_services/accessible')
-        )(state.resources) as ApiClientAuthorization[]).length,
+        )(state.resources) as ApiClientAuthorization[]).length
+        : 0,
     privateAccess: getSharingPublicAccessFormData(state)?.visibility === VisibilityLevel.PRIVATE,
     })
 };