Skip to content

Commit ea9ea1f

Browse files
anup39allyoucanmap
andauthored
Fix: #2227 Added Documents Catalog Plugin. (#2263)
--------- Co-authored-by: allyoucanmap <[email protected]>
1 parent ae29d1a commit ea9ea1f

34 files changed

+2483
-34
lines changed

geonode_mapstore_client/client/js/api/geonode/v2/index.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,46 @@ export const getDatasets = ({
157157
});
158158
};
159159

160+
export const getDocuments = ({
161+
q,
162+
pageSize = 10,
163+
page = 1,
164+
sort,
165+
f,
166+
customFilters = [],
167+
config,
168+
...params
169+
}) => {
170+
const _params = {
171+
...getQueryParams({...params, f}, customFilters),
172+
...(q && {
173+
search: q,
174+
search_fields: ['title', 'abstract']
175+
}),
176+
...(sort && { sort: isArray(sort) ? sort : [ sort ]}),
177+
page,
178+
page_size: pageSize,
179+
'filter{resource_type.in}': 'document'
180+
};
181+
return axios
182+
.get(
183+
getEndpointUrl(DOCUMENTS), {
184+
params: _params,
185+
...config,
186+
...paramsSerializer()
187+
})
188+
.then(({ data }) => {
189+
return {
190+
total: data.total,
191+
isNextPageAvailable: !!data.links.next,
192+
resources: (data.documents || [])
193+
.map((resource) => {
194+
return resource;
195+
})
196+
};
197+
});
198+
};
199+
160200
export const getDocumentsByDocType = (docType = 'image', {
161201
q,
162202
pageSize = 20,

geonode_mapstore_client/client/js/epics/gnresource.js

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -613,12 +613,33 @@ export const closeInfoPanelOnMapClick = (action$, store) => action$.ofType(CLICK
613613
.switchMap(() => Observable.of(setControlProperty('rightOverlay', 'enabled', false)));
614614

615615

616-
// Check which control is enabled between annotations and datasetsCatlog
616+
// Check which control is enabled between annotations, datasetsCatalog and documentsCatalog
617617
const oneOfTheOther = (control) => {
618618
if (control === 'rightOverlay') return null;
619+
620+
// Handle three-way alternates
621+
if (control === 'annotations') {
622+
return {
623+
control,
624+
alternates: ['datasetsCatalog', 'documentsCatalog']
625+
};
626+
}
627+
if (control === 'datasetsCatalog') {
628+
return {
629+
control,
630+
alternates: ['annotations', 'documentsCatalog']
631+
};
632+
}
633+
if (control === 'documentsCatalog') {
634+
return {
635+
control,
636+
alternates: ['annotations', 'datasetsCatalog']
637+
};
638+
}
639+
619640
return {
620641
control,
621-
alternate: control === 'annotations' ? 'datasetsCatalog' : 'annotations'
642+
alternates: []
622643
};
623644
};
624645

@@ -635,14 +656,18 @@ export const closeOpenPanels = (action$, store) => action$.ofType(SET_CONTROL_PR
635656
setActions.push(purgeMapInfoResults(), closeIdentify());
636657
}
637658
const isDatasetCatalogPanelOpen = get(state, "controls.datasetsCatalog.enabled");
659+
const isDocumentsCatalogPanelOpen = get(state, "controls.documentsCatalog.enabled");
638660
const isCatalogOpen = get(state, "controls.metadataexplorer.enabled");
639661
const isVisualStyleEditorOpen = get(state, "controls.visualStyleEditor.enabled");
640-
if ((isDatasetCatalogPanelOpen || isVisualStyleEditorOpen) && isCatalogOpen) {
662+
if ((isDatasetCatalogPanelOpen || isDocumentsCatalogPanelOpen || isVisualStyleEditorOpen) && isCatalogOpen) {
641663
setActions.push(catalogClose());
642664
}
643665
if (isDatasetCatalogPanelOpen && isVisualStyleEditorOpen) {
644666
setActions.push(setControlProperty('datasetsCatalog', 'enabled', false));
645667
}
668+
if (isDocumentsCatalogPanelOpen && isVisualStyleEditorOpen) {
669+
setActions.push(setControlProperty('documentsCatalog', 'enabled', false));
670+
}
646671
const isResourceDetailsOpen = !action.show && getShowDetails(state);
647672
if (isResourceDetailsOpen) {
648673
setActions.push(setShowDetails(false));
@@ -651,8 +676,13 @@ export const closeOpenPanels = (action$, store) => action$.ofType(SET_CONTROL_PR
651676
if (control?.control || action.show) {
652677
if (state.controls?.rightOverlay?.enabled === 'Share') {
653678
setActions.push(setControlProperty('rightOverlay', 'enabled', false));
654-
} else if (!!state.controls?.[`${control.alternate}`]?.enabled) {
655-
setActions.push(setControlProperty(`${control.alternate}`, 'enabled', false));
679+
} else {
680+
// Close all alternate panels
681+
control.alternates?.forEach(alternate => {
682+
if (state.controls?.[alternate]?.enabled) {
683+
setActions.push(setControlProperty(alternate, 'enabled', false));
684+
}
685+
});
656686
}
657687
}
658688
return setActions;
@@ -662,12 +692,28 @@ export const closeOpenPanels = (action$, store) => action$.ofType(SET_CONTROL_PR
662692
});
663693

664694
/**
665-
* Close dataset panels on map info panel open
695+
* Close dataset and documents panels on map info panel open
666696
*/
667697
export const closeDatasetCatalogPanel = (action$, store) => action$.ofType(NEW_MAPINFO_REQUEST)
668-
.filter(() => isMapInfoOpen(store.getState()) && get(store.getState(), "controls.datasetsCatalog.enabled"))
698+
.filter(() => {
699+
const state = store.getState();
700+
return isMapInfoOpen(state) &&
701+
(get(state, "controls.datasetsCatalog.enabled") ||
702+
get(state, "controls.documentsCatalog.enabled"));
703+
})
669704
.switchMap(() => {
670-
return Observable.of(setControlProperty('datasetsCatalog', 'enabled', false));
705+
const state = store.getState();
706+
const actions = [];
707+
708+
if (get(state, "controls.datasetsCatalog.enabled")) {
709+
actions.push(setControlProperty('datasetsCatalog', 'enabled', false));
710+
}
711+
712+
if (get(state, "controls.documentsCatalog.enabled")) {
713+
actions.push(setControlProperty('documentsCatalog', 'enabled', false));
714+
}
715+
716+
return Observable.of(...actions);
671717
});
672718

673719
export const closeResourceDetailsOnMapInfoOpen = (action$, store) => action$.ofType(NEW_MAPINFO_REQUEST)
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright 2025, GeoSolutions Sas.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
import React, { forwardRef } from 'react';
10+
import { Dropdown, MenuItem } from 'react-bootstrap';
11+
12+
import Message from '@mapstore/framework/components/I18N/Message';
13+
import Spinner from '@mapstore/framework/components/layout/Spinner';
14+
import FlexBox from '@mapstore/framework/components/layout/FlexBox';
15+
import Text from '@mapstore/framework/components/layout/Text';
16+
import Menu from '@mapstore/framework/plugins/ResourcesCatalog/components/Menu';
17+
18+
const ResourcesMenu = forwardRef(({
19+
menuItems,
20+
style,
21+
totalResources,
22+
loading,
23+
orderConfig,
24+
query,
25+
titleId,
26+
theme = 'main',
27+
menuItemsLeft = [],
28+
target,
29+
resourcesFoundMsgId,
30+
onSortChange
31+
}, ref) => {
32+
33+
34+
const {
35+
defaultLabelId,
36+
options: orderOptions = [],
37+
variant: orderVariant,
38+
align: orderAlign = 'right'
39+
} = orderConfig || {};
40+
41+
const selectedSort = orderOptions.find(({ value }) => query?.sort === value);
42+
43+
const orderButtonNode = orderOptions.length > 0 &&
44+
<Dropdown pullRight={orderAlign === 'right'} id="sort-dropdown">
45+
<Dropdown.Toggle
46+
bsStyle={orderVariant || 'default'}
47+
bsSize="sm"
48+
noCaret
49+
>
50+
<Message msgId={selectedSort?.labelId || defaultLabelId} />
51+
</Dropdown.Toggle>
52+
<Dropdown.Menu>
53+
{orderOptions.map(({ labelId, value }) => {
54+
return (
55+
<MenuItem
56+
key={value}
57+
active={value === selectedSort?.value}
58+
onClick={(e) => {
59+
if (onSortChange) {
60+
e.preventDefault();
61+
onSortChange(value);
62+
}
63+
}}
64+
>
65+
<Message msgId={labelId} />
66+
</MenuItem>
67+
);
68+
})}
69+
</Dropdown.Menu>
70+
</Dropdown>;
71+
72+
return (
73+
<FlexBox
74+
ref={ref}
75+
classNames={[
76+
'ms-resources-menu',
77+
'_sticky',
78+
'_corner-tl',
79+
`ms-${theme}-colors`,
80+
'_padding-tb-sm'
81+
]}
82+
column
83+
gap="sm"
84+
style={style}
85+
>
86+
{titleId
87+
? <Text fontSize="lg">
88+
<Message msgId={titleId} />
89+
</Text>
90+
: null}
91+
<FlexBox centerChildrenVertically gap="xs">
92+
<FlexBox.Fill flexBox centerChildrenVertically gap="sm">
93+
{menuItemsLeft.map(({ Component, name }) => {
94+
return (<Component key={name} query={query} />);
95+
})}
96+
{orderAlign === 'left' ? orderButtonNode : null}
97+
<Text fontSize="sm" ellipsis>
98+
{loading
99+
? <Spinner />
100+
: <span><span>{totalResources}</span>{" "}<Message msgId={resourcesFoundMsgId} msgParams={{ count: totalResources }} /></span>
101+
}
102+
</Text>
103+
</FlexBox.Fill>
104+
<Menu
105+
items={menuItems}
106+
containerClass={`ms-menu-list`}
107+
size="md"
108+
alignRight
109+
target={target}
110+
/>
111+
{orderAlign === 'right' ? orderButtonNode : null}
112+
</FlexBox>
113+
</FlexBox>
114+
);
115+
});
116+
117+
ResourcesMenu.defaultProps = {
118+
orderOptions: [
119+
{
120+
label: 'Most recent',
121+
labelId: 'resourcesCatalog.mostRecent',
122+
value: '-date'
123+
},
124+
{
125+
label: 'Less recent',
126+
labelId: 'resourcesCatalog.lessRecent',
127+
value: 'date'
128+
},
129+
{
130+
label: 'A Z',
131+
labelId: 'resourcesCatalog.aZ',
132+
value: 'title'
133+
},
134+
{
135+
label: 'Z A',
136+
labelId: 'resourcesCatalog.zA',
137+
value: '-title'
138+
},
139+
{
140+
label: 'Most popular',
141+
labelId: 'resourcesCatalog.mostPopular',
142+
value: 'popular_count'
143+
}
144+
],
145+
defaultLabelId: 'resourcesCatalog.orderBy'
146+
};
147+
148+
export default ResourcesMenu;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
* Copyright 2026, GeoSolutions Sas.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
export const GEONODE_DOCUMENTS_ROW_VIEWER = 'GEONODE_DOCUMENTS_ROW_VIEWER';
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright 2026, GeoSolutions Sas.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
import React from 'react';
10+
import MediaViewer from '@js/components/MediaViewer';
11+
import Text from '@mapstore/framework/components/layout/Text';
12+
import FlexBox from '@mapstore/framework/components/layout/FlexBox';
13+
14+
const DocumentInfoViewer = (resource) => {
15+
return (<FlexBox className="gn-document-info-viewer" column gap="sm">
16+
<Text fontSize="md">{resource?.title}</Text>
17+
<MediaViewer resource={resource} />
18+
</FlexBox>);
19+
};
20+
21+
export default DocumentInfoViewer;

0 commit comments

Comments
 (0)