Bulk Action Bar: multi-select delete / lock / color across list menus#1513
Open
spencerpruitt wants to merge 5 commits into
Open
Bulk Action Bar: multi-select delete / lock / color across list menus#1513spencerpruitt wants to merge 5 commits into
spencerpruitt wants to merge 5 commits into
Conversation
Add a shared "Bulk Options" bar to every list-style overview/editor (States, Cultures, Religions, Regiments, Markets, Burgs, Provinces, Markers, Routes, Zones). It reveals per-row checkboxes plus a filter-aware select-all, then applies Delete / Lock / Unlock / Set color to the current selection. - New src/controllers/bulk-action/ module: pure BulkSelection, a per-type BulkEntityAdapter seam, BulkActionBar DOM glue, and bulkDeleteConfirm. - Bulk delete reuses each type's single-delete cascade; migrated types share a pure *-cascade.ts with their editor so single and bulk delete cannot diverge. Locked rows are protected from bulk delete and reported as skipped. States/Provinces offer an optional "also delete contained burgs" choice. - Legacy public/modules/ui menus attach via a window.bulkBars bridge (the existing window.X cross-layer pattern); migrated TS menus attach directly. - Replaces the ad-hoc Burgs "Remove All" and Zones erase-mode controls. - Route gains an optional lock field so routes can be bulk locked/unlocked. - ~260 unit tests cover selection, every adapter, and every cascade. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
✅ Deploy Preview for afmg ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Owner
|
Hello. Some issues I see:
|
Author
|
Owner
|
I'd rather keep the change contained in existing controllers. Abstraction into a fixture is fine, but controller functions should still be in controllers, just passed to the fixture. When migration is done (timeline doesn't exist), it can be done cleared. Also would need to improve the UI, the current one takes too much space and attention (should probably be just a single button in the bottom section, just like other buttons) |
Address PR Azgaar#1513 review (Azgaar): - Move each migrated menu's bulk logic (delete cascade, summary, predicates) out of the generic bulk-action/adapters/ fixture and into its own controller domain (states/cultures/religions/regiments/markets). The controller now assembles its BulkEntityAdapter inline and passes it to the BulkActionBar; only the generic seam stays under bulk-action/. Pure cascade logic remains unit-tested. - Replace the full-width top toolbar with a single icon button in each menu's footer button row; toggling it reveals row checkboxes plus inline footer actions (delete/lock/unlock/color) and Select-all + count. Legacy-JS adapters and the window.bulkBars bridge stay as-is (cleanup deferred to the JS->TS migration, per review). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a Rivers bulk adapter (select + delete only; rivers have no lock/color) wired through the existing window.bulkBars bridge, and a footer bulk button in the Rivers overview. Delete delegates to the global Rivers.remove (which also removes tributaries and is a no-op on an already-removed id). The existing 'Remove all rivers' button is kept. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…edesign Make the PRD concise (per PR review), and update the architecture note and glossary term to reflect the footer-button UI and the adapters-live-in-controllers layout, plus the new Rivers menu. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Correctness (from high-effort review of the PR diff): - Guard bulk Delete/Lock/Set-color with the global `customization` flag (like single-delete), and make `.bulkInline[hidden]` use `!important` + clear leftover inline display on toggle. The bulk controls live in a footer span, but editors toggle footer visibility via `#xBottom > button`/`> *`, which left the controls clickable during manual-assignment modes and could force-reveal them on exit. - Rivers bulk-delete confirmation now counts the whole basin Rivers.remove purges (parent/basin matches), not just the selected rows, so it no longer understates the deletion. Regression test added. Cleanup: - Extract the `plural` helper (copy-pasted 11x) into src/utils/stringUtils.ts and import it everywhere, removing the duplication this PR had deepened. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
|
Pushed an update:
|
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.
Summary
Adds a shared, reusable Bulk Action Bar to every list-style overview/editor dialog, so multiple entities can be selected and acted on at once instead of one row at a time. Each menu gains a top-right "Bulk Options" toggle that reveals per-row checkboxes plus an inline toolbar with Delete / Lock / Unlock / Set color (color only where the entity type has one). Selection is scoped to the open menu.
Covers all ten list menus: States, Cultures, Religions, Regiments, Markets (TS controllers, direct attach) and Burgs, Provinces, Markers, Routes, Zones (legacy
public/modules/uiJS, via awindow.bulkBarsbridge).Motivation
Acting on entities one at a time is tedious — deleting twelve states means twelve trash clicks and confirmations. Two menus had grown inconsistent one-off shortcuts (Burgs "Remove All", a Zones erase-mode toggle) that existed nowhere else and were all-or-nothing. This unifies everything behind one consistent, filter-aware, multi-select control and removes those ad-hoc controls.
How it works
New module
src/controllers/bulk-action/:bulk-selection.ts— pure, DOM-freeBulkSelectionwith acanSelectpredicate that keeps non-deletable rows (e.g. neutral state 0) out of any selection.bulk-entity-adapter.ts— the per-typeBulkEntityAdapterseam (the only type-specific code).bulk-action-bar.ts— DOM glue; one instance per menu; re-syncs after each list re-render. The toolbar persists across actions and keeps the selection (deleted rows drop off), so actions chain.bulk-delete-confirm.ts— confirmation dialog built from a cascade summary, with achildKind-gated "also delete contained burgs" checkbox (States/Provinces) whose summary updates live.adapters/— one adapter per type.Two attach paths. Migrated TS menus construct a
BulkActionBardirectly. Legacy JS menus can't import ES modules, so they reach it throughlegacy-bridge.ts, which registerswindow.bulkBars— the samewindow.Xcross-layer pattern already used forwindow.COA,window.tip,window.ensureEl. A legacy menu callswindow.bulkBars.mount(type, {redraw})on open andwindow.bulkBars.sync(type)after row-render. The bridge is a deliberate, temporary seam: a menu drops it for the direct-import path once migrated to TS.Cascade fidelity. Bulk delete reuses each type's existing single-delete cascade. For migrated types the single-delete data mutations were extracted into a pure
*-cascade.tsnow shared by both the editor's single delete and the adapter's bulk delete (States/Cultures/Religions/Regiments), so the two can't diverge. Provinces' single delete was a legacy closure that couldn't be imported, so its mutations are reimplemented in the adapter and matched against the original. Burgs/Markers/Routes/Zones/Markets delegate to their existing remove functions.Safety. There is no undo, so locked rows are protected from bulk delete and reported as skipped in the confirmation, which also summarizes the cascade (entities removed, dependents reassigned/removed, child burgs deleted when that option is set).
Removed (with no lost capability)
triggerAllBurgsRemove→ reproduced by "select all → Delete".zonesRemove), itsdragZoneBrusherase branch, and its orphaned Ctrl hotkey handler.Tests / checks
BulkSelection, every adapter, and every cascade (cascade summaries, lock-resists-delete, child-burg counts).vitest rungreen,tsc --noEmitclean,npm run buildclean,biome checkclean.Notes
Routegains an optionallock?: booleanso routes can be bulk locked/unlocked.docs/architecture/architecture.md(the bridge) anddocs/prd/bulk-action-bar.md; a glossary term was added.🤖 Generated with Claude Code