Skip to content

Commit

Permalink
#1769: Implement catalog pages and page specific configurations (#1770)
Browse files Browse the repository at this point in the history
* #1769: Implement catalog pages and page specific configurations

* updated unit test

* update reference

* updated labels

* update logo url and label size

* update path and plugins

* update redirection for all
  • Loading branch information
dsuren1 authored May 28, 2024
1 parent 7956efc commit 4c369c0
Show file tree
Hide file tree
Showing 33 changed files with 720 additions and 102 deletions.
13 changes: 13 additions & 0 deletions geonode_mapstore_client/client/js/actions/gnresource.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const SET_RESOURCE_EXTENT = 'GEONODE_SET_RESOURCE_EXTENT';
export const SET_RESOURCE_PATH_PARAMETERS = 'GEONODE:SET_RESOURCE_PATH_PARAMETERS';
export const SET_MAP_VIEWER_LINKED_RESOURCE = 'GEONODE:SET_MAP_VIEWER_LINKED_RESOURCE';
export const MANAGE_LINKED_RESOURCE = 'GEONODE:MANAGE_LINKED_RESOURCE';
export const SET_SELECTED_LAYER_DATASET = 'GEONODE:SET_SELECTED_LAYER_DATASET';

/**
* Actions for GeoNode resource
Expand Down Expand Up @@ -349,3 +350,15 @@ export function setMapViewerLinkedResource(resource) {
resource
};
}

/**
* Set selected layer type is from dataset
* @param {Object} layer selected
*/

export function setSelectedLayerType(layer) {
return {
type: SET_SELECTED_LAYER_DATASET,
layer
};
}
6 changes: 3 additions & 3 deletions geonode_mapstore_client/client/js/epics/gnresource.js
Original file line number Diff line number Diff line change
Expand Up @@ -639,9 +639,9 @@ export const gnManageLinkedResource = (action$, store) =>
message: `gnviewer.linkedResource.message.success.${processType}`}
))
)).catch(() => Observable.of(errorNotification({
title: "gnviewer.linkedResource.title",
message: `gnviewer.linkedResource.message.failure.${processType}`
})))
title: "gnviewer.linkedResource.title",
message: `gnviewer.linkedResource.message.failure.${processType}`
})))
.let(wrapStartStop(
setControlProperty(processType, 'loading', true),
setControlProperty(processType, 'loading', false)
Expand Down
4 changes: 3 additions & 1 deletion geonode_mapstore_client/client/js/epics/gnsearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ const requestResourcesObservable = ({
}, store) => {
const state = store.getState();
const customFilters = getCustomMenuFilters(state);
const requestParams = cleanParams({ ...params, ...state?.gnsearch?.config?.defaultQuery });
let { resource, f, ...defaultQuery } = state?.gnsearch?.config?.defaultQuery ?? {};
f = castArray(params.f ?? []).concat([...castArray(resource ?? []), ...castArray(f ?? [])]);
const requestParams = cleanParams({ ...params, ...defaultQuery, ...(!isEmpty(f) && {f}) });
return Observable
.defer(() => getResources({
...requestParams,
Expand Down
8 changes: 5 additions & 3 deletions geonode_mapstore_client/client/js/epics/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { getDatasetByName, getDatasetsByName } from '@js/api/geonode/v2';
import { MAP_CONFIG_LOADED } from '@mapstore/framework/actions/config';
import { setPermission } from '@mapstore/framework/actions/featuregrid';
import { SELECT_NODE, updateNode, ADD_LAYER } from '@mapstore/framework/actions/layers';
import { setSelectedDatasetPermissions } from '@js/actions/gnresource';
import { setSelectedDatasetPermissions, setSelectedLayerType } from '@js/actions/gnresource';
import { updateMapLayoutEpic as msUpdateMapLayoutEpic } from '@mapstore/framework/epics/maplayout';

// We need to include missing epics. The plugins that normally include this epic is not used.
Expand All @@ -44,12 +44,14 @@ export const gnCheckSelectedDatasetPermissions = (action$, { getState } = {}) =>
? Rx.Observable.of(
setPermission({canEdit}),
setEditPermissionStyleEditor(canEditStyles),
setSelectedDatasetPermissions(permissions)
setSelectedDatasetPermissions(permissions),
setSelectedLayerType(layer)
)
: Rx.Observable.of(
setPermission({canEdit: false}),
setEditPermissionStyleEditor(false),
setSelectedDatasetPermissions([])
setSelectedDatasetPermissions([]),
setSelectedLayerType(null)
);
});

Expand Down
2 changes: 1 addition & 1 deletion geonode_mapstore_client/client/js/epics/layersettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const gnUpdateLayerSettingsMapLayout = (action$, store) =>
},
boundingSideBarReact: {
...boundingSidebarRect,
...layout.boundingSidebarRect
...layout?.boundingSidebarRect
}
});
return { ...action, source: LayoutSections.PANEL }; // add an argument to avoid infinite loop.
Expand Down
6 changes: 3 additions & 3 deletions geonode_mapstore_client/client/js/plugins/DeleteResource.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import Loader from '@mapstore/framework/components/misc/Loader';
import controls from '@mapstore/framework/reducers/controls';
import { isLoggedIn } from '@mapstore/framework/selectors/security';
import { hashLocationToHref } from '@js/utils/SearchUtils';
import { ResourceTypes } from '@js/utils/ResourceUtils';
import { ResourceTypes, onDeleteRedirectTo } from '@js/utils/ResourceUtils';

const simulateAClick = (href) => {
const a = document.createElement('a');
Expand Down Expand Up @@ -70,7 +70,7 @@ function DeleteResourcePlugin({
resources = [],
onClose = () => {},
onDelete = () => {},
redirectTo = '/',
redirectTo,
loading,
location,
selectedResource
Expand Down Expand Up @@ -101,7 +101,7 @@ function DeleteResourcePlugin({
excludeQueryKeys: ['d']
}));
}
onDelete(resources, redirectTo);
onDelete(resources, onDeleteRedirectTo(resources));
}
}]
}
Expand Down
95 changes: 78 additions & 17 deletions geonode_mapstore_client/client/js/plugins/ResourcesGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,40 @@ function PaginationCustom({
);
}

const removeMenuHighlight = () => {
// Remove previous higlighted menu
const menuHiglighted = document.querySelector('#gn-topbar .highlight-menu');
menuHiglighted?.classList.remove('highlight-menu');
};
const getCatalogPage = (pathname) => {
const {params: {page} = {}} = matchPath(pathname, { path: "/:page", exact: true }) ?? {};
return page;
};
const withPageConfig = (Component) => {
return (props) => {
useEffect(() => {
// highlight topbar menu item based on catalog page
const page = getCatalogPage(props.location.pathname);

if (page) {
removeMenuHighlight();

const topbarMenu = document.querySelector(`#gn-topbar #${page}`);
topbarMenu?.classList.add('highlight-menu');
} else {
removeMenuHighlight();
}
}, [props.location.pathname]);

const mergePropsWithPageConfigs = () => {
const pageName = getCatalogPage(props.location.pathname, props);
return {...props, ...props?.[`${pageName}Page`]};
};

return <Component {...mergePropsWithPageConfigs()} />;
};
};

/**
* @module ResourcesGrid
*/
Expand Down Expand Up @@ -227,7 +261,7 @@ function ResourcesGrid({
menuItems = [
{
labelId: 'gnhome.addResource',
disableIf: "{(state('settings') && state('settings').isMobile) || !(state('user') && state('user').perms && state('user').perms.includes('add_resource')) ? true : false}",
disableIf: "{(state('settings') && state('settings').isMobile) || !(state('user') && state('user').perms && state('user').perms.includes('add_resource'))}",
type: 'dropdown',
variant: 'primary',
responsive: true,
Expand Down Expand Up @@ -432,7 +466,7 @@ function ResourcesGrid({
pagination,
disableDetailPanel,
disableFilters,
filterPagePath = getCataloguePath('/catalogue/#/search/filter'),
filterPagePath = '/catalogue/#/search/filter',
resourceCardActionsOrder = [
ProcessTypes.DELETE_RESOURCE,
ProcessTypes.COPY_RESOURCE,
Expand All @@ -445,7 +479,8 @@ function ResourcesGrid({
onGetFacets,
facets,
filters,
setFilters
setFilters,
...props
}, context) {

const [_cardLayoutStyleState, setCardLayoutStyle] = useLocalStorage('layoutCardsStyle', defaultCardLayoutStyle);
Expand Down Expand Up @@ -501,7 +536,7 @@ function ResourcesGrid({

const handleShowFilterForm = (show) => {
if (show && disableFilters) {
simulateAClick(filterPagePath);
simulateAClick(getCataloguePath(filterPagePath));
} else {
if (!isEmpty(resource)) {
const href = closeDetailPanelHref();
Expand All @@ -511,12 +546,38 @@ function ResourcesGrid({
}
};

const isCatalogPage = (pathname) => {
const isConfigPresent = !!props?.[`${pathname.replace('/', '')}Page`];

// to be a catalog page it should have configuration
return getCatalogPage(pathname) && isConfigPresent;
};

const getMatchPath = () => {
const pathname = location.pathname;
const matchedPath = [
'/search',
'/search/filter',
'/detail/:pk',
'/detail/:resourceType/:pk',
'/:page'
].find((path) => matchPath(pathname, { path, exact: true }));
return matchedPath;
};

const getUpdatedPathName = (pathname) => {
if (isEmpty(pathname)) {
return isCatalogPage(location.pathname) ? location.pathname : '/';
}
return pathname;
};

function handleUpdate(newParams, pathname) {
const { query } = url.parse(location.search, true);
onSearch({
...omit(query, ['page']),
...newParams
}, pathname);
}, getUpdatedPathName(pathname));
}

function handleClear() {
Expand All @@ -539,7 +600,13 @@ function ResourcesGrid({
}, [cardLayoutStyle]);

useEffect(() => {
if (init) {
let pathname = location.pathname;
const initialize = (pathname === '/'
|| !isEmpty(getMatchPath())
|| isCatalogPage(pathname)) && init;

if (initialize) {
pathname = getUpdatedPathName();
onInit({
defaultQuery,
pageSize,
Expand All @@ -556,9 +623,9 @@ function ResourcesGrid({
onSearch({
...query,
...(page && { page })
}, undefined, true);
}, pathname, true);
}
}, [init, isPaginated]);
}, [init, isPaginated, location.pathname]);

const [top, setTop] = useState(0);
const [bottom, setBottom] = useState(0);
Expand Down Expand Up @@ -596,19 +663,13 @@ function ResourcesGrid({
useEffect(() => {
if (!panel) {
const pathname = location.pathname;
const matchedPath = [
'/search',
'/search/filter',
'/detail/:pk',
'/detail/:resourceType/:pk'
].find((path) => matchPath(pathname, { path, exact: true }));
const matchedPath = getMatchPath();
if (matchedPath) {
const options = matchPath(pathname, { path: matchedPath, exact: true });
onReplaceLocation('' + (location.search || ''));
!isCatalogPage(location.pathname) && onReplaceLocation('' + (location.search || ''));
switch (options.path) {
case '/search':
case '/detail/:pk': {
//
break;
}
case '/search/filter': {
Expand Down Expand Up @@ -824,7 +885,7 @@ const ResourcesGridPlugin = connect(
onGetFacets: getFacetItems,
setFilters: setFiltersAction
}
)(withResizeDetector(ResourcesGrid));
)(withResizeDetector(withPageConfig(ResourcesGrid)));

export default createPlugin('ResourcesGrid', {
component: ResourcesGridPlugin,
Expand Down
9 changes: 8 additions & 1 deletion geonode_mapstore_client/client/js/reducers/gnresource.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import isEqual from 'lodash/isEqual';
import isEmpty from 'lodash/isEmpty';
import isNil from 'lodash/isNil';

import {
RESOURCE_LOADING,
Expand All @@ -32,7 +33,8 @@ import {
ENABLE_MAP_THUMBNAIL_VIEWER,
SET_RESOURCE_EXTENT,
SET_RESOURCE_PATH_PARAMETERS,
SET_MAP_VIEWER_LINKED_RESOURCE
SET_MAP_VIEWER_LINKED_RESOURCE,
SET_SELECTED_LAYER_DATASET
} from '@js/actions/gnresource';
import {
cleanCompactPermissions,
Expand Down Expand Up @@ -238,6 +240,11 @@ function gnresource(state = defaultState, action) {
...state,
viewerLinkedResource: action.resource
};
case SET_SELECTED_LAYER_DATASET:
return {
...state,
selectedLayerIsDataset: !isNil(action.layer?.extendedParams?.pk)
};
default:
return state;
}
Expand Down
9 changes: 7 additions & 2 deletions geonode_mapstore_client/client/js/routes/Catalogue.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,15 @@ function getPluginsConfiguration(name, pluginsConfig) {

const withRedirect = (Component) => {
return (props) => {
const { pathname, search } = props.location ?? {};
const catalogHomeRedirectsTo = getGeoNodeLocalConfig('geoNodeSettings.catalogHomeRedirectsTo');
const defaultCatalogPage = getGeoNodeLocalConfig('geoNodeSettings.defaultCatalogPage');
if (!isEmpty(catalogHomeRedirectsTo)) {
const search = props.location?.search ?? "";
window.location.href = `${catalogHomeRedirectsTo}#/${search ? search : ""}`;
window.location.href = `${catalogHomeRedirectsTo}#/${!isEmpty(defaultCatalogPage) ? defaultCatalogPage : search ? search : ""}`;
return null;
}
if (!isEmpty(defaultCatalogPage) && pathname === '/' && isEmpty(search)) {
window.location.href = `#/${defaultCatalogPage ? defaultCatalogPage : ""}`;
return null;
}
return <Component {...props}/>;
Expand Down
3 changes: 2 additions & 1 deletion geonode_mapstore_client/client/js/utils/AppRoutesUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ export const CATALOGUE_ROUTES = [
'/search/',
'/search/filter',
'/detail/:pk',
'/detail/:ctype/:pk'
'/detail/:ctype/:pk',
'/:page'
],
component: appRouteComponentTypes.CATALOGUE
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import {
resourceHasPermission,
canCopyResource,
isDocumentExternalSource,
getCataloguePath,
isDatasetLayer
getCataloguePath
} from '@js/utils/ResourceUtils';
import get from 'lodash/get';

Expand Down Expand Up @@ -47,6 +46,5 @@ export const getPluginsContext = () => ({
getUserResourceName,
getUserResourceNames,
isDocumentExternalSource,
getCataloguePath,
isDatasetLayer
getCataloguePath
});
Loading

0 comments on commit 4c369c0

Please sign in to comment.