Skip to content

New column chooser#4409

Draft
haynesjm42 wants to merge 127 commits into
developfrom
new-column-chooser
Draft

New column chooser#4409
haynesjm42 wants to merge 127 commits into
developfrom
new-column-chooser

Conversation

@haynesjm42

Copy link
Copy Markdown
Member

Hoist P/R Checklist

Pull request authors: Review and check off the below. Items that do not apply can also be
checked off to indicate they have been considered. If unclear if a step is relevant, please leave
unchecked and note in comments.

  • Caught up with develop branch as of last change.
  • Added CHANGELOG entry, or determined not required.
  • Reviewed for breaking changes, added breaking-change label + CHANGELOG if so.
  • Updated doc comments / prop-types, or determined not required.
  • Reviewed and tested on Mobile, or determined not required.
  • Created Toolbox branch / PR, or determined not required.

If your change is still a WIP, please use the "Create draft pull request" option in the split
button below to indicate it is not ready yet for a final review.

Pull request reviewers: when merging this P/R, please consider using a squash commit to
collapse multiple intermediate commits into a single commit representing the overall feature
change. This helps keep the commit log clean and easy to scan across releases. PRs containing a
single commit should be rebased when possible.

haynesjm42 and others added 30 commits April 13, 2026 12:04
Add ColumnChooserModel, ColumnChooser, PinSectionModel, and PinSection as minimal shells with correct Hoist patterns. Export from desktop/cmp/grid/index.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement core ColumnChooser data flow: read target GridModel's column tree and columnState, build internal ColumnChooserRecord objects, and display them in three pin-zone grids (left, center, right) with checkbox toggles for visibility.

- Define ColumnChooserRecord interface for internal grid records
- Implement buildRecords() to walk GridModel columns recursively, handling both leaf Columns and ColumnGroups
- Create PinSectionModel with managed internal GridModel for each pin zone
- Wire reactive sync from target GridModel's columnState/columns to pin section grids
- Add visibility toggle via onCellClicked handler with Icon.checkSquare/square rendering
- Filter records by pin zone, excluding groups with no leaves in that zone

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Enable treeMode on each PinSectionModel's internal GridModel with isTreeColumn on the name column.
- loadRecords() now accepts a showGroups parameter: in tree mode it builds a nested children structure for AG Grid tree rendering; in flat mode it loads leaf records directly with no nesting.
- Added hasColumnGroups computed to ColumnChooserModel that checks whether the target grid has any ColumnGroup columns.
- syncFromGridModel() now passes showGroups to loadRecords(), and a new reaction re-syncs on showGroups change.
- ColumnChooser toolbar renders a tree/flat toggle button (omitted when no column groups exist).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a text input to the ColumnChooser toolbar that filters the column list by name. A debounced reaction applies a FilterTestFn to each PinSectionModel's store whenever `filterText` changes — leaf records match on name (case-insensitive contains), group records are kept when any of their descendant leaf columns match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shows the chooserDescription of the currently selected column in a styled panel at the bottom of the ColumnChooser. Adds reactions to ensure only one pin section (left/center/right) can have an active selection at a time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Enable AG Grid managed row dragging on each pin section grid so users can
reorder columns by dragging rows. On drag end, the new order is read from
AG Grid and pushed to the target GridModel via updateColumnState(). Also
exports row drag event types from kit/ag-grid and removes the sortBy
constraint that would conflict with managed row drag.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Enable dragging columns between pin zones (left, center, right) to change their pin state using AG Grid's addRowDropZone API. Each grid registers the other two as drop targets via getRowDropZoneParams. A MobX reaction watches for all three AG APIs to become available before wiring drop zones. Also adds min-height to pin sections so empty zones remain viable drop targets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…hooser

Adds a restore-defaults toolbar button that calls gridModel.restoreDefaultsAsync().
Conditionally hides left/right pin sections when they have no columns.
Adds CSS class modifiers (--center / --pinned) to PinSection for differentiated
styling. Updates SCSS with border, radius, background, section labels, and proper
flex sizing for center vs pinned zones.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use record.data.visible directly in checkbox renderer instead of cell value v, which is unreliable in treeMode
- Add explicit renderer for name column to read record.data.name, bypassing tree column ID-based values
- Add flex: 1 to grid in PinSection so it fills available space

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Sort records by sortOrder (from columnState) before loading into internal grids, both in flat mode (leaf sort) and tree mode (sort children within each group, sort root records)
- Add rendererIsComplex: true to visibility checkbox column to ensure AG Grid always re-renders when data changes, fixing stale checkbox state after toggles

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AG Grid's treeData mode sorts rows by tree path, overriding our columnState-based ordering. Switch to a flat grid where:
- Records are loaded in exact columnState order with a depth field
- Name column renderer applies left padding based on depth for visual hierarchy
- Group rows render in bold to distinguish from leaf columns
- Full control over row order without AG Grid tree sorting interference

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Walk columnState (display order) instead of the column definition tree. For each leaf
column, look up its parent group chain and create group instances as needed. Adjacent
columns sharing the same group merge under one group node; non-adjacent columns from
the same group produce separate split-group instances with unique IDs.

Also adds treeStyle: none and expandLevel: -1 to internal grids, renames
ColumnChooserRecord to ColumnChooserData, and fixes comments.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove PinSectionModel and PinSection — consolidate into a single grid owned
directly by ColumnChooserModel. Pin zone handling will be added back later.
Move all grid config (action column, tree column, sort, store) into ColumnChooserModel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use managed row drag (rowDragManaged) for visual feedback without any grid sort
  (sort was causing AG Grid to hide drag handles)
- Add dedicated drag handle column separate from tree column (agGroupCellRenderer
  suppresses rowDrag handles)
- Read new order from AG Grid on drag end via forEachNodeAfterFilterAndSort
- Fix StoreRecord data access: use node.data.data.isGroup/id (StoreRecord.data
  contains the raw data fields, not the StoreRecord itself)
- Append any excludeFromChooser columns to maintain complete columnState

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace ag-grid's managed row dragging with unmanaged mode using
suppressMoveWhenRowDragging and isRowValidDropPosition. This gives full
control over drop validation, shows a highlight indicator line during
drag, and computes the new column order on drop rather than reading
ag-grid's post-move display order.

Key changes:
- getValidDropPosition() validates drops, enforces lockColumnGroups
  constraints, prevents dropping groups inside themselves
- handleRowDragEnd() computes new columnState from drop target/position,
  with group merging/splitting handled automatically by buildRecords()
- Drag disabled while filter is active
- Fix setShowGroups declaration to use `declare` so it doesn't shadow
  the @bindable-generated prototype method
- Export IsRowValidDropPositionParams/Result and RowDropTargetPosition
  types from kit/ag-grid

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- IdlePanel - message to better explain rationale, full-width "I'm back" button + click handler on entire viewport.
- Admin metrics - autosize all rows so start-collapsed expands cleanly, use `segmentedControl` for three state source filter
The convention was previously framed as "plain ASCII in code comments," which is broader than
the actual concern. The motivating issue is em-dashes specifically - they cause encoding
friction with tooling (grep, MCP) and offer no benefit in monospace code. Other Unicode
characters (arrows, math symbols, accented letters) don't trip the same problems and can
aid clarity, so the rule shouldn't reject them by implication.

Updates `CLAUDE.md` bullet and the `Avoid Unicode in Code Comments` heading + body in
`docs/coding-conventions.md` to be explicit about this distinction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cleans out deprecation shims whose scheduled removal has come due. Replacements
have all shipped previously.

- `loadModel` getters on `HoistModel`, `HoistService`, `UrlStore`, `RestFormModel` (v82)
- `XH.appLoadModel` (v82)
- `GridModel.applyColumnStateChanges()` (v82)
- Static defaults setters on `GridModel`, `ChartModel`, `ExceptionHandler`, `FetchService` (v85)
- Filter helpers `withFilterByField`/`withFilterByKey`/`replaceFilterByKey`/`withFilterByTypes` (v85)

CHANGELOG and v85 upgrade notes updated; the upgrade notes carry the full
removed-to-replacement table for sweeping app code.
Synchronizes JSDoc on the load/refresh APIs across `Loadable`, `LoadSupport`,
`HoistModel`, and `HoistService` so MCP/CLI consumers see consistent, complete
descriptions on every entry point (interface JSDoc does not propagate through
`implements`, and `@param` content is stripped from MCP descriptions - so the
critical "passed directly, not wrapped in a config" footgun was previously
invisible to agents).

- `LoadSpec.meta` JSDoc clarifies the always-defined guarantee (defaults to
  `{}`); `LoadSpecConfig` gets interface-level JSDoc matching the `*Config`
  convention
- All four entry points (`loadAsync`, `refreshAsync`, `autoRefreshAsync`,
  `doLoadAsync`) now share identical wording across the four locations, with
  the asymmetry footgun and the `meta` semantics in the description
- `HoistModel.doLoadAsync` / `loadAsync` and parallel methods elsewhere link
  to the lifecycle doc anchor (`docs/lifecycle-models-and-services.md#loading-doloadasync`)
- Brief JSDoc added to `loadObserver`/`lastLoadRequested`/`lastLoadCompleted`/
  `lastLoadException` accessors on `HoistModel` and `HoistService` (previously
  surfaced empty in MCP)
- Normalize `loadAsync` parameter type to `LoadSpecConfig` on `Loadable`,
  `HoistService`, and `UrlStore` (was `LoadSpec | Partial<LoadSpec>`); now
  matches `HoistModel` and `LoadSupport`
- `core/README.md` Load Support section: new paragraph documenting `LoadSpec.meta`
  with caller/consumer example, plus a callout on the calling-shape asymmetry
  between `loadAsync` and `refreshAsync`/`autoRefreshAsync`
The v85 changelog, upgrade notes, and the version-compatibility matrix were pre-populated for an anticipated hoist-core 38.1 patch release that never shipped — hoist-core went 38.0 → 39.0 directly. v39 is the right "recommended pairing" for v85's tracing changes (both releases drop alwaysSampleErrors and add name-based sampleRules), and v85's hard minimum stays at 38.0.

- CHANGELOG: "hoist-core >= 38.1 is recommended" → "hoist-core >= 39.0 is recommended"
- docs/upgrade-notes/v85-upgrade-notes.md: same swap in Prerequisites
- docs/version-compatibility.md: v85 row Recommended/Max Tested 38.1 → 39.0; replaced phantom 38.1 entry in the Reverse Lookup table with a real 39.0 row noting the v39 features and that there's no hard hoist-react bump from 38.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
haynesjm42 and others added 16 commits June 4, 2026 13:21
# Conflicts:
#	CHANGELOG.md
#	appcontainer/AppContainerModel.ts
#	cmp/viewmanager/DataAccess.ts
#	core/HoistBase.ts
#	core/HoistService.ts
#	core/Span.ts
#	core/index.ts
#	core/load/LoadSupport.ts
#	core/load/Loadable.ts
#	core/model/HoistModel.ts
#	core/runner/RunContext.ts
#	core/runner/Runner.ts
#	core/runner/index.ts
#	core/types/Interfaces.ts
#	docs/version-compatibility.md
#	mcp/server.ts
#	svc/ConfigService.ts
#	svc/EnvironmentService.ts
#	svc/FetchService.ts
#	svc/IdentityService.ts
#	svc/PrefService.ts
#	svc/README.md
#	svc/TraceService.ts
#	svc/TrackService.ts
Comment thread cmp/grid/GridModel.ts
// Strip metadata other than id, hidden, and pinned state from hidden columns to save
// space when storing user configs with large amounts of hidden fields. Pinned state is
// preserved so a column's pin survives being hidden and is restored when it is shown again.
if (state.hidden) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I find the lack of symmetry between the three properties confusing.

@@ -0,0 +1,906 @@
/*

@lbwexler lbwexler Jun 17, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

  • should this be @internal, perhaps within grid/impl/ ColumnChooserModel also @internal as you have it and could go there?
  • could then promote ColumnChooser to /grid

@lbwexler

lbwexler commented Jun 17, 2026

Copy link
Copy Markdown
Member

Think it would be nice to call this new public component object 'ColChooser', to match with the existing public ColChooserConfig and GridModel.colChooser. Could we just extend that existing API, naming scheme right into this new public component?

@lbwexler lbwexler linked an issue Jun 27, 2026 that may be closed by this pull request
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.

Replace Desktop ColumnChooser with new GridEditor

7 participants