Feature/publish data collection#2591
Conversation
…t be refreshed
(cherry picked from commit 856e7fa)
) * updates to improve templates customizations * review delete redirect (cherry picked from commit 6533619) Co-authored-by: stefano bovio <stefano.bovio@geosolutionsgroup.com>
Co-authored-by: allyoucanmap <allyoucanmap@users.noreply.github.com>
(cherry picked from commit bab3b5b) Co-authored-by: stefano bovio <stefano.bovio@geosolutionsgroup.com>
Co-authored-by: giohappy <giohappy@users.noreply.github.com>
Co-authored-by: giohappy <giohappy@users.noreply.github.com>
* Update 4.4.x MS submodule to release 2024.02.xx * update module
Co-authored-by: giohappy <giohappy@users.noreply.github.com>
…) (GeoNode#1917) * Added table of content to open layer details in map view. Fixes issue#1660. * Updated to the newer version. * Code refactor * Fixed instability issues for info button on TOC. * Fixed linked resources for info button on TOC and code cleanup. * Avoided repeating calls to get layer dataset fields including linked resources for info button on TOC. * Fixed localConfig json file for the info button. * Reverted api changes to include linked resources, because they are already included for 'viewer_common' api_preset. * Fixed getDatasetByPk definition. * Fixed linting issues. * Fixed bug where info button was misbehaving when any maplayer had no dataset. * Fixed a bug where the title of the dataset was not changing on the details panel. --------- Co-authored-by: Suren <dsuren1@gmail.com> (cherry picked from commit 9b1dcb4) Co-authored-by: ahmdthr <116570171+ahmdthr@users.noreply.github.com>
Co-authored-by: giohappy <giohappy@users.noreply.github.com>
…eoNode#1924) (cherry picked from commit d05f04a) Co-authored-by: Suren <dsuren1@gmail.com>
Co-authored-by: allyoucanmap <allyoucanmap@users.noreply.github.com>
…eoNode#1932) (cherry picked from commit 9e79006) Co-authored-by: Suren <dsuren1@gmail.com>
Co-authored-by: allyoucanmap <allyoucanmap@users.noreply.github.com>
Co-authored-by: allyoucanmap <allyoucanmap@users.noreply.github.com>
…GeoNode#1942) (GeoNode#1950) (cherry picked from commit a9f2cfd) Co-authored-by: Suren <dsuren1@gmail.com>
…eoNode#1953) (cherry picked from commit 89a25af) Co-authored-by: Suren <dsuren1@gmail.com>
Co-authored-by: giohappy <giohappy@users.noreply.github.com>
[main-ui] new JS dist build
[main-ui] new JS dist build
[main-ui] new JS dist build
[main-ui] new JS dist build
…n.jsx Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…/geonode-mapstore-client into feature/publish-data-collection
There was a problem hiding this comment.
Code Review
This pull request introduces support for tabular datasets and tabular collections in the GeoNode MapStore client by adding new routes, components, and plugins (such as TabularPreview, TabularCollectionViewer, ApproveDataCollection, PublishDataCollection, and Footer), and integrating DataCite publishing configurations. It also refactors the card grid container layout to use CSS container queries instead of react-resize-detector. The review feedback highlights several critical areas for improvement, primarily focusing on preventing potential TypeError and AttributeError crashes through optional chaining and safety guards when handling potentially null or undefined resources, layers, or user objects. Additionally, the feedback points out a test suite failure caused by commented-out configuration items, recommends replacing HTML 'class' attributes with React's 'className' in the new Footer component, suggests URL query parameter handling improvements in ShareEmbedLink, and advises cleaning up unused props and speculative comments.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| (state) => state?.gnsettings?.geoserverUrl, | ||
| (state) => state?.gnresource?.data | ||
| ], (geoserverUrl, resource) => { | ||
| if (!resource.subtype || !geoserverUrl) { |
| function headerFromFeatures(data) { | ||
| const feature = data.features[0] || [] | ||
| const properties = feature.properties; | ||
| return Object.keys(properties).map((p, index) => ({ value: p, key: propertyToKey(p, index) })); | ||
| }; | ||
|
|
||
| function rowsFromFeatures(data) { | ||
| const features = data.features || [] | ||
| // [{col1: "value"}] | ||
| return features.map((feature, index) => { | ||
| const row = {} | ||
| const properties = feature.properties | ||
| Object.keys(properties) | ||
| .forEach(name => Object.assign(row, { [propertyToKey(name, index)]: properties[name] })) | ||
| return row; | ||
| }); | ||
| }; |
There was a problem hiding this comment.
If data is undefined, or data.features is empty, or feature.properties is undefined, both headerFromFeatures and rowsFromFeatures will throw a TypeError when calling Object.keys(properties). Please add safety guards and default values to prevent these crashes.
| function headerFromFeatures(data) { | |
| const feature = data.features[0] || [] | |
| const properties = feature.properties; | |
| return Object.keys(properties).map((p, index) => ({ value: p, key: propertyToKey(p, index) })); | |
| }; | |
| function rowsFromFeatures(data) { | |
| const features = data.features || [] | |
| // [{col1: "value"}] | |
| return features.map((feature, index) => { | |
| const row = {} | |
| const properties = feature.properties | |
| Object.keys(properties) | |
| .forEach(name => Object.assign(row, { [propertyToKey(name, index)]: properties[name] })) | |
| return row; | |
| }); | |
| }; | |
| function headerFromFeatures(data) { | |
| const feature = data?.features?.[0]; | |
| const properties = feature?.properties || {}; | |
| return Object.keys(properties).map((p, index) => ({ value: p, key: propertyToKey(p, index) })); | |
| }; | |
| function rowsFromFeatures(data) { | |
| const features = data?.features || []; | |
| // [{col1: "value"}] | |
| return features.map((feature, index) => { | |
| const row = {}; | |
| const properties = feature?.properties || {}; | |
| Object.keys(properties) | |
| .forEach(name => Object.assign(row, { [propertyToKey(name, index)]: properties[name] })); | |
| return row; | |
| }); | |
| }; |
| setTextValue(evt.target.value); | ||
| onEdit(evt.target.value); | ||
| }} | ||
| value={textValue} | ||
| value={onEdit ? textValue : title} |
There was a problem hiding this comment.
If onEdit is not provided (which is possible since value conditionally checks onEdit ? textValue : title), typing in the input will throw a TypeError: onEdit is not a function because it is called unconditionally in onChange. Please add a guard check before calling onEdit.
setTextValue(evt.target.value);
if (onEdit) {
onEdit(evt.target.value);
}
}}
value={onEdit ? textValue : title}| ...(sourcetype === SOURCE_TYPES.REMOTE && !wmsUrl.includes('/geoserver/') && { | ||
| serverType: ServerTypes.NO_VENDOR | ||
| }) |
There was a problem hiding this comment.
If wmsUrl is undefined, calling wmsUrl.includes('/geoserver/') will throw a TypeError. Please add a check to ensure wmsUrl is defined before calling includes.
| ...(sourcetype === SOURCE_TYPES.REMOTE && !wmsUrl.includes('/geoserver/') && { | |
| serverType: ServerTypes.NO_VENDOR | |
| }) | |
| ...(sourcetype === SOURCE_TYPES.REMOTE && wmsUrl && !wmsUrl.includes('/geoserver/') && { | |
| serverType: ServerTypes.NO_VENDOR | |
| }) |
| const ApproveDataCollectionComponent = (props) => { | ||
| const { open, onClose, style=DEFAULT_DIALOG_STYLE, closeGlyph, dispatch } = props; | ||
| const { title, owner } = props.resourceData; |
There was a problem hiding this comment.
If props.resourceData is null or undefined, destructuring title and owner will throw a TypeError. Additionally, owner.pk on line 44 can crash if owner is null. Please add a safety guard to return null if resourceData is not available, and use optional chaining for owner?.pk.
| const ApproveDataCollectionComponent = (props) => { | |
| const { open, onClose, style=DEFAULT_DIALOG_STYLE, closeGlyph, dispatch } = props; | |
| const { title, owner } = props.resourceData; | |
| const ApproveDataCollectionComponent = (props) => { | |
| const { open, onClose, style=DEFAULT_DIALOG_STYLE, closeGlyph, dispatch } = props; | |
| if (!props.resourceData) { | |
| return null; | |
| } | |
| const { title, owner } = props.resourceData; |
| <Cards | ||
| featured | ||
| resources={resources} | ||
| formatHref={formatHref} | ||
| isCardActive={isCardActive} | ||
| buildHrefByTemplate={buildHrefByTemplate} | ||
| containerWidth={width} | ||
| downloading={downloading} | ||
| getDetailHref={getDetailHref} | ||
| /> |
There was a problem hiding this comment.
The Cards component no longer accepts or uses the containerWidth prop. You should remove containerWidth={width} from the <Cards /> component. Additionally, since width is no longer used anywhere else in FeaturedList, you can remove the width prop and the withResizeDetector wrapper from FeaturedList entirely to clean up the code.
| <Cards | |
| featured | |
| resources={resources} | |
| formatHref={formatHref} | |
| isCardActive={isCardActive} | |
| buildHrefByTemplate={buildHrefByTemplate} | |
| containerWidth={width} | |
| downloading={downloading} | |
| getDetailHref={getDetailHref} | |
| /> | |
| <Cards | |
| featured | |
| resources={resources} | |
| formatHref={formatHref} | |
| isCardActive={isCardActive} | |
| buildHrefByTemplate={buildHrefByTemplate} | |
| downloading={downloading} | |
| getDetailHref={getDetailHref} | |
| /> |
|
|
||
| /* this function adds plugin based on the current query, used mainly for embed pages*/ | ||
| export const addQueryPlugins = (pluginsConfig, query) => { | ||
| if (isArray(pluginsConfig)) { |
| <nav class="col-6 col-md-6 col-lg-3" aria-label="Quick Links"> | ||
| <h3 class="fs-5 fw-bold mb-3 text-light">Quick Links</h3> | ||
| <ul class="list-unstyled fs-6 fw-normal m-0"> | ||
| <li class="mb-2"> | ||
| <a href="/about" class="link-light text-decoration-none">About</a> | ||
| </li> | ||
| <li class="mb-2"> | ||
| <a href="/upload" class="link-light text-decoration-none">Upload</a> | ||
| </li> | ||
| <li class="mb-2"> | ||
| <a href="/ogc_and_api" class="link-light text-decoration-none">OGC Services and API</a> | ||
| </li> | ||
| <li class="mb-2"> | ||
| <a href="https://www.zalf.de/en/struktur/cdp/fdm/Pages/default.aspx" class="link-light text-decoration-none">Research Data Management</a> | ||
| </li> | ||
| </ul> | ||
| </nav> | ||
|
|
||
|
|
||
|
|
||
|
|
||
| {/* Resources */} | ||
| <nav class="col-6 col-md-6 col-lg-3" aria-label="Resources"> | ||
| <h3 class="fs-5 fw-bold mb-3 text-light">Resources</h3> | ||
| <ul class="list-unstyled fs-6 fw-normal m-0"> | ||
| <li class="mb-2"> | ||
| <a href="/publications" class="link-light">Publications</a> | ||
| </li> | ||
| <li class="mb-2"> | ||
| <a href="/data_policy" class="link-light">Data Policy</a> | ||
| </li> | ||
| <li class="mb-2"> | ||
| <a href="/how_to_cite" class="link-light">How to Cite Us</a> | ||
| </li> | ||
| <li class="mb-2"> | ||
| <a href="/imprint" class="link-light">Imprint</a> | ||
| </li> | ||
| <li class="mb-2"> | ||
| <a href="/privacy" class="link-light">Privacy</a> | ||
| </li> | ||
| </ul> | ||
| </nav> |
There was a problem hiding this comment.
In React, you must use className instead of class for styling elements. Using class will trigger console warnings and may prevent styles from being applied correctly. Please replace all occurrences of class with className in this file.
<nav className="col-6 col-md-6 col-lg-3" aria-label="Quick Links">
<h3 className="fs-5 fw-bold mb-3 text-light">Quick Links</h3>
<ul className="list-unstyled fs-6 fw-normal m-0">
<li className="mb-2">
<a href="/about" className="link-light text-decoration-none">About</a>
</li>
<li className="mb-2">
<a href="/upload" className="link-light text-decoration-none">Upload</a>
</li>
<li className="mb-2">
<a href="/ogc_and_api" className="link-light text-decoration-none">OGC Services and API</a>
</li>
<li className="mb-2">
<a href="https://www.zalf.de/en/struktur/cdp/fdm/Pages/default.aspx" className="link-light text-decoration-none">Research Data Management</a>
</li>
</ul>
</nav>
{/* Resources */}
<nav className="col-6 col-md-6 col-lg-3" aria-label="Resources">
<h3 className="fs-5 fw-bold mb-3 text-light">Resources</h3>
<ul className="list-unstyled fs-6 fw-normal m-0">
<li className="mb-2">
<a href="/publications" className="link-light">Publications</a>
</li>
<li className="mb-2">
<a href="/data_policy" className="link-light">Data Policy</a>
</li>
<li className="mb-2">
<a href="/how_to_cite" className="link-light">How to Cite Us</a>
</li>
<li className="mb-2">
<a href="/imprint" className="link-light">Imprint</a>
</li>
<li className="mb-2">
<a href="/privacy" className="link-light">Privacy</a>
</li>
</ul>
</nav>| : resource.resource_type === ResourceTypes.DATASET | ||
| && ![GXP_PTYPES.REST_IMG, GXP_PTYPES.REST_MAP].includes(resource.ptype) | ||
| && isDefaultDatasetSubtype(resource.subtype) | ||
| && resource.subtype !== "tabular" // obsolete by above line?! |
| if user is None or not user.is_authenticated: | ||
| return {"can_publish": False, "prefixes": []} | ||
|
|
||
| can_publish = user.can_publish_data_collection() |
There was a problem hiding this comment.
To prevent potential AttributeError crashes (e.g., in environments or tests where the custom user model or monkey-patching is not fully loaded), please check if the can_publish_data_collection attribute exists on the user object before calling it.
| can_publish = user.can_publish_data_collection() | |
| can_publish = hasattr(user, "can_publish_data_collection") and user.can_publish_data_collection() |
No description provided.