From e1e17729d024637f9f3392611c9a59dc31e5db23 Mon Sep 17 00:00:00 2001 From: Lucas Di Pentima Date: Wed, 8 Jun 2022 15:26:18 -0300 Subject: [PATCH] 19177: Hides 'Sharing URLs' tab from Sharing dialog when configured to do so. Also, adds some unit testing on the sharing dialog component, because testing this on Cypress would require to reconfigure the backend, making other tests to fail. Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima --- src/common/config.ts | 2 + .../sharing-dialog/sharing-dialog-actions.ts | 3 +- .../sharing-dialog-component.test.tsx | 71 +++++++++++++++++++ .../sharing-dialog-component.tsx | 12 ++-- .../sharing-dialog/sharing-dialog.tsx | 9 ++- 5 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 src/views-components/sharing-dialog/sharing-dialog-component.test.tsx diff --git a/src/common/config.ts b/src/common/config.ts index 2518c95e..2954d704 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -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): Clust WebShell: { ExternalURL: "" }, }, Workbench: { + DisableSharingURLsUI: false, ArvadosDocsite: "", FileViewersConfigURL: "", WelcomePageHTML: "", diff --git a/src/store/sharing-dialog/sharing-dialog-actions.ts b/src/store/sharing-dialog/sharing-dialog-actions.ts index 367eea81..cdc6c0c7 100644 --- a/src/store/sharing-dialog/sharing-dialog-actions.ts +++ b/src/store/sharing-dialog/sharing-dialog-actions.ts @@ -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(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(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 index 00000000..36447a8d --- /dev/null +++ b/src/views-components/sharing-dialog/sharing-dialog-component.test.tsx @@ -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("", () => { + 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(); + expect(wrapper.html()).toContain('Sharing URLs (2)'); + + // disable Sharing URLs UI + props.sharingURLsDisabled = true; + wrapper = mount(); + 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(); + expect(wrapper.html()).not.toContain('Sharing URLs'); + }); +}); \ No newline at end of file diff --git a/src/views-components/sharing-dialog/sharing-dialog-component.tsx b/src/views-components/sharing-dialog/sharing-dialog-component.tsx index 15d7f660..b2f31397 100644 --- a/src/views-components/sharing-dialog/sharing-dialog-component.tsx +++ b/src/views-components/sharing-dialog/sharing-dialog-component.tsx @@ -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(SharingDialogTab.PERMISSIONS); const [expDate, setExpDate] = React.useState(); const [withExpiration, setWithExpiration] = React.useState(false); @@ -151,7 +154,8 @@ export default (props: SharingDialogDataProps & SharingDialogActionProps) => { } - { tabNr === SharingDialogTab.PERMISSIONS && privateAccess && sharingURLsNr > 0 && + { tabNr === SharingDialogTab.PERMISSIONS && !sharingURLsDisabled && + privateAccess && sharingURLsNr > 0 && Although there aren't specific permissions set, this is publicly accessible via Sharing URL(s). diff --git a/src/views-components/sharing-dialog/sharing-dialog.tsx b/src/views-components/sharing-dialog/sharing-dialog.tsx index 6b488e44..01cd390b 100644 --- a/src/views-components/sharing-dialog/sharing-dialog.tsx +++ b/src/views-components/sharing-dialog/sharing-dialog.tsx @@ -35,18 +35,21 @@ type Props = WithDialogProps & WithProgressStateProps; const mapStateToProps = (state: RootState, { working, ...props }: Props): SharingDialogDataProps => { const dialog = getDialog(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, }) }; -- 2.30.2