Skip to content

feat: add bidirectional map/table selection sync to collapsible data table [PR2] - #3720

Open
BRaimbault wants to merge 8 commits into
feat/datatable-pr1-toolbarfrom
feat/datatable-pr2-bidirectional-sync
Open

BRaimbault wants to merge 8 commits into
feat/datatable-pr1-toolbarfrom
feat/datatable-pr2-bidirectional-sync

Conversation

@BRaimbault

@BRaimbault BRaimbault commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Part of DHIS2-21456

Diff size note: this PR adds ~2,200 lines: ~1,400 are runtime code / ~800 (36%) are tests.

Description

Adds bidirectional highlighting/selection sync between the map and data table, persistent multi-feature selection, and a collapsible/resizable table panel. Second in the data table improvement series, building on PR1's toolbar and context menu.

Selection (DataTable)

  • New checkbox column; header checkbox selects/deselects all currently visible rows in one action
  • Ctrl/Cmd-click a row to toggle its selection; Shift-click selects a range from the last-clicked row (falls back to a single-row toggle if there's no prior anchor yet)
  • Selection is tracked in a new selection reducer, scoped per layer, and resets on layer switch

Map ↔ table sync

  • Hovering a map feature highlights and scrolls to its table row; hovering a table row highlights the feature on the map — consistent styling in both directions (previously cursor-hover fell through to @dhis2/ui's native grey tr:hover style while map-hover showed our own blue highlight)
  • Left/right-clicking a map feature scrolls the table to its row without changing selection; Ctrl/Cmd-click also toggles selection
  • Double-clicking a table row zooms the map to that feature
  • A row that's both selected and hovered now shows the hover color, not the selected color

Filtering

  • "Show only selected features" and "show only in view" toolbar toggles filter both the table and the map
  • "Show only in view" now uses true bounding-box overlap instead of centroid-only, and correctly handles map viewports that cross the antimeridian

Zoom actions

  • "Zoom to layer" added to the table's row context menu (previously map-only)
  • "Zoom to selected features" added to both the map and table context menus, disabled when nothing's selected; zooms to the combined bounds of every selected feature

Table panel (BottomPanel)

  • Collapse/restore button and double-click-the-header-to-toggle, shrinking the panel down to just the toolbar strip
  • The resize handle is always available, including collapsed: dragging up exits collapsed mode and resizes live; dragging down to the floor enters collapsed mode
  • Restoring (button, double-click, or dragging back up) returns to the exact height the panel had before collapsing

Bug fixes

  • Long unbroken text (e.g. URLs) in table cells now wraps instead of overflowing
  • O(n·m) .includes() scans in selection filtering replaced with O(1) Set lookups
  • Fixed a stale-effect bug where Ctrl-clicking a table row (or any selection change) re-triggered the map-click scroll effect and yanked the table back to a previously map-clicked row
  • Fixed a crash in the map context menu's mapStateToProps when no context menu is open
  • Fixed the toolbar layout bug where the resize handle's runaway flex-basis squeezed the layer name to zero width

maps-gl

  • New Cluster.setVisibleIds() override: "show only selected" now re-clusters from the filtered feature set (via source.setData()) instead of applying a GL filter expression, which can't target cluster circles (they carry no per-feature id). Applies to client- and donut-clustered event layers; server-clustered layers are unaffected since their data table is already unsupported today (unrelated pre-existing limitation)
  • Layer#panToFeature() now accepts an array of ids, fitting the map to their combined bounds

Quality checklist

Add N/A to items that are not applicable.

Screenshots

supporting images

@dhis2-bot

Copy link
Copy Markdown
Contributor

🚀 Deployed on https://pr-3720.maps.netlify.dhis2.org

@dhis2-bot
dhis2-bot temporarily deployed to netlify July 13, 2026 15:58 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 13, 2026 16:04 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 13, 2026 18:51 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 13, 2026 18:54 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 13, 2026 22:37 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 14, 2026 17:21 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 16, 2026 22:15 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 17, 2026 10:03 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 17, 2026 18:21 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 19, 2026 10:17 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 19, 2026 10:21 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 19, 2026 13:42 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 19, 2026 15:49 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 19, 2026 20:52 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 19, 2026 21:23 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 19, 2026 23:26 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 20, 2026 07:19 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 20, 2026 12:06 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 20, 2026 14:13 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 20, 2026 15:00 Inactive
@BRaimbault
BRaimbault marked this pull request as ready for review July 27, 2026 09:45
@BRaimbault
BRaimbault force-pushed the feat/datatable-pr2-bidirectional-sync branch from 1489b0f to 782301d Compare July 27, 2026 09:58
@BRaimbault
BRaimbault marked this pull request as draft July 27, 2026 09:59
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 27, 2026 10:00 Inactive
@BRaimbault
BRaimbault force-pushed the feat/datatable-pr2-bidirectional-sync branch from 782301d to 2e5fe4f Compare July 27, 2026 10:02
@dhis2-bot
dhis2-bot temporarily deployed to netlify July 27, 2026 10:04 Inactive
@BRaimbault BRaimbault changed the title feat: add bidirectional map/table selection sync and collapsible datatable [PR2] feat: add bidirectional map/table selection sync to data table [PR2] Jul 28, 2026

@HendrikThePendric HendrikThePendric 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.

In general this looks good. I did leave some comments which you can take or leave.

Another thing I noticed while reviewing was a general pattern where I saw:

  • A diff in the prop-types
  • A diff in the props in the function signature
  • No changes in the function body
  • A diff in the JSX where the added props being passed down to descendants

So this is prop-drilling and you could consider addressing it by introducing a/multiple context providers and maybe some hooks. But this is just a casual comment. I didn't look into it deeply and also realise this is a codebase with a mix of function and class components, so it could get messy.

Comment thread src/components/datatable/useTableData.js Outdated
Comment thread src/components/map/layers/Layer.js Outdated
@edoardo
edoardo dismissed HendrikThePendric’s stale review August 24, 2026 09:55

The merge-base changed after approval.

@edoardo
edoardo force-pushed the feat/datatable-pr2-bidirectional-sync branch from 2e5fe4f to 14df4cc Compare August 24, 2026 09:55
@dhis2-bot
dhis2-bot temporarily deployed to netlify August 24, 2026 09:57 Inactive
@BRaimbault
BRaimbault force-pushed the feat/datatable-pr2-bidirectional-sync branch from 14df4cc to 6d9fa0b Compare September 1, 2026 10:27
@dhis2-bot
dhis2-bot temporarily deployed to netlify September 1, 2026 10:29 Inactive
@BRaimbault
BRaimbault force-pushed the feat/datatable-pr2-bidirectional-sync branch from 6d9fa0b to e6143ed Compare September 4, 2026 08:59
@dhis2-bot
dhis2-bot temporarily deployed to netlify September 4, 2026 09:01 Inactive
@dhis2-bot
dhis2-bot temporarily deployed to netlify September 4, 2026 09:38 Inactive
@BRaimbault

Copy link
Copy Markdown
Collaborator Author

Thanks for your review @HendrikThePendric, I addressed your specific comments and marked them as resolved. On the prop-drilling observation, agreed, but don't want to extend this PR's scope now. I will explore using a context as a PR stack clean-up or at a later stage.

@BRaimbault
BRaimbault removed this pull request from stack #3735 September 9, 2026 08:34
@BRaimbault
BRaimbault added this pull request to stack #3765 September 9, 2026 08:34
@BRaimbault
BRaimbault force-pushed the feat/datatable-pr2-bidirectional-sync branch from 9cc47fc to 70bcd59 Compare September 9, 2026 08:36
@dhis2-bot
dhis2-bot temporarily deployed to netlify September 9, 2026 08:38 Inactive
Clarify/relocate the boundsDependency comment in useTableData, and
rename Layer's componentDidUpdate handlers from the misleading
handleXChange pattern (reads as event handlers, when most of the work
is detecting whether a change is relevant) to a consistent sync*
naming scheme, per review feedback.
@BRaimbault
BRaimbault force-pushed the feat/datatable-pr2-bidirectional-sync branch from 70bcd59 to d9d782f Compare September 10, 2026 12:49
@sonarqubecloud

Copy link
Copy Markdown

@dhis2-bot
dhis2-bot temporarily deployed to netlify September 10, 2026 12:50 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants