From f0c756ea4a60ddc55672c8a7047d2d60639b0211 Mon Sep 17 00:00:00 2001 From: Suren Date: Fri, 9 May 2025 15:41:21 +0530 Subject: [PATCH 1/5] #1977: Move group and owner setting to management panel --- .../client/js/api/geonode/v2/index.js | 9 ++ .../client/js/epics/__tests__/gnsave-test.js | 101 +++++++++++++++- .../client/js/epics/gnsave.js | 108 +++++++++++------- .../components/DetailsSettings.jsx | 44 ++++++- .../containers/DetailsPanel.jsx | 8 +- .../containers/Permissions/index.jsx | 18 +-- .../client/js/selectors/resource.js | 8 +- .../client/js/utils/ResourceUtils.js | 60 +++++++++- .../mapstore/gn-translations/data.de-DE.json | 3 + .../mapstore/gn-translations/data.en-US.json | 3 + .../mapstore/gn-translations/data.es-ES.json | 3 + .../mapstore/gn-translations/data.fi-FI.json | 3 + .../mapstore/gn-translations/data.fr-FR.json | 3 + .../mapstore/gn-translations/data.hr-HR.json | 3 + .../mapstore/gn-translations/data.it-IT.json | 3 + .../mapstore/gn-translations/data.nl-NL.json | 3 + .../mapstore/gn-translations/data.pt-PT.json | 3 + .../mapstore/gn-translations/data.sk-SK.json | 3 + .../mapstore/gn-translations/data.sv-SE.json | 3 + .../mapstore/gn-translations/data.vi-VN.json | 3 + .../mapstore/gn-translations/data.zh-ZH.json | 3 + 21 files changed, 328 insertions(+), 67 deletions(-) diff --git a/geonode_mapstore_client/client/js/api/geonode/v2/index.js b/geonode_mapstore_client/client/js/api/geonode/v2/index.js index 8bab5ca350..fe93110b9d 100644 --- a/geonode_mapstore_client/client/js/api/geonode/v2/index.js +++ b/geonode_mapstore_client/client/js/api/geonode/v2/index.js @@ -377,11 +377,13 @@ export const getUsers = ({ q, page = 1, pageSize = 20, + config, ...params } = {}) => { return axios.get( getEndpointUrl(USERS), { + ...config, params: { ...params, ...(q && { @@ -406,11 +408,13 @@ export const getGroups = ({ q, page = 1, pageSize = 20, + config, ...params } = {}) => { return axios.get( getEndpointUrl(GROUPS), { + ...config, params: { ...params, ...(q && { @@ -431,6 +435,11 @@ export const getGroups = ({ }); }; +export const transferResource = (pk, body) => { + return axios.post(getEndpointUrl(USERS, `/${pk}/transfer_resources`), body) + .then(({ data }) => (data)); +}; + export const getUserByPk = (pk, apikey) => { return axios.get(getEndpointUrl(USERS, `/${pk}`), { params: { diff --git a/geonode_mapstore_client/client/js/epics/__tests__/gnsave-test.js b/geonode_mapstore_client/client/js/epics/__tests__/gnsave-test.js index 4ddefa3268..d75436f0db 100644 --- a/geonode_mapstore_client/client/js/epics/__tests__/gnsave-test.js +++ b/geonode_mapstore_client/client/js/epics/__tests__/gnsave-test.js @@ -33,6 +33,7 @@ import { SET_EDIT_PERMISSION } from '@mapstore/framework/actions/styleeditor'; import { configureMap } from '@mapstore/framework/actions/config'; import { selectNode, addLayer } from '@mapstore/framework/actions/layers'; +import { START_ASYNC_PROCESS } from '@js/actions/resourceservice'; let mockAxios; @@ -49,6 +50,93 @@ describe('gnsave epics', () => { setTimeout(done); }); it('should create new map with success (gnSaveContent)', (done) => { + const NUM_ACTIONS = 5; + const metadata = { + title: 'Title', + description: 'Description', + thumbnail: 'thumbnail.jpeg' + }; + mockAxios.onPost().reply(() => [200, { map: {} }]); + mockAxios.onPut().reply(() => [200, { output: {} }]); + testEpic( + gnSaveContent, + NUM_ACTIONS, + saveContent(undefined, metadata, false), + (actions) => { + try { + expect(actions.map(({ type }) => type)) + .toEqual([ + SAVING_RESOURCE, + SAVE_SUCCESS, + SET_RESOURCE, + UPDATE_SINGLE_RESOURCE, + START_ASYNC_PROCESS + ]); + } catch (e) { + done(e); + } + done(); + }, + { + gnresource: { + data: { + resource_type: "map" + }, + isCompactPermissionsChanged: true, + compactPermissions: { + users: [], + organizations: [], + groups: [] + } + } + } + ); + }); + it('should update existing map with success (gnSaveContent)', (done) => { + const NUM_ACTIONS = 5; + const id = 1; + const metadata = { + title: 'Title', + description: 'Description', + thumbnail: 'thumbnail.jpeg' + }; + mockAxios.onPatch().reply(() => [200, {}]); + mockAxios.onPut().reply(() => [200, { output: {} }]); + testEpic( + gnSaveContent, + NUM_ACTIONS, + saveContent(id, metadata, false, false), + (actions) => { + try { + expect(actions.map(({ type }) => type)) + .toEqual([ + SAVING_RESOURCE, + SAVE_SUCCESS, + SET_RESOURCE, + UPDATE_SINGLE_RESOURCE, + START_ASYNC_PROCESS + ]); + } catch (e) { + done(e); + } + done(); + }, + { + gnresource: { + data: { + resource_type: "map" + }, + isCompactPermissionsChanged: true, + compactPermissions: { + users: [], + organizations: [], + groups: [] + } + } + } + ); + }); + it('should skip permission update when permission is unchanged', (done) => { const NUM_ACTIONS = 4; const metadata = { title: 'Title', @@ -56,6 +144,7 @@ describe('gnsave epics', () => { thumbnail: 'thumbnail.jpeg' }; mockAxios.onPost().reply(() => [200, { map: {} }]); + mockAxios.onPut().reply(() => [200, { output: {} }]); testEpic( gnSaveContent, NUM_ACTIONS, @@ -110,7 +199,15 @@ describe('gnsave epics', () => { }, { gnresource: { - type: "map" + data: { + resource_type: "map" + }, + isCompactPermissionsChanged: false, + compactPermissions: { + users: [], + organizations: [], + groups: [] + } } } ); @@ -170,7 +267,7 @@ describe('gnsave epics', () => { 'thumbnail_url': 'thumbnail.jpeg' }; mockAxios.onGet(new RegExp(`resources/${pk}`)) - .reply(200, resource); + .reply(200, {resource}); testEpic( gnSaveDirectContent, NUM_ACTIONS, diff --git a/geonode_mapstore_client/client/js/epics/gnsave.js b/geonode_mapstore_client/client/js/epics/gnsave.js index 67a746c760..21ca9862fa 100644 --- a/geonode_mapstore_client/client/js/epics/gnsave.js +++ b/geonode_mapstore_client/client/js/epics/gnsave.js @@ -10,6 +10,7 @@ import axios from '@mapstore/framework/libs/ajax'; import { Observable } from 'rxjs'; import get from 'lodash/get'; import castArray from 'lodash/castArray'; +import isEqual from 'lodash/isEqual'; import { mapInfoSelector } from '@mapstore/framework/selectors/map'; import { userSelector } from '@mapstore/framework/selectors/security'; @@ -76,17 +77,18 @@ import { cleanCompactPermissions, toGeoNodeMapConfig, RESOURCE_MANAGEMENT_PROPERTIES, - getDimensions + getDimensions, + GROUP_OWNER_PROPERTIES } from '@js/utils/ResourceUtils'; import { ProcessTypes, ProcessStatus } from '@js/utils/ResourceServiceUtils'; -import { updateDatasetTimeSeries } from '@js/api/geonode/v2/index'; +import { transferResource, updateDatasetTimeSeries } from '@js/api/geonode/v2/index'; import { updateNode } from '@mapstore/framework/actions/layers'; import { layersSelector } from '@mapstore/framework/selectors/layers'; -const RESOURCE_MANAGEMENT_PROPERTIES_KEYS = Object.keys(RESOURCE_MANAGEMENT_PROPERTIES); +const RESOURCE_MANAGEMENT_PROPERTIES_KEYS = Object.keys({...RESOURCE_MANAGEMENT_PROPERTIES, ...GROUP_OWNER_PROPERTIES}); function parseMapBody(body) { const geoNodeMap = toGeoNodeMapConfig(body.data); @@ -169,11 +171,13 @@ export const gnSaveContent = (action$, store) => const contentType = state.gnresource?.type || currentResource?.resource_type; const data = !currentResource?.['@ms-detail'] ? getDataPayload(state, contentType) : null; const extent = getExtentPayload(state, contentType); + const { compactPermissions } = getPermissionsPayload(state); const body = { 'title': action.metadata.name, ...(RESOURCE_MANAGEMENT_PROPERTIES_KEYS.reduce((acc, key) => { if (currentResource?.[key] !== undefined) { - acc[key] = !!currentResource[key]; + const value = typeof currentResource[key] === 'boolean' ? !!currentResource[key] : currentResource[key]; + acc[key] = value; } return acc; }, {})), @@ -193,22 +197,34 @@ export const gnSaveContent = (action$, store) => window.location.reload(); return Observable.empty(); } - return Observable.of( - saveSuccess(resource), - setResource({ - ...currentResource, - ...body, - ...resource - }), - updateResource(resource), - ...(action.showNotifications - ? [ - action.showNotifications === true - ? successNotification({title: "saveDialog.saveSuccessTitle", message: "saveDialog.saveSuccessMessage"}) - : warningNotification(action.showNotifications) - ] - : []), - ...actions // additional actions to be dispatched + return Observable.merge( + Observable.of( + saveSuccess(resource), + setResource({ + ...currentResource, + ...body, + ...resource + }), + updateResource(resource), + ...(action.showNotifications + ? [ + action.showNotifications === true + ? successNotification({title: "saveDialog.saveSuccessTitle", message: "saveDialog.saveSuccessMessage"}) + : warningNotification(action.showNotifications) + ] + : []), + ...actions // additional actions to be dispatched + ), + ...(compactPermissions ? [ + Observable.defer(() => + updateCompactPermissionsByPk(action.id, cleanCompactPermissions(compactPermissions)) + .then(output => ({ resource: currentResource, output, processType: ProcessTypes.PERMISSIONS_RESOURCE })) + .catch((error) => ({ resource: currentResource, error: error?.data?.detail || error?.statusText || error?.message || true, processType: ProcessTypes.PERMISSIONS_RESOURCE })) + ) + .switchMap((payload) => { + return Observable.of(startAsyncProcess(payload)); + }) + ] : []) ); }) .catch((error) => { @@ -264,22 +280,35 @@ export const gnSaveDirectContent = (action$, store) => const state = store.getState(); const mapInfo = mapInfoSelector(state); const resourceId = mapInfo?.id || getResourceId(state); - const { compactPermissions, geoLimits } = getPermissionsPayload(state); + const { geoLimits } = getPermissionsPayload(state); const currentResource = getResourceData(state); - return Observable.defer(() => axios.all([ - getResourceByPk(resourceId), - ...(geoLimits - ? geoLimits.map((limits) => - limits.features.length === 0 - ? deleteGeoLimits(resourceId, limits.id, limits.type) - .catch(() => ({ error: true, resourceId, limits })) - : updateGeoLimits(resourceId, limits.id, limits.type, { features: limits.features }) - .catch(() => ({ error: true, resourceId, limits })) - ) - : []) - ])) - .switchMap(([resource, ...geoLimitsResponses]) => { + const newOwner = get(currentResource, 'owner.pk', null); + const currentOwner = get(state, 'gnresource.initialResource.owner.pk', null); + const userId = userSelector(state)?.pk; + let transferOwnership; + if (newOwner && userId && !isEqual(currentOwner, newOwner)) { + transferOwnership = { currentOwner, newOwner, resources: [Number(resourceId)] }; + } + + // resource information should be saved in a synchronous manner + // i.e transfer ownership (if any) followed by resource data and finally permissions + return Observable.concat( + transferOwnership ? Observable.defer(() => transferResource(userId, transferOwnership)) : Promise.resolve(), + Observable.defer(() => axios.all([ + getResourceByPk(resourceId), + ...(geoLimits + ? geoLimits.map((limits) => + limits.features.length === 0 + ? deleteGeoLimits(resourceId, limits.id, limits.type) + .catch(() => ({ error: true, resourceId, limits })) + : updateGeoLimits(resourceId, limits.id, limits.type, { features: limits.features }) + .catch(() => ({ error: true, resourceId, limits })) + ) + : []) + ]))).toArray() + .switchMap(([, responses]) => { + const [resource, ...geoLimitsResponses] = responses; const geoLimitsErrors = geoLimitsResponses.filter(({ error }) => error); const name = getResourceName(state); const description = getResourceDescription(state); @@ -290,16 +319,6 @@ export const gnSaveDirectContent = (action$, store) => href: resource?.href }; return Observable.concat( - ...(compactPermissions ? [ - Observable.defer(() => - updateCompactPermissionsByPk(resourceId, cleanCompactPermissions(compactPermissions)) - .then(output => ({ resource: currentResource, output, processType: ProcessTypes.PERMISSIONS_RESOURCE })) - .catch((error) => ({ resource: currentResource, error: error?.data?.detail || error?.statusText || error?.message || true, processType: ProcessTypes.PERMISSIONS_RESOURCE })) - ) - .switchMap((payload) => { - return Observable.of(startAsyncProcess(payload)); - }) - ] : []), Observable.of( saveContent( resourceId, @@ -313,6 +332,7 @@ export const gnSaveDirectContent = (action$, store) => : true /* showNotification */), resetGeoLimits() ) + ); }) .catch((error) => { diff --git a/geonode_mapstore_client/client/js/plugins/ResourceDetails/components/DetailsSettings.jsx b/geonode_mapstore_client/client/js/plugins/ResourceDetails/components/DetailsSettings.jsx index a5052957f5..0d401d77a1 100644 --- a/geonode_mapstore_client/client/js/plugins/ResourceDetails/components/DetailsSettings.jsx +++ b/geonode_mapstore_client/client/js/plugins/ResourceDetails/components/DetailsSettings.jsx @@ -1,11 +1,16 @@ import React, { forwardRef } from 'react'; -import { Checkbox } from 'react-bootstrap'; +import { connect } from 'react-redux'; +import { createStructuredSelector } from 'reselect'; +import { Checkbox, FormGroup, ControlLabel } from 'react-bootstrap'; + import Message from '@mapstore/framework/components/I18N/Message'; import tooltip from '@mapstore/framework/components/misc/enhancers/tooltip'; -import { RESOURCE_MANAGEMENT_PROPERTIES } from '@js/utils/ResourceUtils'; -import TimeSeriesSettings from './DetailsTimeSeries'; +import { GROUP_OWNER_PROPERTIES, RESOURCE_MANAGEMENT_PROPERTIES } from '@js/utils/ResourceUtils'; +import TimeSeriesSettings from '@js/plugins/ResourceDetails/components/DetailsTimeSeries'; import FlexBox from '@mapstore/framework/components/layout/FlexBox'; import Text from '@mapstore/framework/components/layout/Text'; +import SelectInfiniteScroll from '@mapstore/framework/plugins/ResourcesCatalog/components/SelectInfiniteScroll'; +import { getCompactPermissions } from '@js/selectors/resource'; const MessageTooltip = tooltip(forwardRef(({children, msgId, ...props}, ref) => { return ( @@ -17,10 +22,35 @@ const MessageTooltip = tooltip(forwardRef(({children, msgId, ...props}, ref) => ); })); -function DetailsSettings({ resource, onChange }) { +function DetailsSettings({ resource, user, compactPermissions, onChange }) { const perms = resource?.perms || []; return ( + + {Object.keys(GROUP_OWNER_PROPERTIES).map((key) => { + const { labelId, disabled, placeholderId, labelKey, loadOptions, clearable } = + GROUP_OWNER_PROPERTIES[key]; + return ( + + + + { + onChange({ + [key]: selected?.value ?? null + }); + }} + loadOptions={(...args) => loadOptions(...args, compactPermissions)} + /> + + + ); + })} + @@ -46,4 +76,8 @@ function DetailsSettings({ resource, onChange }) { ); } -export default DetailsSettings; +export default connect( + createStructuredSelector({ + compactPermissions: getCompactPermissions + }), {} +)(DetailsSettings); diff --git a/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/DetailsPanel.jsx b/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/DetailsPanel.jsx index 712a9eb701..9418671154 100644 --- a/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/DetailsPanel.jsx +++ b/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/DetailsPanel.jsx @@ -24,6 +24,7 @@ import { } from '@js/selectors/resource'; import Message from '@mapstore/framework/components/I18N/Message'; import { mapSelector } from '@mapstore/framework/selectors/map'; +import { userSelector } from '@mapstore/framework/selectors/security'; import DetailsInfo from '@mapstore/framework/plugins/ResourcesCatalog/components/DetailsInfo'; import { replaceResourcePaths } from '@mapstore/framework/utils/GeostoreUtils'; import Text from '@mapstore/framework/components/layout/Text'; @@ -75,7 +76,8 @@ function DetailsPanel({ resourcesGridId, monitoredState, location, - panelRef + panelRef, + user }, context) { const resource = parseCatalogResource(resourceProp); @@ -141,6 +143,7 @@ function DetailsPanel({ resource={resource || {}} enableFilters={enableFilters} editing={editing} + user={user} /> : null} {(loading) ? @@ -158,7 +161,8 @@ DetailsPanel.contextTypes = { const ConnectedDetailsPanel = connect( createStructuredSelector({ monitoredState: getMonitoredStateSelector, - location: getRouterLocation + location: getRouterLocation, + user: userSelector }) )(DetailsPanel); diff --git a/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/Permissions/index.jsx b/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/Permissions/index.jsx index ddaf497edf..537d69d8be 100644 --- a/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/Permissions/index.jsx +++ b/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/Permissions/index.jsx @@ -21,7 +21,8 @@ import { import { updateResourceCompactPermissions } from "@js/actions/gnresource"; import { getCompactPermissions, - getViewedResourceType + getViewedResourceType, + resourceOwnerSelector } from "@js/selectors/resource"; import { getCurrentResourcePermissionsLoading } from "@js/selectors/resourceservice"; import { @@ -34,7 +35,7 @@ import { } from "@js/utils/ResourceUtils"; import GeoLimits from "./GeoLimits"; -const entriesTabs = [ +const getEntriesTabs = (owner) => [ { id: "user", labelId: "gnviewer.users", @@ -44,7 +45,7 @@ const entriesTabs = [ .map(({ id }) => id); return getUsers({ ...params, - "filter{-pk.in}": [...exclude, -1], + "filter{-pk.in}": [...exclude, owner.pk, -1], // exclude existing users along with owner and anonymous user "filter{is_superuser}": false }); }, @@ -88,6 +89,7 @@ const entriesTabs = [ const Permissions = ({ + owner, resourceType, permissionsLoading, compactPermissions, @@ -116,7 +118,7 @@ const Permissions = ({ onChangePermissions(permissionsListsToCompact(value)) } @@ -137,12 +139,14 @@ export default connect( [ getCompactPermissions, getCurrentResourcePermissionsLoading, - getViewedResourceType + getViewedResourceType, + resourceOwnerSelector ], - (compactPermissions, permissionsLoading, type) => ({ + (compactPermissions, permissionsLoading, type, owner) => ({ compactPermissions, permissionsLoading, - resourceType: type + resourceType: type, + owner }) ), { diff --git a/geonode_mapstore_client/client/js/selectors/resource.js b/geonode_mapstore_client/client/js/selectors/resource.js index f58251ad63..91c14cb817 100644 --- a/geonode_mapstore_client/client/js/selectors/resource.js +++ b/geonode_mapstore_client/client/js/selectors/resource.js @@ -12,7 +12,7 @@ import { compareMapChanges } from '@mapstore/framework/utils/MapUtils'; import { currentStorySelector } from '@mapstore/framework/selectors/geostory'; import { originalDataSelector } from '@mapstore/framework/selectors/dashboard'; import { widgetsConfig } from '@mapstore/framework/selectors/widgets'; -import { ResourceTypes, RESOURCE_MANAGEMENT_PROPERTIES } from '@js/utils/ResourceUtils'; +import { ResourceTypes, RESOURCE_MANAGEMENT_PROPERTIES, GROUP_OWNER_PROPERTIES } from '@js/utils/ResourceUtils'; import { getCurrentResourceDeleteLoading, getCurrentResourceCopyLoading @@ -28,7 +28,7 @@ import omitBy from 'lodash/omitBy'; import { generateContextResource } from '@mapstore/framework/selectors/contextcreator'; import { layerSettingSelector, getSelectedLayer as getSelectedNode } from '@mapstore/framework/selectors/layers'; -const RESOURCE_MANAGEMENT_PROPERTIES_KEYS = Object.keys(RESOURCE_MANAGEMENT_PROPERTIES); +const RESOURCE_MANAGEMENT_PROPERTIES_KEYS = Object.keys({...RESOURCE_MANAGEMENT_PROPERTIES, ...GROUP_OWNER_PROPERTIES}); /** * @module selectors/resource @@ -64,6 +64,10 @@ export const isThumbnailChanged = (state) => { return state?.gnresource?.data?.thumbnailChanged || false; }; +export const resourceOwnerSelector = (state) => { + return state?.gnresource?.data?.owner || {}; +}; + export const getViewedResourceType = (state) => { const viewedResourceType = state?.gnresource?.type || false; return viewedResourceType; diff --git a/geonode_mapstore_client/client/js/utils/ResourceUtils.js b/geonode_mapstore_client/client/js/utils/ResourceUtils.js index 6909097ba3..fcf858f488 100644 --- a/geonode_mapstore_client/client/js/utils/ResourceUtils.js +++ b/geonode_mapstore_client/client/js/utils/ResourceUtils.js @@ -8,15 +8,16 @@ import uuid from 'uuid'; import url from 'url'; -import isEmpty from 'lodash/isEmpty'; -import omit from 'lodash/omit'; +import { isEmpty, uniqBy, omit, orderBy, isString, isObject } from 'lodash'; + +import { isImageServerUrl } from '@mapstore/framework/utils/ArcGISUtils'; import { getConfigProp, convertFromLegacy, normalizeConfig } from '@mapstore/framework/utils/ConfigUtils'; +import { excludeGoogleBackground, extractTileMatrixFromSources, ServerTypes } from '@mapstore/framework/utils/LayersUtils'; + +import { getGroups, getUsers } from '@js/api/geonode/v2'; import { getGeoNodeLocalConfig, parseDevHostname } from '@js/utils/APIUtils'; import { ProcessTypes, ProcessStatus } from '@js/utils/ResourceServiceUtils'; -import { uniqBy, orderBy, isString, isObject } from 'lodash'; -import { excludeGoogleBackground, extractTileMatrixFromSources, ServerTypes } from '@mapstore/framework/utils/LayersUtils'; import { determineResourceType } from '@js/utils/FileUtils'; -import { isImageServerUrl } from '@mapstore/framework/utils/ArcGISUtils'; /** * @module utils/ResourceUtils @@ -80,6 +81,55 @@ export const RESOURCE_MANAGEMENT_PROPERTIES = { } }; +export const GROUP_OWNER_PROPERTIES = { + 'owner': { + labelId: 'gnviewer.owner', + placeholderId: 'gnviewer.ownerPlaceholder', + labelKey: 'username', + clearable: false, + disabled: ({user}) => !user.is_superuser, + loadOptions: ({ q, ...params }, compactPermissions) => { + const { users = [] } = compactPermissions; + const exclude = users + .filter(({ permissions }) => permissions !== "owner") + .map(({ id }) => id); + return getUsers({ + ...params, + "filter{-pk.in}": [...exclude, -1], // self assignment is not allowed along with anonymous user + "filter{is_superuser}": false + }) + .then((response) => { + return { + ...response, + results: (response?.users ?? []) + .map((item) => ({...item, selectOption: { + value: item, + label: item.username + }})) + }; + }); + } + }, + 'group': { + labelId: 'gnviewer.group', + placeholderId: 'gnviewer.groupPlaceholder', + clearable: true, + disabled: ({perms = []}) => !perms.includes('change_resourcebase'), + loadOptions: ({ q, ...params }) => getGroups({q, ...params}) + .then((response) => { + return { + ...response, + results: (response?.groups ?? []) + .map((item) => ({...item, selectOption: { + value: item.group, + label: item.group.name + }})) + }; + }), + labelKey: 'name' + } +}; + export const TIME_SERIES_PROPERTIES = ['attribute', 'end_attribute', 'presentation', 'precision_value', 'precision_step']; export const TIME_ATTRIBUTE_TYPES = ['xsd:date', 'xsd:dateTime', 'xsd:date-time', 'xsd:time']; diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.de-DE.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.de-DE.json index c9c8574996..1aac161986 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.de-DE.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.de-DE.json @@ -200,6 +200,8 @@ "filterBy": "Filtern...", "addPermissionsEntry": "Benutzer / Gruppen hinzufügen", "groups": "Gruppen", + "group": "Gruppe", + "groupPlaceholder": "Gruppe auswählen", "users": "Benutzer", "nonePermission": "Keiner", "viewPermission": "Ansicht", @@ -323,6 +325,7 @@ "iso": "ISO -Metadaten", "dublinCore": "Dublin Core Metadaten", "owner": "Eigentümer", + "ownerPlaceholder": "Eigentümer auswählen", "creation": "Erstellungsdatum", "publication": "Veröffentlichung", "revision": "Überarbeitung", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.en-US.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.en-US.json index 6ab3cbb47e..e49658e3b0 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.en-US.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.en-US.json @@ -199,6 +199,8 @@ "attributes": "Attributes", "filterBy": "Filter...", "addPermissionsEntry": "Add Users / Groups", + "group": "Group", + "groupPlaceholder": "Select group", "groups": "Groups", "users": "Users", "nonePermission": "None", @@ -323,6 +325,7 @@ "iso": "ISO Metadata", "dublinCore": "Dublin Core Metadata", "owner": "Owner", + "ownerPlaceholder": "Select owner", "creation": "Creation", "publication": "Publication", "revision": "Revision", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.es-ES.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.es-ES.json index 13e8dcdce3..d9c1934afa 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.es-ES.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.es-ES.json @@ -200,6 +200,8 @@ "filterBy": "Filtro ...", "addPermissionsEntry": "Agregar usuarios / grupos", "groups": "Grupos", + "group": "Grupo", + "groupPlaceholder": "Seleccionar grupo", "users": "Usuarios", "nonePermission": "Ninguno", "viewPermission": "Ver", @@ -322,6 +324,7 @@ "iso": "Metadatos iso", "dublinCore": "Metadatos de Dublin Core", "owner": "Propietario", + "ownerPlaceholder": "Seleccionar propietario", "creation": "Creación", "publication": "Publicación", "revision": "Revisión", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.fi-FI.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.fi-FI.json index 91eb411c4a..0cdbd3e281 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.fi-FI.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.fi-FI.json @@ -198,6 +198,8 @@ "filterBy": "Filter...", "addPermissionsEntry": "Add Users / Groups", "groups": "Groups", + "group": "Group", + "groupPlaceholder": "Select group", "users": "Users", "nonePermission": "None", "viewPermission": "View", @@ -297,6 +299,7 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", + "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.fr-FR.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.fr-FR.json index 18577d24d0..8fb46fb591 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.fr-FR.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.fr-FR.json @@ -200,6 +200,8 @@ "filterBy": "Filtrer...", "addPermissionsEntry": "Ajouter des utilisateurs/groupes", "groups": "Groupes", + "group": "Groupe", + "groupPlaceholder": "Sélectionner un groupe", "users": "Utilisateurs", "nonePermission": "Rien", "viewPermission": "View", @@ -323,6 +325,7 @@ "iso": "Métadonnées ISO", "dublinCore": "Métadonnées de Dublin Core", "owner": "Propriétaire", + "ownerPlaceholder": "Sélectionner le propriétaire", "creation": "Création", "publication": "Publication", "revision": "Révision", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.hr-HR.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.hr-HR.json index 26cb27a92b..2ccf6566a9 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.hr-HR.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.hr-HR.json @@ -198,6 +198,8 @@ "filterBy": "Filter...", "addPermissionsEntry": "Add Users / Groups", "groups": "Groups", + "group": "Group", + "groupPlaceholder": "Select group", "users": "Users", "nonePermission": "None", "viewPermission": "View", @@ -297,6 +299,7 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", + "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.it-IT.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.it-IT.json index e30942d319..d21bbd8024 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.it-IT.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.it-IT.json @@ -202,6 +202,8 @@ "filterBy": "Filtra...", "addPermissionsEntry": "Aggiungi utenti/gruppi", "groups": "Gruppi", + "group": "Gruppo", + "groupPlaceholder": "Seleziona gruppo", "users": "Utenti", "nonePermission": "Nessuno", "viewPermission": "Visualizza", @@ -325,6 +327,7 @@ "iso": "Metadati ISO", "dublinCore": "Metadati di Dublin Core", "owner": "Proprietario", + "ownerPlaceholder": "Seleziona proprietario", "date": "Data", "creation": "Creazione", "publication": "Pubblicazione", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.nl-NL.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.nl-NL.json index 9ffe31d704..e89ed21ac4 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.nl-NL.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.nl-NL.json @@ -198,6 +198,8 @@ "filterBy": "Filter...", "addPermissionsEntry": "Add Users / Groups", "groups": "Groups", + "group": "Group", + "groupPlaceholder": "Select group", "users": "Users", "nonePermission": "None", "viewPermission": "View", @@ -297,6 +299,7 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", + "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.pt-PT.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.pt-PT.json index 1316f2199a..0fb993decb 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.pt-PT.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.pt-PT.json @@ -198,6 +198,8 @@ "filterBy": "Filter...", "addPermissionsEntry": "Add Users / Groups", "groups": "Groups", + "group": "Group", + "groupPlaceholder": "Select group", "users": "Users", "nonePermission": "None", "viewPermission": "View", @@ -297,6 +299,7 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", + "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.sk-SK.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.sk-SK.json index cd6037d4f8..54e00c78c0 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.sk-SK.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.sk-SK.json @@ -198,6 +198,8 @@ "filterBy": "Filter...", "addPermissionsEntry": "Add Users / Groups", "groups": "Groups", + "group": "Group", + "groupPlaceholder": "Select group", "users": "Users", "nonePermission": "None", "viewPermission": "View", @@ -297,6 +299,7 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", + "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.sv-SE.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.sv-SE.json index 7f25137d04..ebb5b496c9 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.sv-SE.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.sv-SE.json @@ -199,6 +199,8 @@ "filterBy": "Filter...", "addPermissionsEntry": "Add Users / Groups", "groups": "Groups", + "group": "Group", + "groupPlaceholder": "Select group", "users": "Users", "nonePermission": "None", "viewPermission": "View", @@ -298,6 +300,7 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", + "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.vi-VN.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.vi-VN.json index 93c6cc0d83..c69144823b 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.vi-VN.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.vi-VN.json @@ -198,6 +198,8 @@ "filterBy": "Filter...", "addPermissionsEntry": "Add Users / Groups", "groups": "Groups", + "group": "Group", + "groupPlaceholder": "Select group", "users": "Users", "nonePermission": "None", "viewPermission": "View", @@ -297,6 +299,7 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", + "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.zh-ZH.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.zh-ZH.json index b88b4e67a2..6065f806c4 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.zh-ZH.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.zh-ZH.json @@ -198,6 +198,8 @@ "filterBy": "Filter...", "addPermissionsEntry": "Add Users / Groups", "groups": "Groups", + "group": "Group", + "groupPlaceholder": "Select group", "users": "Users", "nonePermission": "None", "viewPermission": "View", @@ -297,6 +299,7 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", + "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", From 90add8f48559ed8c2df3add2b0518520010f153c Mon Sep 17 00:00:00 2001 From: Suren Date: Mon, 16 Jun 2025 17:07:41 +0530 Subject: [PATCH 2/5] update group update (cherry picked from commit f19ea4a0f62a0ca8f446af653572872fcf1211d4) --- .../client/js/api/geonode/v2/index.js | 5 - .../client/js/epics/gnsave.js | 97 ++++++++----------- .../components/DetailsSettings.jsx | 53 +++++----- .../client/js/selectors/resource.js | 6 +- .../client/js/utils/ResourceUtils.js | 49 ---------- 5 files changed, 72 insertions(+), 138 deletions(-) diff --git a/geonode_mapstore_client/client/js/api/geonode/v2/index.js b/geonode_mapstore_client/client/js/api/geonode/v2/index.js index fe93110b9d..ca594cdb64 100644 --- a/geonode_mapstore_client/client/js/api/geonode/v2/index.js +++ b/geonode_mapstore_client/client/js/api/geonode/v2/index.js @@ -435,11 +435,6 @@ export const getGroups = ({ }); }; -export const transferResource = (pk, body) => { - return axios.post(getEndpointUrl(USERS, `/${pk}/transfer_resources`), body) - .then(({ data }) => (data)); -}; - export const getUserByPk = (pk, apikey) => { return axios.get(getEndpointUrl(USERS, `/${pk}`), { params: { diff --git a/geonode_mapstore_client/client/js/epics/gnsave.js b/geonode_mapstore_client/client/js/epics/gnsave.js index 21ca9862fa..8a5817e183 100644 --- a/geonode_mapstore_client/client/js/epics/gnsave.js +++ b/geonode_mapstore_client/client/js/epics/gnsave.js @@ -10,7 +10,6 @@ import axios from '@mapstore/framework/libs/ajax'; import { Observable } from 'rxjs'; import get from 'lodash/get'; import castArray from 'lodash/castArray'; -import isEqual from 'lodash/isEqual'; import { mapInfoSelector } from '@mapstore/framework/selectors/map'; import { userSelector } from '@mapstore/framework/selectors/security'; @@ -77,18 +76,17 @@ import { cleanCompactPermissions, toGeoNodeMapConfig, RESOURCE_MANAGEMENT_PROPERTIES, - getDimensions, - GROUP_OWNER_PROPERTIES + getDimensions } from '@js/utils/ResourceUtils'; import { ProcessTypes, ProcessStatus } from '@js/utils/ResourceServiceUtils'; -import { transferResource, updateDatasetTimeSeries } from '@js/api/geonode/v2/index'; +import { updateDatasetTimeSeries } from '@js/api/geonode/v2/index'; import { updateNode } from '@mapstore/framework/actions/layers'; import { layersSelector } from '@mapstore/framework/selectors/layers'; -const RESOURCE_MANAGEMENT_PROPERTIES_KEYS = Object.keys({...RESOURCE_MANAGEMENT_PROPERTIES, ...GROUP_OWNER_PROPERTIES}); +const RESOURCE_MANAGEMENT_PROPERTIES_KEYS = Object.keys({...RESOURCE_MANAGEMENT_PROPERTIES}); function parseMapBody(body) { const geoNodeMap = toGeoNodeMapConfig(body.data); @@ -174,7 +172,7 @@ export const gnSaveContent = (action$, store) => const { compactPermissions } = getPermissionsPayload(state); const body = { 'title': action.metadata.name, - ...(RESOURCE_MANAGEMENT_PROPERTIES_KEYS.reduce((acc, key) => { + ...([...RESOURCE_MANAGEMENT_PROPERTIES_KEYS, 'group'].reduce((acc, key) => { if (currentResource?.[key] !== undefined) { const value = typeof currentResource[key] === 'boolean' ? !!currentResource[key] : currentResource[key]; acc[key] = value; @@ -281,60 +279,47 @@ export const gnSaveDirectContent = (action$, store) => const mapInfo = mapInfoSelector(state); const resourceId = mapInfo?.id || getResourceId(state); const { geoLimits } = getPermissionsPayload(state); - const currentResource = getResourceData(state); - - const newOwner = get(currentResource, 'owner.pk', null); - const currentOwner = get(state, 'gnresource.initialResource.owner.pk', null); - const userId = userSelector(state)?.pk; - let transferOwnership; - if (newOwner && userId && !isEqual(currentOwner, newOwner)) { - transferOwnership = { currentOwner, newOwner, resources: [Number(resourceId)] }; - } // resource information should be saved in a synchronous manner // i.e transfer ownership (if any) followed by resource data and finally permissions - return Observable.concat( - transferOwnership ? Observable.defer(() => transferResource(userId, transferOwnership)) : Promise.resolve(), - Observable.defer(() => axios.all([ - getResourceByPk(resourceId), - ...(geoLimits - ? geoLimits.map((limits) => - limits.features.length === 0 - ? deleteGeoLimits(resourceId, limits.id, limits.type) - .catch(() => ({ error: true, resourceId, limits })) - : updateGeoLimits(resourceId, limits.id, limits.type, { features: limits.features }) - .catch(() => ({ error: true, resourceId, limits })) - ) - : []) - ]))).toArray() - .switchMap(([, responses]) => { - const [resource, ...geoLimitsResponses] = responses; - const geoLimitsErrors = geoLimitsResponses.filter(({ error }) => error); - const name = getResourceName(state); - const description = getResourceDescription(state); - const metadata = { - name: (name) ? name : resource?.title, - description: (description) ? description : resource?.abstract, - extension: resource?.extension, - href: resource?.href - }; - return Observable.concat( - Observable.of( - saveContent( - resourceId, - metadata, - false, - geoLimitsErrors.length > 0 - ? { - title: 'gnviewer.warningGeoLimitsSaveTitle', - message: 'gnviewer.warningGeoLimitsSaveMessage' - } - : true /* showNotification */), - resetGeoLimits() - ) + return Observable.defer(() => axios.all([ + getResourceByPk(resourceId), + ...(geoLimits + ? geoLimits.map((limits) => + limits.features.length === 0 + ? deleteGeoLimits(resourceId, limits.id, limits.type) + .catch(() => ({ error: true, resourceId, limits })) + : updateGeoLimits(resourceId, limits.id, limits.type, { features: limits.features }) + .catch(() => ({ error: true, resourceId, limits })) + ) + : []) + ])).switchMap(([resource, ...geoLimitsResponses]) => { + const geoLimitsErrors = geoLimitsResponses.filter(({ error }) => error); + const name = getResourceName(state); + const description = getResourceDescription(state); + const metadata = { + name: (name) ? name : resource?.title, + description: (description) ? description : resource?.abstract, + extension: resource?.extension, + href: resource?.href + }; + return Observable.concat( + Observable.of( + saveContent( + resourceId, + metadata, + false, + geoLimitsErrors.length > 0 + ? { + title: 'gnviewer.warningGeoLimitsSaveTitle', + message: 'gnviewer.warningGeoLimitsSaveMessage' + } + : true /* showNotification */), + resetGeoLimits() + ) - ); - }) + ); + }) .catch((error) => { return Observable.of( saveError(error.data || error.message), diff --git a/geonode_mapstore_client/client/js/plugins/ResourceDetails/components/DetailsSettings.jsx b/geonode_mapstore_client/client/js/plugins/ResourceDetails/components/DetailsSettings.jsx index 0d401d77a1..541b592905 100644 --- a/geonode_mapstore_client/client/js/plugins/ResourceDetails/components/DetailsSettings.jsx +++ b/geonode_mapstore_client/client/js/plugins/ResourceDetails/components/DetailsSettings.jsx @@ -5,12 +5,13 @@ import { Checkbox, FormGroup, ControlLabel } from 'react-bootstrap'; import Message from '@mapstore/framework/components/I18N/Message'; import tooltip from '@mapstore/framework/components/misc/enhancers/tooltip'; -import { GROUP_OWNER_PROPERTIES, RESOURCE_MANAGEMENT_PROPERTIES } from '@js/utils/ResourceUtils'; +import { RESOURCE_MANAGEMENT_PROPERTIES } from '@js/utils/ResourceUtils'; import TimeSeriesSettings from '@js/plugins/ResourceDetails/components/DetailsTimeSeries'; import FlexBox from '@mapstore/framework/components/layout/FlexBox'; import Text from '@mapstore/framework/components/layout/Text'; import SelectInfiniteScroll from '@mapstore/framework/plugins/ResourcesCatalog/components/SelectInfiniteScroll'; import { getCompactPermissions } from '@js/selectors/resource'; +import { getGroups } from '@js/api/geonode/v2'; const MessageTooltip = tooltip(forwardRef(({children, msgId, ...props}, ref) => { return ( @@ -22,34 +23,36 @@ const MessageTooltip = tooltip(forwardRef(({children, msgId, ...props}, ref) => ); })); -function DetailsSettings({ resource, user, compactPermissions, onChange }) { +function DetailsSettings({ resource, onChange }) { const perms = resource?.perms || []; return ( - {Object.keys(GROUP_OWNER_PROPERTIES).map((key) => { - const { labelId, disabled, placeholderId, labelKey, loadOptions, clearable } = - GROUP_OWNER_PROPERTIES[key]; - return ( - - - - { - onChange({ - [key]: selected?.value ?? null - }); - }} - loadOptions={(...args) => loadOptions(...args, compactPermissions)} - /> - - - ); - })} + + + + onChange({ group: selected?.value ?? null})} + loadOptions={({ q, ...params }) => getGroups({q, ...params}) + .then((response) => { + return { + ...response, + results: (response?.groups ?? []) + .map((item) => ({...item, selectOption: { + value: item.group, + label: item.group.name + }})) + }; + }) + } + /> + + + diff --git a/geonode_mapstore_client/client/js/selectors/resource.js b/geonode_mapstore_client/client/js/selectors/resource.js index 91c14cb817..ebcf745d66 100644 --- a/geonode_mapstore_client/client/js/selectors/resource.js +++ b/geonode_mapstore_client/client/js/selectors/resource.js @@ -12,7 +12,7 @@ import { compareMapChanges } from '@mapstore/framework/utils/MapUtils'; import { currentStorySelector } from '@mapstore/framework/selectors/geostory'; import { originalDataSelector } from '@mapstore/framework/selectors/dashboard'; import { widgetsConfig } from '@mapstore/framework/selectors/widgets'; -import { ResourceTypes, RESOURCE_MANAGEMENT_PROPERTIES, GROUP_OWNER_PROPERTIES } from '@js/utils/ResourceUtils'; +import { ResourceTypes, RESOURCE_MANAGEMENT_PROPERTIES } from '@js/utils/ResourceUtils'; import { getCurrentResourceDeleteLoading, getCurrentResourceCopyLoading @@ -28,7 +28,7 @@ import omitBy from 'lodash/omitBy'; import { generateContextResource } from '@mapstore/framework/selectors/contextcreator'; import { layerSettingSelector, getSelectedLayer as getSelectedNode } from '@mapstore/framework/selectors/layers'; -const RESOURCE_MANAGEMENT_PROPERTIES_KEYS = Object.keys({...RESOURCE_MANAGEMENT_PROPERTIES, ...GROUP_OWNER_PROPERTIES}); +const RESOURCE_MANAGEMENT_PROPERTIES_KEYS = Object.keys({...RESOURCE_MANAGEMENT_PROPERTIES}); /** * @module selectors/resource @@ -327,7 +327,7 @@ export const getResourceDirtyState = (state) => { return null; } const resourceType = state?.gnresource?.type; - let metadataKeys = ['title', 'abstract', 'data', 'extent', ...RESOURCE_MANAGEMENT_PROPERTIES_KEYS]; + let metadataKeys = ['title', 'abstract', 'data', 'extent', 'group', ...RESOURCE_MANAGEMENT_PROPERTIES_KEYS]; if (resourceType === ResourceTypes.DATASET) { metadataKeys = metadataKeys.concat('timeseries'); } diff --git a/geonode_mapstore_client/client/js/utils/ResourceUtils.js b/geonode_mapstore_client/client/js/utils/ResourceUtils.js index fcf858f488..20f20b56d3 100644 --- a/geonode_mapstore_client/client/js/utils/ResourceUtils.js +++ b/geonode_mapstore_client/client/js/utils/ResourceUtils.js @@ -81,55 +81,6 @@ export const RESOURCE_MANAGEMENT_PROPERTIES = { } }; -export const GROUP_OWNER_PROPERTIES = { - 'owner': { - labelId: 'gnviewer.owner', - placeholderId: 'gnviewer.ownerPlaceholder', - labelKey: 'username', - clearable: false, - disabled: ({user}) => !user.is_superuser, - loadOptions: ({ q, ...params }, compactPermissions) => { - const { users = [] } = compactPermissions; - const exclude = users - .filter(({ permissions }) => permissions !== "owner") - .map(({ id }) => id); - return getUsers({ - ...params, - "filter{-pk.in}": [...exclude, -1], // self assignment is not allowed along with anonymous user - "filter{is_superuser}": false - }) - .then((response) => { - return { - ...response, - results: (response?.users ?? []) - .map((item) => ({...item, selectOption: { - value: item, - label: item.username - }})) - }; - }); - } - }, - 'group': { - labelId: 'gnviewer.group', - placeholderId: 'gnviewer.groupPlaceholder', - clearable: true, - disabled: ({perms = []}) => !perms.includes('change_resourcebase'), - loadOptions: ({ q, ...params }) => getGroups({q, ...params}) - .then((response) => { - return { - ...response, - results: (response?.groups ?? []) - .map((item) => ({...item, selectOption: { - value: item.group, - label: item.group.name - }})) - }; - }), - labelKey: 'name' - } -}; - export const TIME_SERIES_PROPERTIES = ['attribute', 'end_attribute', 'presentation', 'precision_value', 'precision_step']; export const TIME_ATTRIBUTE_TYPES = ['xsd:date', 'xsd:dateTime', 'xsd:date-time', 'xsd:time']; From 680e9cdfae12b35e8c3ca4c1d2de1060dce9a612 Mon Sep 17 00:00:00 2001 From: Suren Date: Tue, 17 Jun 2025 12:25:49 +0530 Subject: [PATCH 3/5] code refactor --- geonode_mapstore_client/client/js/epics/gnsave.js | 4 ++-- .../ResourceDetails/containers/DetailsPanel.jsx | 4 +--- .../ResourceDetails/containers/Permissions/index.jsx | 11 ++++------- .../client/js/selectors/resource.js | 6 +----- .../static/mapstore/gn-translations/data.de-DE.json | 1 - .../static/mapstore/gn-translations/data.en-US.json | 1 - .../static/mapstore/gn-translations/data.es-ES.json | 1 - .../static/mapstore/gn-translations/data.fi-FI.json | 1 - .../static/mapstore/gn-translations/data.fr-FR.json | 1 - .../static/mapstore/gn-translations/data.hr-HR.json | 1 - .../static/mapstore/gn-translations/data.it-IT.json | 1 - .../static/mapstore/gn-translations/data.nl-NL.json | 1 - .../static/mapstore/gn-translations/data.pt-PT.json | 1 - .../static/mapstore/gn-translations/data.sk-SK.json | 1 - .../static/mapstore/gn-translations/data.sv-SE.json | 1 - .../static/mapstore/gn-translations/data.vi-VN.json | 1 - .../static/mapstore/gn-translations/data.zh-ZH.json | 1 - 17 files changed, 8 insertions(+), 30 deletions(-) diff --git a/geonode_mapstore_client/client/js/epics/gnsave.js b/geonode_mapstore_client/client/js/epics/gnsave.js index eea5cefd07..30e9b7d49b 100644 --- a/geonode_mapstore_client/client/js/epics/gnsave.js +++ b/geonode_mapstore_client/client/js/epics/gnsave.js @@ -91,7 +91,7 @@ import { layersSelector, getSelectedLayer as getSelectedNode } from '@mapstore/f import { styleServiceSelector, getUpdatedLayer, selectedStyleSelector } from '@mapstore/framework/selectors/styleeditor'; import LayersAPI from '@mapstore/framework/api/geoserver/Layers'; -const RESOURCE_MANAGEMENT_PROPERTIES_KEYS = Object.keys({...RESOURCE_MANAGEMENT_PROPERTIES}); +const RESOURCE_MANAGEMENT_PROPERTIES_KEYS = Object.keys(RESOURCE_MANAGEMENT_PROPERTIES); function parseMapBody(body) { const geoNodeMap = toGeoNodeMapConfig(body.data); @@ -314,7 +314,7 @@ export const gnSaveDirectContent = (action$, store) => const { geoLimits } = getPermissionsPayload(state); // resource information should be saved in a synchronous manner - // i.e transfer ownership (if any) followed by resource data and finally permissions + // i.e update resource data followed by permissions return Observable.defer(() => axios.all([ getResourceByPk(resourceId), ...(geoLimits diff --git a/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/DetailsPanel.jsx b/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/DetailsPanel.jsx index e1948c04e5..c3cfbdfb07 100644 --- a/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/DetailsPanel.jsx +++ b/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/DetailsPanel.jsx @@ -24,7 +24,6 @@ import { } from '@js/selectors/resource'; import Message from '@mapstore/framework/components/I18N/Message'; import { mapSelector } from '@mapstore/framework/selectors/map'; -import { userSelector } from '@mapstore/framework/selectors/security'; import DetailsInfo from '@mapstore/framework/plugins/ResourcesCatalog/components/DetailsInfo'; import { replaceResourcePaths } from '@mapstore/framework/utils/ResourcesUtils'; import Text from '@mapstore/framework/components/layout/Text'; @@ -161,8 +160,7 @@ DetailsPanel.contextTypes = { const ConnectedDetailsPanel = connect( createStructuredSelector({ monitoredState: getMonitoredStateSelector, - location: getRouterLocation, - user: userSelector + location: getRouterLocation }) )(DetailsPanel); diff --git a/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/Permissions/index.jsx b/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/Permissions/index.jsx index 2bd374cfae..a0c6e48720 100644 --- a/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/Permissions/index.jsx +++ b/geonode_mapstore_client/client/js/plugins/ResourceDetails/containers/Permissions/index.jsx @@ -21,8 +21,7 @@ import { import { updateResourceCompactPermissions } from "@js/actions/gnresource"; import { getCompactPermissions, - getViewedResourceType, - resourceOwnerSelector + getViewedResourceType } from "@js/selectors/resource"; import { getCurrentResourcePermissionsLoading } from "@js/selectors/resourceservice"; import { @@ -146,14 +145,12 @@ export default connect( [ getCompactPermissions, getCurrentResourcePermissionsLoading, - getViewedResourceType, - resourceOwnerSelector + getViewedResourceType ], - (compactPermissions, permissionsLoading, type, owner) => ({ + (compactPermissions, permissionsLoading, type) => ({ compactPermissions, permissionsLoading, - resourceType: type, - owner + resourceType: type }) ), { diff --git a/geonode_mapstore_client/client/js/selectors/resource.js b/geonode_mapstore_client/client/js/selectors/resource.js index 0861dc634e..56cb720f21 100644 --- a/geonode_mapstore_client/client/js/selectors/resource.js +++ b/geonode_mapstore_client/client/js/selectors/resource.js @@ -30,7 +30,7 @@ import { generateContextResource } from '@mapstore/framework/selectors/contextcr import { layerSettingSelector, getSelectedLayer as getSelectedNode } from '@mapstore/framework/selectors/layers'; import { saveLayer } from '@mapstore/framework/utils/LayersUtils'; -const RESOURCE_MANAGEMENT_PROPERTIES_KEYS = Object.keys({...RESOURCE_MANAGEMENT_PROPERTIES}); +const RESOURCE_MANAGEMENT_PROPERTIES_KEYS = Object.keys(RESOURCE_MANAGEMENT_PROPERTIES); /** * @module selectors/resource @@ -66,10 +66,6 @@ export const isThumbnailChanged = (state) => { return state?.gnresource?.data?.thumbnailChanged || false; }; -export const resourceOwnerSelector = (state) => { - return state?.gnresource?.data?.owner || {}; -}; - export const getViewedResourceType = (state) => { const viewedResourceType = state?.gnresource?.type || false; return viewedResourceType; diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.de-DE.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.de-DE.json index 139854b74c..4a82ebb70a 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.de-DE.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.de-DE.json @@ -327,7 +327,6 @@ "iso": "ISO -Metadaten", "dublinCore": "Dublin Core Metadaten", "owner": "Eigentümer", - "ownerPlaceholder": "Eigentümer auswählen", "creation": "Erstellungsdatum", "publication": "Veröffentlichung", "revision": "Überarbeitung", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.en-US.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.en-US.json index 3ac0b8f1cb..8ce157bc23 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.en-US.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.en-US.json @@ -327,7 +327,6 @@ "iso": "ISO Metadata", "dublinCore": "Dublin Core Metadata", "owner": "Owner", - "ownerPlaceholder": "Select owner", "creation": "Creation", "publication": "Publication", "revision": "Revision", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.es-ES.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.es-ES.json index e57707eb63..696e7d7750 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.es-ES.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.es-ES.json @@ -326,7 +326,6 @@ "iso": "Metadatos iso", "dublinCore": "Metadatos de Dublin Core", "owner": "Propietario", - "ownerPlaceholder": "Seleccionar propietario", "creation": "Creación", "publication": "Publicación", "revision": "Revisión", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.fi-FI.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.fi-FI.json index c6bf559a18..3e54cbef53 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.fi-FI.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.fi-FI.json @@ -301,7 +301,6 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", - "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.fr-FR.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.fr-FR.json index 06293a23df..593e36f544 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.fr-FR.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.fr-FR.json @@ -327,7 +327,6 @@ "iso": "Métadonnées ISO", "dublinCore": "Métadonnées de Dublin Core", "owner": "Propriétaire", - "ownerPlaceholder": "Sélectionner le propriétaire", "creation": "Création", "publication": "Publication", "revision": "Révision", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.hr-HR.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.hr-HR.json index db84e7e3c1..d9ee519401 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.hr-HR.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.hr-HR.json @@ -301,7 +301,6 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", - "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.it-IT.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.it-IT.json index b7d468602a..f650fa0ba0 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.it-IT.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.it-IT.json @@ -329,7 +329,6 @@ "iso": "Metadati ISO", "dublinCore": "Metadati di Dublin Core", "owner": "Proprietario", - "ownerPlaceholder": "Seleziona proprietario", "date": "Data", "creation": "Creazione", "publication": "Pubblicazione", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.nl-NL.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.nl-NL.json index dc24d6c5b8..656a6cc0cd 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.nl-NL.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.nl-NL.json @@ -301,7 +301,6 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", - "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.pt-PT.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.pt-PT.json index 43c68e5765..053ab40c22 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.pt-PT.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.pt-PT.json @@ -301,7 +301,6 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", - "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.sk-SK.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.sk-SK.json index 4d80795160..4c50af2d1a 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.sk-SK.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.sk-SK.json @@ -301,7 +301,6 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", - "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.sv-SE.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.sv-SE.json index bd95ac0946..f22267c045 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.sv-SE.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.sv-SE.json @@ -302,7 +302,6 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", - "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.vi-VN.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.vi-VN.json index 5b3758634c..cbc38237b4 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.vi-VN.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.vi-VN.json @@ -301,7 +301,6 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", - "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", diff --git a/geonode_mapstore_client/static/mapstore/gn-translations/data.zh-ZH.json b/geonode_mapstore_client/static/mapstore/gn-translations/data.zh-ZH.json index bdbd0c93f2..0eb0523820 100644 --- a/geonode_mapstore_client/static/mapstore/gn-translations/data.zh-ZH.json +++ b/geonode_mapstore_client/static/mapstore/gn-translations/data.zh-ZH.json @@ -301,7 +301,6 @@ "filterNoMatchUploadDocument": "Filter does not match an upload", "uploadDocument": "Upload a document", "owner": "Owner", - "ownerPlaceholder": "Select owner", "created": "Created", "published": "Published", "lastModified": "Last modified", From ef5603a3f134d597dce990f5eb49dd99bec56c77 Mon Sep 17 00:00:00 2001 From: Suren Date: Tue, 17 Jun 2025 12:29:21 +0530 Subject: [PATCH 4/5] lint fix --- geonode_mapstore_client/client/js/utils/ResourceUtils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/geonode_mapstore_client/client/js/utils/ResourceUtils.js b/geonode_mapstore_client/client/js/utils/ResourceUtils.js index d538b040ec..afaf89462a 100644 --- a/geonode_mapstore_client/client/js/utils/ResourceUtils.js +++ b/geonode_mapstore_client/client/js/utils/ResourceUtils.js @@ -14,7 +14,6 @@ import { isImageServerUrl } from '@mapstore/framework/utils/ArcGISUtils'; import { getConfigProp, convertFromLegacy, normalizeConfig } from '@mapstore/framework/utils/ConfigUtils'; import { excludeGoogleBackground, extractTileMatrixFromSources, ServerTypes } from '@mapstore/framework/utils/LayersUtils'; -import { getGroups, getUsers } from '@js/api/geonode/v2'; import { getGeoNodeLocalConfig, parseDevHostname } from '@js/utils/APIUtils'; import { ProcessTypes, ProcessStatus } from '@js/utils/ResourceServiceUtils'; import { determineResourceType } from '@js/utils/FileUtils'; From 179f6661ee2b0c8cb2a9bccdb69241558c51499c Mon Sep 17 00:00:00 2001 From: Suren Date: Tue, 17 Jun 2025 12:33:12 +0530 Subject: [PATCH 5/5] update style --- .../js/plugins/ResourceDetails/components/DetailsSettings.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geonode_mapstore_client/client/js/plugins/ResourceDetails/components/DetailsSettings.jsx b/geonode_mapstore_client/client/js/plugins/ResourceDetails/components/DetailsSettings.jsx index b26e4bd2c5..ba227b3d97 100644 --- a/geonode_mapstore_client/client/js/plugins/ResourceDetails/components/DetailsSettings.jsx +++ b/geonode_mapstore_client/client/js/plugins/ResourceDetails/components/DetailsSettings.jsx @@ -23,7 +23,7 @@ const MessageTooltip = tooltip(forwardRef(({children, msgId, ...props}, ref) => function DetailsSettings({ resource, onChange }) { return ( - +