[MPDX-9693] - Add bulk actions menu to MPD Goal Admin table - #1980
[MPDX-9693] - Add bulk actions menu to MPD Goal Admin table#1980wjames111 wants to merge 9 commits into
Conversation
More Actions is now always visible and disabled until a row is checked, with Print All (still inert until MPDX-9702), Run & Send Selected, and Assign Coach as its items. Run and Send All stays a standalone button. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bundle sizes [mpdx-react]Compared against 5f0edc3 No significant changes found |
wjames111
left a comment
There was a problem hiding this comment.
Multi-Agent Code Review
Verdict: APPROVED WITH SUGGESTIONS — no blockers. 5 medium-priority improvements posted as line comments; lower-severity suggestions listed below. Risk LOW (blast radius 1, complexity 1, sensitivity 1, recoverability 0). Dependency analysis found no breaking changes — all fan-in stays inside the MpdGoalAdmin module.
5 specialized agents (Architecture, Testing, UX, Standards, Financial Reporting) reviewed the diff, then cross-examined each other's findings with a rebuttal round. Jest (51/51), eslint, and tsc were verified green on this checkout.
Suggestions (severity < 5.0 — informational, no /dismiss needed)
- Nested
t()composition (4.5) —t('{{count}} Selected Staff')is interpolated into the modal'st('Assign Coach for {{name}}')(GoalsTableToolbar.tsx:165-169). Translators get two fragments they can't reorder/inflect. Consider atitleoverride prop with one full sentence per case. - Missing cancel-path test (4.5) — nothing pins that closing
AssignCoachModalleaves the selection and coaches untouched. - State naming (4.0) — with three modal-ish states in the file,
modalOpen/modalTargetwould read better asrunAndSendOpen/runAndSendTarget. - JSDoc overpromise (4.0) —
assignCoachsays "across all cohorts" but the selection model makes cross-cohort ids impossible (selection clears on cohort switch); soften the comment. DynamicAssignCoachModalfollow-up (3.5) — the written lazy-modal rule applies, but converting only this PR's import splits zero bytes becauseGoalsTable.tsx:25(pre-existing, MPDX-9699) also statically imports the modal. A follow-up converting both call sites would actually split Formik+Yup out of the page chunk (template: siblingDynamicEditTrainingCostsModal.tsx).- Snapshot the assign target (3.5, latent) —
handleAssignCoachreads liveselectedRowswhile the run-and-send path deliberately snapshots intomodalTarget(see its comment). Harmless today (the dialog is focus-trapped), but becomes reachable once MPDX-9914 makes selection async. Apply the same snapshot idiom. - Silent
!coachguard (3.5) —GoalsTableToolbar.tsx:63-66no-ops with no feedback; unreachable today (options and lookup sharemockCoaches) but becomes a real silent-failure path when coaches come from a query. - Type placement (3.5) —
mockData.tsimportsAssignCoachOptionfrom a component; the feature's shared types live inmpdGoalAdminHelpers.ts. - Save-click guard (3.0) — the bulk-assign test clicks Save without the
waitFor(() => expect(saveButton).toBeEnabled())guard its siblingAssignCoachModal.test.tsxuses. Deterministic-green today (verified 5 consecutive runs); robustness nit. - Menu a11y polish (2.5) — optional:
useId()-derivedid+aria-controls+MenuListProps aria-labelledby, perCsvExportMenu.tsx. No written rule requires it andMassActionsDropdownships without it. - Misc (3.0-3.5) —
aria-live="polite"on the{{count}} selectedtext;flexWrap: 'wrap'on the actions Box for xs viewports.
Debate notes (findings raised then withdrawn/refuted)
- Translation key placement — withdrawn after empirical verification: the hand-placed keys match the catalog's actual sort (base-key localeCompare, plural suffixes grouped); this PR adds zero new sort inversions.
- Success snackbar — withdrawn: every bulk action in the repo toasts on success, and with pagination the toast is the only feedback for off-page rows. The toast is correct here.
- Print All gating — reduced to a labeling/scope question for MPDX-9702 (the item is inert in every selection state; repo mass-action precedent hides bulk menus entirely without a selection).
Findings on Related Files (Not in This PR)
These are informational — they do not count toward the verdict.
[Pre-existing] src/components/HrTools/MpdGoalAdmin/GoalsTable/GoalsTable.tsx:49 — assignableCoaches: AssignCoachOption[] = [] + no-op handler make the per-row Assign Coach modal impossible to complete (see the mockData.ts line comment for the full finding — the fix belongs there or in MPDX-9699/9914).
[Pre-existing] public/locales translation catalog — 'Assign Coach for {{name}}' and 'Select a coach' (from MPDX-9699 / #1897) were never added to translation.json, so the modal title renders untranslated in all locales.
[Pre-existing] GoalsTable.tsx:160,172 — "disabled until wired up (MPDX-9696)" cites the completed scaffolding ticket; these two controls (View/Edit link, row actions button) need forward-looking ticket refs like the ones this PR added.
[Pre-existing] RunAndSendModal usage — always-mounted with open={modalOpen} (GoalsTableToolbar.tsx:156-162), against the lazy-modal rule's "mount only while open" guidance; predates this PR.
…ckData.ts:6 Wire GoalsTable per-row Assign Coach to mockCoaches and the context assignCoach so the modal is completable Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…alsTableToolbar/GoalsTableToolbar.tsx:148 Demote 'Run and Send All' to outlined while rows are selected so only one contained CTA is on screen Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…alsTableToolbar/GoalsTableToolbar.test.tsx:81 Add test proving Run and Send All targets all filtered rows, not the selection Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…alsTableToolbar/GoalsTableToolbar.test.tsx:106 Add an overwrite warning to AssignCoachModal listing staff whose existing coach will be replaced, wired from the toolbar's bulk assign Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dGoalAdminContext.test.tsx:86 Assert row-3's coach as the literal 'Nelson Jones' instead of comparing against the shared mockCohorts fixture, which the provider mutates by reference Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
user-event v13 calls are synchronous, and the repo rule is to never await them; only the PR's files are touched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Description
assignCoachhelper toMpdGoalAdminContextand amockCoacheslist. Real mutation wiring is MPDX-9914 (assignCoach) and MPDX-9912 (Run & Send).Related: MPDX-9693
Testing
Checklist:
/quality:agent-reviewcommand locally and fixed any relevant suggestions🤖 Generated with Claude Code