diff --git a/geonode_mapstore_client/client/js/components/ActionButtons/ActionButtons.jsx b/geonode_mapstore_client/client/js/components/ActionButtons/ActionButtons.jsx index 722471ca1e..68a63b258d 100644 --- a/geonode_mapstore_client/client/js/components/ActionButtons/ActionButtons.jsx +++ b/geonode_mapstore_client/client/js/components/ActionButtons/ActionButtons.jsx @@ -5,12 +5,21 @@ * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ -import React from 'react'; +import React, { useRef } from 'react'; import PropTypes from 'prop-types'; import Dropdown from '@js/components/Dropdown'; import Message from '@mapstore/framework/components/I18N/Message'; import FaIcon from '@js/components/FaIcon'; +import { canCopyResource } from '@js/utils/ResourceUtils'; +// this is a workaround based on the current structure of actions in card options +// new version will centralize this logic inside the correspondent plugins +const checkAction = { + 'delete': (resource) => !!resource?.perms?.includes('delete_resourcebase'), + // we assume tha the add_resource check has been checked in parent elements + 'copy': (resource) => canCopyResource(resource, { perms: ['add_resource'] }), + 'download': (resource) => !!(resource?.download_url && resource?.perms?.includes('download_resourcebase')) +}; function ActionButtons({ options, actions, @@ -20,16 +29,18 @@ function ActionButtons({ onDownload }) { - // do not render if the options only contain download or copy or both without meeting their requirements - if (options?.every(({action}) => action !== 'delete')) { - if (options?.every(({action}) => (action === 'download' && !resource.download_url) || (['copy'].includes(action) && !resource.is_copyable & !resource.download_url))) { - return null; - } - } - + const containerNode = useRef(); + const dropdownClassName = 'gn-card-dropdown'; + const dropdownNode = containerNode?.current?.querySelector(`.${dropdownClassName}`); + const isDropdownEmpty = (dropdownNode?.children?.length || 0) === 0; return ( -
+
event.stopPropagation()} + style={isDropdownEmpty ? { display: 'none' } : {}} + > - + {options.map((opt) => { if ((opt.type === 'button' && actions[opt.action]) || opt.action === 'download') { - return ( - ((opt.action === 'download' && resource.download_url) || (opt.action !== 'copy' && opt.action !== 'download') || (resource?.is_copyable && opt.action !== 'download')) && opt.action !== 'download' ? onAction(actions[opt.action], [ @@ -53,8 +65,8 @@ function ActionButtons({ > {' '} - - ); + ) + : null; } return ( diff --git a/geonode_mapstore_client/client/js/plugins/SaveAs.jsx b/geonode_mapstore_client/client/js/plugins/SaveAs.jsx index 645e4ceb9d..61ac1e3266 100644 --- a/geonode_mapstore_client/client/js/plugins/SaveAs.jsx +++ b/geonode_mapstore_client/client/js/plugins/SaveAs.jsx @@ -12,9 +12,8 @@ import { createSelector } from 'reselect'; import { createPlugin } from '@mapstore/framework/utils/PluginsUtils'; import { setControlProperty } from '@mapstore/framework/actions/controls'; import Message from '@mapstore/framework/components/I18N/Message'; -import { Glyphicon } from 'react-bootstrap'; import { mapInfoSelector } from '@mapstore/framework/selectors/map'; -import { isLoggedIn } from '@mapstore/framework/selectors/security'; +import { userSelector } from '@mapstore/framework/selectors/security'; import Button from '@js/components/Button'; import { saveContent, @@ -33,6 +32,7 @@ import { getResourceDirtyState } from '@js/selectors/resource'; import { ProcessTypes } from '@js/utils/ResourceServiceUtils'; +import { canCopyResource } from '@js/utils/ResourceUtils'; import { processResources } from '@js/actions/gnresource'; import { getCurrentResourceCopyLoading } from '@js/selectors/resourceservice'; @@ -133,15 +133,28 @@ function SaveAsButton({ ; } +const canCopyResourceFunction = (state) => { + return (resource) => { + const user = userSelector(state); + if (!user) { + return false; + } + const isResourceNew = isNewResource(state); + const canAdd = canAddResource(state); + if (isResourceNew && canAdd) { + return true; + } + return canCopyResource(resource, user); + }; +}; + const ConnectedSaveAsButton = connect( createSelector( - isLoggedIn, - canAddResource, getResourceData, getResourceDirtyState, - isNewResource, - (loggedIn, userCanAddResource, resource, dirtyState, isResourceNew) => ({ - enabled: loggedIn && userCanAddResource && (resource?.is_copyable || isResourceNew), + canCopyResourceFunction, + (resource, dirtyState, canCopy) => ({ + enabled: !!canCopy(resource), resource, disabled: !!dirtyState }) @@ -154,20 +167,6 @@ const ConnectedSaveAsButton = connect( export default createPlugin('SaveAs', { component: SaveAsPlugin, containers: { - BurgerMenu: { - name: 'saveAs', - position: 30, - text: , - icon: , - action: setControlProperty.bind(null, 'saveAs', null), - selector: createSelector( - isLoggedIn, - canAddResource, - (loggedIn, userCanAddResource) => ({ - style: (loggedIn && userCanAddResource) ? {} : { display: 'none' } - }) - ) - }, ActionNavbar: { name: 'SaveAs', Component: ConnectedSaveAsButton diff --git a/geonode_mapstore_client/client/js/utils/ResourceUtils.js b/geonode_mapstore_client/client/js/utils/ResourceUtils.js index 8a8d0069af..26b039aa06 100644 --- a/geonode_mapstore_client/client/js/utils/ResourceUtils.js +++ b/geonode_mapstore_client/client/js/utils/ResourceUtils.js @@ -585,13 +585,19 @@ export const parseMapConfig = (mapResponse, resource = {}) => { }; }; -/** -* Util to check if resosurce can be cloned (Save As) +/* +* Util to check if resource can be cloned (Save As) * Requirements for copying are 'add_resource' permission and is_copyable property on resource +* the dataset and document need also the download_resourcebase permission */ export const canCopyResource = (resource, user) => { const canAdd = user?.perms?.includes('add_resource'); const canCopy = resource?.is_copyable; + const resourceType = resource?.resource_type; + if ([ResourceTypes.DATASET, ResourceTypes.DOCUMENT].includes(resourceType)) { + const canDownload = !!resource?.perms?.includes('download_resourcebase'); + return (canAdd && canCopy && canDownload) ? true : false; + } return (canAdd && canCopy) ? true : false; }; diff --git a/geonode_mapstore_client/client/js/utils/__tests__/ResourceUtils-test.js b/geonode_mapstore_client/client/js/utils/__tests__/ResourceUtils-test.js index f81327b28f..c68a88097c 100644 --- a/geonode_mapstore_client/client/js/utils/__tests__/ResourceUtils-test.js +++ b/geonode_mapstore_client/client/js/utils/__tests__/ResourceUtils-test.js @@ -422,11 +422,19 @@ describe('Test Resource Utils', () => { expect(pasrsedStyleName).toBe('test:testName'); }); - it('should test canCopyResource', () => { - const resource = { is_copyable: true }; + it('should test canCopyResource with different resource type', () => { const user = { perms: ['add_resource'] }; + expect(canCopyResource({ resource_type: 'dataset', perms: ['download_resourcebase'], is_copyable: true }, user)).toBe(true); + expect(canCopyResource({ resource_type: 'document', perms: ['download_resourcebase'], is_copyable: true }, user)).toBe(true); + expect(canCopyResource({ resource_type: 'map', perms: [], is_copyable: true }, user)).toBe(true); + expect(canCopyResource({ resource_type: 'geostory', perms: [], is_copyable: true }, user)).toBe(true); + expect(canCopyResource({ resource_type: 'dashboard', perms: [], is_copyable: true }, user)).toBe(true); - expect(canCopyResource(resource, user)).toEqual(true); + expect(canCopyResource({ resource_type: 'dataset', perms: [], is_copyable: true }, user)).toBe(false); + expect(canCopyResource({ resource_type: 'document', perms: [], is_copyable: true }, user)).toBe(false); + expect(canCopyResource({ resource_type: 'map', perms: [] }, user)).toBe(false); + expect(canCopyResource({ resource_type: 'geostory', perms: [] }, user)).toBe(false); + expect(canCopyResource({ resource_type: 'dashboard', perms: [] }, user)).toBe(false); }); it('should test excludeDeletedResources', () => { diff --git a/geonode_mapstore_client/client/static/mapstore/configs/localConfig.json b/geonode_mapstore_client/client/static/mapstore/configs/localConfig.json index 3bfaf8b52a..9385067f4f 100644 --- a/geonode_mapstore_client/client/static/mapstore/configs/localConfig.json +++ b/geonode_mapstore_client/client/static/mapstore/configs/localConfig.json @@ -450,10 +450,6 @@ { "type": "user", "value": "add_resource" - }, - { - "type": "resource", - "value": "download_resourcebase" } ] },