refactor(management): the manager pages ask a domain - #1210
Conversation
The four manager pages read the generated client directly, which frontend ADR-001 forbids and #1183 listed as debt. The user domain gains what they read: the listing, one account, the deleted accounts, the memberships, the addresses, and the delete. Committees and recovery get a domain each, because a committee list is not the user domain's business and neither is which activation an account is waiting for. The adapters throw on a refusal rather than answering with an empty list. Three of the four pages already treated a failed read that way; AddressManager and RecoveryManager logged to the console instead, which tells a board member the association has nobody in it. All four now report through $handleNetworkError. The tests move with the pages. They mocked the client the pages no longer call, and now stand in for the door each page actually depends on — which also means they assert an intention, deleteUser(71), rather than a request shape, {path: {userId: 71}, throwOnError: true}. Fifty-one files left on the list, from fifty-five. Part of #1167
|
Carried forward from the old file, so worth catching while this page is open: lines 138 and 205 bind The handlers therefore never run, so Tracked as #1211. I am not opening a competing PR since this file is yours right now — either fix it here and close #1211, or say and I will take it once this lands. Found while diagnosing #1042, which turned out to be unrelated (a click landing on the wrong element mid-transition, fixed in #1212). |
`RecoveryManagerHelper.openSection` clicked the toggle and returned. Under `v-expand-transition` the pane shows at about two pixels and grows for some 280ms, and a row inside it holds one bounding box long enough for Playwright to call it stable — so a restore click is delivered to whatever has arrived at those coordinates once the pane moves on. The action is never entered, nothing is refused, and no request is made. That is what `board deletes user from member manager and restores in recovery manager` failed with on #1210: the row was there, the click landed, and the request log ends with the pane's own reads. #1212 proved the shape on the committee panel and left ExpandPanelHelper behind for it. The pane gains a test id so the same wait can be used here. Refs #1141
Third slice of #1167.
Why
AddressManager,CommitteeManager,RecoveryManagerandUserManagerread the generated client directly. ADR-001 forbids it, and #1183 listed all four as debt.How
domains/usergains what these pages read:listUsers,readUser,listDeletedUsers,listMemberships,listAddresses,deleteUser.Two new domains, because the alternative was putting them somewhere they do not belong:
domains/committeesfor the committee list and its removal, anddomains/recoveryfor which activation an account is waiting for. A committee is not the user domain's business, and neither is a recovery token's purpose.A behaviour change worth naming
The adapters throw on a refusal rather than answering with an empty list.
CommitteeManageralready worked this way — it passesthrowOnError: true, catches, and reports through$handleNetworkError, and it distinguishes "could not be read" from "there are none".AddressManagerandRecoveryManagerdid not: they checkedstatus === 200and otherwise calledconsole.log. A board member with a failed read saw an association with nobody in it and no indication anything had gone wrong.All four now report. That is a small, deliberate improvement rather than a pure move, and it is why two tests changed from asserting
console.logto asserting the handler.The tests moved with the pages
They mocked the client the pages no longer call. Each now stands in for the door its page depends on, which is also the boundary that matters when the domain's internals change.
A side effect worth having: the assertions stopped naming request shapes.
expect(mockDeleteUserById).toHaveBeenCalledWith(71)says what the page meant;{path: {userId: 71}, throwOnError: true}said how the client spells it, and would have had to change again the next time the wire did.Verification
yarn vitest run— 189 files, 1627 tests.yarn typecheckandeslintclean.grep -rl "@/services/api" src/pages/managementreturns nothing, including theimport("@/services/api").MembershipResponseinline type annotation that a file-level grep would have missed.Debt list: 55 → 51.
Diff breakdown —
█added░removed, scaled to the largest row.