feat: column show/hide, pinning, reordering, and persistence for data table [PR4]#3724
Draft
BRaimbault wants to merge 29 commits into
Draft
feat: column show/hide, pinning, reordering, and persistence for data table [PR4]#3724BRaimbault wants to merge 29 commits into
BRaimbault wants to merge 29 commits into
Conversation
… plumbing Adds the Redux action/reducer for a per-layer dataTableColumnConfig field and wires it through favorites.js save/load and all layer loaders, mirroring the existing legendDecimalPlaces config-blob pattern. No UI yet.
getVisibleHeaders/getPinnedLeftOffsets in a new src/util/tableColumns.js, directly unit-tested, matching the filterSelection.js/tableSort.js pattern. Not yet wired into DataTable.jsx.
Computes visibleHeaders from dataTableColumnConfig, feeds it into useColumnWidths, and applies @dhis2/ui's built-in fixed/left sticky-column support for pinned columns. The checkbox column only becomes fixed when something else is pinned, since @dhis2/ui renders fixed cells as <th> instead of <td> - doing this unconditionally would break every existing Cypress td-index assertion. Also fires onHeadersChange with the full unfiltered header list for a future ColumnPicker to consume. CSS selectors that were td-only (dataCell/lightText/monoCell/selected/ hovered) now also match th, since a pinned column's cells render as <th>.
New popover, built on the existing FilterDropdownPopover shell and the same @dnd-kit drag-reorder pattern already used in LayersPanel.jsx (not the raw HTML5 drag-and-drop the original design sketch used). Dispatches setDataTableColumnConfig directly; not yet wired into BottomPanel.
Adds allHeaders state fed by DataTable's onHeadersChange, cleared immediately on layer switch to avoid briefly showing the previous layer's columns alongside the new layer's saved column config.
…cker favorites.spec.js: end-to-end cleanMapConfig round-trip for dataTableColumnConfig across thematic/earthEngine/TEI/geojson layer types, verified to actually depend on the validLayerProperties whitelist entry. ColumnPicker.spec.jsx: render-and-interact tests (disabled state, default visibility, toggle/pin dispatch with full config assertions, pinned-first ordering). Drag-reorder (onDragEnd) isn't covered - confirmed by direct experiment that dnd-kit's KeyboardSensor doesn't produce a usable drag in jsdom without much heavier mocking than is worthwhile here.
…us headers
React fires child effects before parent effects within the same commit.
DataTable's header-reporting effect (child) and BottomPanel's own
"reset allHeaders on layer switch" effect (parent) both fired on
mount/layer-switch; the parent's reset always ran second in that commit,
clobbering the real headers DataTable had just reported. Layer types with
a synchronous header computation (Thematic/OrgUnit/Facility) never got a
second chance to set it, leaving the picker's trigger button permanently
disabled - Event layers only worked because their extended-events loading
triggers a second, later header recompute that escapes the race.
Fix: track headers keyed by which layer produced them
(headersByLayer = {layerId, headers}, tagged by DataTable's own effect
closure, not a "latest activeLayerId" guess) and derive staleness at
render time via a plain comparison, instead of a second effect racing to
clear the same state.
Auto-generated by the i18n extraction tooling to include the new translatable strings introduced in ColumnPicker.jsx/BottomPanel.jsx.
Contributor
|
🚀 Deployed on https://pr-3724.maps.netlify.dhis2.org |
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Part of DHIS2-21456
Description
Adds a column picker to the data table toolbar for showing/hiding, pinning (freeze left), and reordering columns, and persists the configuration per layer in the map's saved favourite. Fourth in the data table improvement series, building on PR1's toolbar, PR2's selection sync, and PR3's filtering.
Column picker (
ColumnPicker)@dnd-kit, consistent with the drag-reorder already used inLayersPanel.jsx), and a pin button (freeze to the left of the table)document.bodyso it renders above the rest of the UI instead of being clipped by the popover's own positioned ancestorIconSync16already used elsewhere in the table), and a reset-to-defaults button that clears the saved config back to the default order/visibilityPinned columns in the table
fixed/left) cells using@dhis2/ui's built-in support, staying in place while the rest of the table scrolls horizontally<th>-vs-<td>DOM shape change for the common nothing-pinned casePersistence
dataTableColumnConfigfield on eachmapView, following the sameconfigJSON-blob pattern already used forlegendDecimalPlaces/legendIsolated/etc.:DATA_TABLE_COLUMN_CONFIG_SETreducer action, round-tripped throughfavorites.jsand every layer loader (thematic, event, org unit, facility, tracked entity, GeoJSON URL, Earth Engine) so column visibility/order/pinning survives reopening or sharing a saved mapFilter popover polish
react-virtuosocomponent that CSS's own intrinsic sizing can't see through) instead of the anchor column's width, so a wide column no longer forces an oversized dropdownToolbar polish
datatable/controls/, replacing one large block of inline JSX inBottomPanel.jsxBug fixes
Refactors (no behavior change)
getVisibleHeaders/getPinnedLeftOffsets) extracted intoutil/tableColumns.js, directly unit-tested, matching thefilterSelection.js/tableSort.jspattern from PR3FilterInput.jsx's pure filter/search/display-value logic and canvas text measurement extracted intoutil/filterInput.js(unit-tested); its self-contained help tooltip extracted intoFilterHelpTooltip.jsxDataTable.jsx's self-contained pieces (TopTooltip,SelectionFilterButton, theTableVirtuoso"components" glue) extracted into their own files; its pure row/sort/filterable-column helpers moved intoutil/dataTable.jsColumnPickerControl.jsx's row rendering extracted intoColumnRow.jsx; its column-key toggle/pin/reverse-selection logic and pinned-cell layout math moved intoutil/tableColumns.jsalongside the existing column helpers - this also removed a duplicated pinned-column-count calculation that had crept intoDataTable.jsxgetCssVarhelper, instead of hand-maintained duplicate constantsQuality checklist
Add N/A to items that are not applicable.
Screenshots
supporting images