roostorg/coop — client

#563 (antd → lucide-react) follow-up

7 PRs opened this wave, plus every issue found while manually testing the icon migration.

Shalabh Agarwal · 2026-09-15

ISSUE 1

Location Bank create doesn't redirect back

On successful create, the form's onCompleted handler never calls navigate(...) — the UI stays parked on the create form instead of returning to the banks list.

client/.../LocationBankForm.tsx#L126-L145onCompleted missing navigate
repro, then fix
Repro
Create a Location Bank → save succeeds → form stays put instead of returning to the list.
Fix
Same flow after the fix — navigates back to the banks list on success.
ISSUE 2

Recent Decisions search triggers password-manager autofill

The user-search box has autoFocus and a placeholder containing "username" — classic password-manager heuristics (Bitwarden, 1Password) fire an inline autofill prompt on page load for a plain search field.

Fixed locally as luyrxzpk — needs a PR. Confirmed pre-existing on main, not a #563 regression.
client/.../ManualReviewRecentDecisions.tsx#L933-L949placeholder="...username" + autoFocus
repro screenshot
Repro
Page load → Bitwarden/1Password inline icon fires on the search box.
Fix — not captured yet
Fixed locally (luyrxzpk: reworded placeholder, dropped autoFocus) — no verify capture yet.
ISSUE 3

Recent Decisions pagination has no bounds check

The "next page" chevron calls handleNext() unconditionally — no disabled tied to result count or a hasNextPage field, so you can page past the last result indefinitely.

client/.../ManualReviewRecentDecisions.tsx#L1109-L1113ChevronRight onClick={() => handleNext()}
repro, then fix
Repro
1 row of data — paging past page 1 keeps going, re-querying empty pages.
Fix
Both bounds check and the off-by-one lag are fixed.
ISSUE 4

Sidebar Settings submenu never auto-closes

The submenu's useEffect only ever sets isSettingsMenuExpanded to true when a settings route is selected — nothing flips it back to false on navigate-away or outside click.

client/src/components/Sidebar.tsx#L250-L254 — effect only ever sets true
repro, then fix
Repro
Open Settings, click any other nav item — submenu stays expanded.
Fix
Collapses on navigate-away and on outside click (16/16 tests).
ISSUE 5

TextTokenInput loses pending text on direct Save

Pending token text only committed on Enter or a document-level click-outside — clicking "Save Changes" fires the click-outside handler after the button's own click handler reads a stale strings closure, so the just-typed value never reaches the mutation.

PR: github.com/roostorg/coop/pull/1148 — shared component, also used by Location/Media/Text bank forms and queue-routing conditions.
client/.../TextTokenInput.tsx#L100-L120<input> has no onBlur
repro, then fix
Repro
Type a matching string, click Save directly — the string is silently dropped.
Fix
onBlur flushes the pending token before Save reads state.
ISSUE 6

Useless generic error when HMA is unreachable

With HMA down, the fetch rejects (ECONNREFUSED) before the response-status check runs. The resolver's catch only maps one known error type; everything else becomes a generic GraphQL error, and the client discards the real message for a hardcoded "please try again."

Fixed locally as ullwxrty — typed HMAUnavailableError server-side, real message surfaced client-side. Needs a PR.
server/services/hmaService/index.ts#L204createBank(), unmapped fetch failure client/.../HashBankForm.tsx#L252-L257 — hardcoded error copy, real error discarded
repro, then fix
Repro
HMA down → generic "please try again" — retrying never helps.
Fix
Real, actionable error message surfaced.
ISSUE 7

Blurred-video player overflows its rounded frame

ReactPlayer's wrapper renders default inline 640×360; the component only constrained max-height, and maxWidth/maxHeight defaulted to Infinity (invalid CSS, silently ignored) — video spills past the rounded/shadowed card.

client/.../ManualReviewJobContentBlurableVideo.tsx#L80-L81style={{ display:'flex', maxWidth, maxHeight }}
repro, then fix
Repro
VIDEO-field job → player extends past the rounded/shadowed frame.
Fix
Reworked to a responsive player — scales to card, object-fit: contain.
ISSUE 8

Rules dashboard table doesn't use available width

Table wrapper defaults to w-fit-style sizing across 8 dashboard pages (Rules, Reporting Rules, Item Types, Actions, all 3 bank types, Manage Users) — leaves large dead space on wide viewports.

PR: github.com/roostorg/coop/pull/1172 — touches all 8 files, same pattern each place.
client/.../RulesDashboard.tsx#L523 — representative <Table ...> call
repro screenshot, then fix video
Repro
Table hugs its content width, leaving dead space on the right.
Fix (verify)
Table fills the available width across all 8 pages.
ISSUE 9

Item Type editor — duplicate DOM ids on checkboxes

"Required" and "Hidden" checkboxes per custom field both used a static id, so every field row collided, breaking label-click association and a11y past the first field. Closes issue #93.

client/.../ItemTypeFormCustomField.tsx#L168-L181 — static id="required-checkbox" / id="hidden-checkbox"
repro, then fix
Repro
Add a second custom field — clicking its "Required" label toggles the first field's checkbox.
Fix
Ids scoped per-field — 2/2 tests pass, user-verified.
ISSUE 10

Text Bank can be created with an empty / whitespace-only name

Nothing on any layer requires a non-empty name — client submit is gated only on edit permission, the resolver and service pass name straight through, and the DB column is NOT NULL but '' satisfies that. Audit found the gap is systemic across 9 config-entity forms (Hash Bank, Item Type, MRT Queue, etc.) with no server-side guard anywhere.

Fixed locally across two branches — fix-blank-entity-names (server, 24 resolvers) and fix-blank-entity-names-client (client, 8 files) — both unpushed. Needs PRs.
client/.../TextBankForm.tsx — create button has no name check server/graphql/modules/textBank.ts#L78createTextBank forwards name unchecked
repro
Repro
Create Text Bank with Name left blank — succeeds, blank-name row shows in the list.
Fix — not captured yet
Fixed locally (server + client branches, unpushed) — no verify capture yet.