Skip to content

Commit c221b3b

Browse files
authored
#1992: Metadata editor - 2-levels nested dropdown support (#1993)
1 parent cb9f907 commit c221b3b

File tree

4 files changed

+75
-6
lines changed

4 files changed

+75
-6
lines changed

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

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,34 @@ import {
1212
RESOURCES,
1313
getEndpointUrl
1414
} from './constants';
15-
import { isObject, isArray, castArray } from 'lodash';
15+
import isObject from 'lodash/isObject';
16+
import isArray from 'lodash/isArray';
17+
import castArray from 'lodash/castArray';
18+
import isEmpty from 'lodash/isEmpty';
19+
20+
const uiKeys = (entry) => Object.keys(entry).filter(propertyKey => propertyKey.indexOf('ui:') === 0);
1621

1722
const parseUiSchema = (properties) => {
1823
return Object.keys(properties).reduce((acc, key) => {
1924
const entry = properties[key];
20-
const uiKeys = Object.keys(entry).filter(propertyKey => propertyKey.indexOf('ui:') === 0);
21-
if (uiKeys.length) {
22-
acc[key] = Object.fromEntries(uiKeys.map(uiKey => [uiKey, entry[uiKey]]));
25+
const uiKeysRoot = uiKeys(entry);
26+
if (uiKeysRoot.length) {
27+
acc[key] = Object.fromEntries(uiKeysRoot.map(uiKey => [uiKey, entry[uiKey]]));
28+
}
29+
if (entry.type === 'array') {
30+
const uiKeysNested = uiKeys(entry?.items);
31+
if (uiKeysNested.length) {
32+
acc[key] = Object.fromEntries(uiKeysNested.map(uiKey => [uiKey, entry?.items?.[uiKey]]));
33+
}
2334
}
2435
if (entry.type === 'object') {
2536
const nestedProperties = parseUiSchema(entry?.properties);
2637
acc[key] = { ...acc[key], ...nestedProperties };
2738
}
39+
if (entry.type === 'array' && entry.items?.type === 'object') {
40+
const nestedProperties = parseUiSchema(entry?.items?.properties);
41+
acc[key] = { ...acc[key], ...(!isEmpty(nestedProperties) && {items: {...nestedProperties}}) };
42+
}
2843
return acc;
2944
}, {});
3045
};

geonode_mapstore_client/client/js/plugins/MetadataEditor/components/_fields/SchemaField.jsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ import axios from '@mapstore/framework/libs/ajax';
1111
import castArray from 'lodash/castArray';
1212
import isEmpty from 'lodash/isEmpty';
1313
import isString from 'lodash/isString';
14+
import template from 'lodash/template';
1415
import Autocomplete from '../Autocomplete';
1516
import DefaultSchemaField from '@rjsf/core/lib/components/fields/SchemaField';
17+
import useSchemaReference from './useSchemaReference';
1618

1719
function findProperty(name, properties) {
1820
return Object.keys(properties || {}).some((key) => {
@@ -58,6 +60,7 @@ const SchemaField = (props) => {
5860
(isSchemaItemObject && !isEmpty(schema?.items?.properties))
5961
);
6062
const isSingleSelect = schema?.type === 'object' && !isEmpty(schema?.properties);
63+
const { referenceValue, referenceKey } = useSchemaReference({...props, isMultiSelect });
6164

6265
if (autocomplete && (isMultiSelect || isSingleSelect)) {
6366
const {
@@ -87,7 +90,10 @@ const SchemaField = (props) => {
8790
const autocompleteOptions = isString(autocomplete)
8891
? { url: autocomplete }
8992
: autocomplete;
90-
const autocompleteUrl = autocompleteOptions?.url;
93+
let autocompleteUrl = autocompleteOptions?.url;
94+
if (referenceValue) {
95+
autocompleteUrl = template(autocompleteUrl)({[referenceKey ?? 'id']: referenceValue });
96+
}
9197
const queryKey = autocompleteOptions?.queryKey || 'q';
9298
const resultsKey = autocompleteOptions?.resultsKey || 'results';
9399
const valueKey = autocompleteOptions?.valueKey || 'id';
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import {useEffect, useRef} from 'react';
2+
import get from 'lodash/get';
3+
import template from 'lodash/template';
4+
5+
export default ({
6+
uiSchema,
7+
idSchema,
8+
onChange,
9+
isMultiSelect,
10+
formContext,
11+
name
12+
}) => {
13+
const uiOptions = uiSchema?.['ui:options'];
14+
const referenceValuePath = uiOptions?.['geonode-ui:referencevalue'];
15+
const referenceKey = uiOptions?.['geonode-ui:referencekey'];
16+
17+
// Extract index from the ID schema
18+
const match = idSchema.$id.match(/_(\d+)(_|$)/);
19+
const index = match ? parseInt(match[1], 10) : null;
20+
const referenceValue = referenceValuePath
21+
? get(formContext, `metadata.${template(referenceValuePath)({'index': index})}`)
22+
: null;
23+
const prevReferenceValue = useRef(null);
24+
25+
const storeReferenceValue = (value) => {
26+
prevReferenceValue.current = {
27+
...prevReferenceValue.current, [name]: value
28+
};
29+
};
30+
31+
useEffect(() => {
32+
// store the initial reference value
33+
if (prevReferenceValue.current === null && referenceValuePath) {
34+
storeReferenceValue(referenceValue);
35+
}
36+
}, []);
37+
38+
useEffect(()=> {
39+
// to reset the form data when the parent field reference value changes
40+
if (referenceValuePath && referenceValue !== prevReferenceValue.current?.[name]) {
41+
storeReferenceValue(referenceValue);
42+
onChange(isMultiSelect ? [] : {});
43+
}
44+
}, [referenceValuePath, referenceValue]);
45+
46+
return { referenceValue, referenceKey };
47+
};

geonode_mapstore_client/client/js/plugins/MetadataEditor/containers/MetadataEditor.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ function MetadataEditor({
109109
readonly={readOnly}
110110
ref={initialize.current}
111111
formContext={{
112-
title: metadata?.title
112+
title: metadata?.title,
113+
metadata
113114
}}
114115
schema={schema}
115116
widgets={widgets}

0 commit comments

Comments
 (0)