Skip to content

feat(export): Exclude hidden fields from vector data - #1705

Merged
giswqs merged 4 commits into
opengeos:mainfrom
RohithPariki:fix-1676
Aug 4, 2026
Merged

feat(export): Exclude hidden fields from vector data #1705
giswqs merged 4 commits into
opengeos:mainfrom
RohithPariki:fix-1676

Conversation

@RohithPariki

@RohithPariki RohithPariki commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Implements a new "Exclude field on export" option in the attribute table column menu.
  • Intercepts layer serialization across vector data export, project saves, and project sharing to actively prune excluded fields from the embedded layer.geojson data.
  • Applies exclusions natively at the database level when syncing tables from PostGIS via backend/geolibre_server.

Problem

Currently, GeoLibre projects package all source fields inside the embedded GeoJSON vectors. Hiding a column merely removes it from the data grid UI but still writes it to the .geolibre.json payload, network requests (during sharing), and .geojson file exports, inadvertently leaking potentially sensitive metadata (names, addresses, PII, etc).

Root Cause

The export pipeline and the PostGIS sync requests didn't differentiate between fields meant to be visible and fields meant to be completely excluded. The serialization steps simply pulled layer.geojson wholesale and SQL sync requests queried all available columns blindly.

Solution

  • Defined a "excluded" property under the layer's fieldVisibility dict mapping.
  • Added excludeHiddenFieldsFromProject and excludeHiddenFieldsFromGeojson to @geolibre/core to recursively strip excluded properties prior to serialization.
  • Updated TopToolbar, LayerPanel, and useProjectFileActions to route through the exclusion pipeline during sharing, exports, and saves.
  • Patched /postgis/read in the backend sidecar to construct its SQL SELECT geometry projection by omitting excluded_fields.
  • Added UI triggers in the AttributeTable dropdown to exclude or include fields.

Testing & Verification

  • Passed pre-commit hooks and frontend linting (npm run lint).
  • Passed TypeScript typecheck (npm run typecheck).
  • Passed frontend test suite (npm run test:frontend) without dropping coverage below thresholds.
  • Added test_read_drops_excluded_fields regression test and passed backend test suite successfully (npm run test:backend).
  • Visual validation of the Attribute Table context menu.

References

Closes #1676

Summary by CodeRabbit

  • New Features

    • Added field-level controls to include or exclude selected columns from exports.
    • Excluded fields are omitted from GeoJSON, vector exports, shared projects, and saved projects.
    • PostGIS reads support excluding selected fields while preserving geometry and feature IDs.
    • Added clear include/exclude labels and visual indicators in the attribute table.
  • Bug Fixes

    • Hidden or excluded fields are consistently removed before sharing, saving, and exporting.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8faf7170-d746-4ec5-8fae-e8fa78fb0ec7

📥 Commits

Reviewing files that changed from the base of the PR and between 04e12ec and eb48425.

📒 Files selected for processing (4)
  • backend/geolibre_server/geolibre_server/app/postgis.py
  • backend/geolibre_server/tests/test_postgis.py
  • packages/core/src/visibility.ts
  • tests/visibility.test.ts

📝 Walkthrough

Walkthrough

The PR adds per-field visibility states and removes excluded fields from GeoJSON, project sharing, project saves, vector exports, attribute-table exports, and PostGIS reads. The attribute table adds controls to toggle export exclusion.

Changes

Field exclusion

Layer / File(s) Summary
Visibility model and filtering utilities
packages/core/src/types.ts, packages/core/src/visibility.ts, packages/core/src/index.ts, tests/visibility.test.ts
Defines FieldVisibility, adds layer-level field visibility settings, and provides tested GeoJSON and project filtering utilities.
Desktop field controls and egress filtering
apps/geolibre-desktop/src/components/panels/AttributeTable.tsx, apps/geolibre-desktop/src/components/panels/LayerPanel.tsx, apps/geolibre-desktop/src/components/layout/TopToolbar.tsx, apps/geolibre-desktop/src/hooks/useProjectFileActions.ts, apps/geolibre-desktop/src/i18n/locales/en.json
Adds field export toggles and applies exclusion during attribute export, vector export, project sharing, and project saving.
PostGIS read-column filtering
packages/processing/src/sidecar-client.ts, backend/geolibre_server/geolibre_server/app/postgis.py, backend/geolibre_server/tests/test_postgis.py
Passes excluded fields to PostGIS reads, omits them from SQL results and GeoJSON properties, and verifies geometry and feature IDs remain available.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AttributeTable
  participant CoreVisibility
  participant ExportHandlers
  participant LayerPanel
  participant PostGIS
  AttributeTable->>CoreVisibility: GeoJSON and excluded field names
  CoreVisibility-->>ExportHandlers: GeoJSON without excluded properties
  LayerPanel->>PostGIS: excluded_fields
  PostGIS-->>LayerPanel: features with filtered properties
Loading

Possibly related PRs

Suggested reviewers: giswqs

Poem

A rabbit marks fields with a tap of its paw,
Excluded leaves vanish from files that it saw.
GeoJSON grows lighter, projects stay neat,
PostGIS serves only the columns complete.
“Hop!” says the rabbit, “the filter is done!”

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements core exclusion, UI, export, sharing, and PostGIS changes, but does not cover all required egress paths or hidden-field consumers. Implement and test exclusion for standalone HTML, print/report, AI, clipboard, identify, styling, and other required egress and visibility paths.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: excluding hidden fields from vector data during export.
Out of Scope Changes check ✅ Passed All changes support field exclusion, persistence, export, sharing, PostGIS queries, localization, or regression coverage described in issue #1676.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: dependency version conflict. Check your lock file or package.json.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

🔍 Cloudflare PR preview

Item Value
Site https://74e5c8f6.geolibre-preview.pages.dev
Demo app https://74e5c8f6.geolibre-preview.pages.dev/demo/
Commit eb48425

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/geolibre-desktop/src/components/panels/LayerPanel.tsx (1)

1557-1560: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Generate Shapefile warnings from egressGeojson.

Line 1550 exports egressGeojson, but Line 1559 scans the unfiltered geojson. An excluded long field or field-name collision can produce a warning for a field that is not in the output. Pass egressGeojson to shapefileFieldWarnings.

Proposed fix
- const warnings = format === "shapefile" ? shapefileFieldWarnings(geojson) : [];
+ const warnings = format === "shapefile" ? shapefileFieldWarnings(egressGeojson) : [];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/geolibre-desktop/src/components/panels/LayerPanel.tsx` around lines 1557
- 1560, Update the Shapefile warning generation in the export flow to pass
egressGeojson, the filtered export dataset, to shapefileFieldWarnings instead of
geojson. Keep the existing format check and refresh-status behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/geolibre_server/geolibre_server/app/postgis.py`:
- Around line 542-544: The query-building logic around read_columns must always
retain the primary-key column even when request.excluded_fields includes it, so
the feature identity remains available for the assignment around feature.id.
Keep the primary key in the selected result while omitting it from properties,
or reject attempts to exclude it before querying; add coverage for primary-key
exclusion.
- Line 581: Update the row-to-property mapping in the properties comprehension
to call zip(read_columns, row[1:], strict=True), ensuring SELECT/result-length
mismatches raise immediately instead of silently dropping values.

In `@packages/core/src/visibility.ts`:
- Around line 42-50: Update excludeHiddenFieldsFromProject to also sanitize each
layer’s metadata.embeddedGeoJSON with excludeHiddenFieldsFromGeojson before
buildEmbeddedLayers materializes embedded data, preserving unchanged metadata
when no fields are removed and marking the project changed when filtering
occurs. Add save and share coverage verifying excluded properties are absent
from embedded GeoJSON.

---

Outside diff comments:
In `@apps/geolibre-desktop/src/components/panels/LayerPanel.tsx`:
- Around line 1557-1560: Update the Shapefile warning generation in the export
flow to pass egressGeojson, the filtered export dataset, to
shapefileFieldWarnings instead of geojson. Keep the existing format check and
refresh-status behavior unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 88d72d7f-20e8-4d44-83a8-3c63d29b6e0e

📥 Commits

Reviewing files that changed from the base of the PR and between 8a7d3dd and 04e12ec.

📒 Files selected for processing (11)
  • apps/geolibre-desktop/src/components/layout/TopToolbar.tsx
  • apps/geolibre-desktop/src/components/panels/AttributeTable.tsx
  • apps/geolibre-desktop/src/components/panels/LayerPanel.tsx
  • apps/geolibre-desktop/src/hooks/useProjectFileActions.ts
  • apps/geolibre-desktop/src/i18n/locales/en.json
  • backend/geolibre_server/geolibre_server/app/postgis.py
  • backend/geolibre_server/tests/test_postgis.py
  • packages/core/src/index.ts
  • packages/core/src/types.ts
  • packages/core/src/visibility.ts
  • packages/processing/src/sidecar-client.ts

Comment thread backend/geolibre_server/geolibre_server/app/postgis.py Outdated
Comment thread backend/geolibre_server/geolibre_server/app/postgis.py Outdated
Comment thread packages/core/src/visibility.ts Outdated
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

🔍 GitHub Pages PR preview

Item Value
Site Deploy failed. See the job log.
Demo app Unavailable
Commit eb48425

@giswqs

giswqs commented Aug 4, 2026

Copy link
Copy Markdown
Member

/claude-review

@@ -843,13 +844,18 @@ export function useProjectFileActions(mapControllerRef: MapControllerRef) {
// them. Make keeping them an explicit choice and use the same central
// redaction pass as every external egress.
let contentToSave = content;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: contentToSave is now unconditionally reassigned in every branch of the if/else below (both the redactedPaths.length > 0 "keep" branch and the else branch call serializeProject(projectToEgress), and "strip" calls serializeProject(redacted.project)), so this initial let contentToSave = content; is dead — it's never read before being overwritten. Slightly misleading since it looks like a real fallback. Could simplify to declare contentToSave inside the branches, or drop the outer content variable if it's now unused elsewhere.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Code review

Bugs

  • handleSaveEditsToSource's PostGIS re-read (apps/geolibre-desktop/src/components/panels/LayerPanel.tsx:1918-1927) applies excluded_fields to the refresh that repopulates the layer's live in-memory geojson, not just at export/share/save boundaries like the rest of the PR — this strips excluded field data from the working copy itself, breaking further editing/viewing of that field until a full reload, and is inconsistent with the plain handleRefreshLayer path which applies no exclusion at all. Confidence: medium-high.
  • handleExportLayer (LayerPanel.tsx:1559) computes Shapefile field-name-collision warnings against the pre-exclusion geojson instead of the exported egressGeojson, so it can warn about a field that isn't even written to the file; AttributeTable.tsx's equivalent path does this correctly. Confidence: medium.

Security

  • renameColumn (apps/geolibre-desktop/src/lib/attribute-columns.ts) never migrates a matching layer.fieldVisibility key when a column is renamed, so renaming a field the user marked "excluded" silently un-excludes it — the field then reappears in exports, project saves, and shares with no warning. This directly undermines the feature's stated purpose of preventing sensitive-field leakage via an ordinary, easy-to-trigger user action. Confidence: high.

Performance

  • No notable issues found in the changed code.

Quality

  • useProjectFileActions.ts:846let contentToSave = content; is now dead: every branch of the following conditional overwrites it, so the initial value is never read. Low confidence/minor.
  • FieldVisibility's "hidden" variant is never produced anywhere in this PR (the pre-existing "hide column" feature is a wholly separate columnSettings.hidden mechanism), and the new helpers excludeHiddenFieldsFromGeojson/excludeHiddenFieldsFromProject are named around "hidden" fields but only ever strip "excluded" ones — this naming overlap with the older mechanism is likely to confuse future contributors. Low-medium confidence.
  • Minor i18n inconsistency: the two new dropdown labels use t(key, "default text") while the sibling hideField/renameField items just use t(key), even though both keys are already defined in en.json. Not a functional issue, just inconsistent with the rest of the file.

CLAUDE.md

  • No violations found — new strings were added to en.json and routed through t(), and RTL-safe me-2 spacing was reused consistent with the existing menu items.

@giswqs
giswqs merged commit 0da0215 into opengeos:main Aug 4, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Field-level visibility: hide attributes and exclude them on share and export

2 participants