- Shipped
- August 19, 2026 at 6:21 AM UTC
- Author
- Kamo
- Commit
- c71d60b
The page was the last screen still wearing the old look — a flat gradient bar, white cards, a centred spinner, alert() for every failure — while the rest of the console had moved to the instrument-panel language. It also threw away data the backend was already sending: each organization's own brand colour, its full domain list, its device policy. One idea carries the rebuild: the numbers are the filters. The old page had a row of counts and, separately, a row of filter chips restating the same predicates in different words — two controls to keep in sync and two chances to disagree about what "owned" means. A stat tile is now its own predicate, and both the count and the selection come from matchesFilter in the model. What the page gained: search across all six fields with the match marked (a secondary domain used to return nothing even while the card showed "+2 more" beneath it), / to focus it, four sorts, grid and dense-list views, pinning, and a detail drawer addressable as ?org=<id> — which is what let the cards get quieter, since the row no longer tries to show short title, alias, year, config, domain and display name at once in 0.7rem grey. View, sort, pins and recents persist in the member's ui-preferences, so the arrangement follows them between machines. Unsubscribe is wired to the endpoint that now exists, behind a typed confirmation: every other control here is reversible by the person using it and that one is not. The 1341-line file is now arrangement only. What an organization is, and every question the screen asks about one, lives in networkModel.ts under unit test; what the server is asked lives in hooks/. The three views read the same derivations, so they cannot drift into disagreeing about which organizations are reachable. Motion is real but quiet: staggered entry, layout reflow on filter and sort, one slow drift in the masthead, and the console's existing kmail skeleton instead of a spinner. All of it gated on prefers-reduced-motion. Three bugs found while writing it, each fixed here: comparing entering?.orgId to detailOrg?.id is undefined === undefined when both are absent, and then reads .mode off nothing; window.open with noopener returns null, so a pre-claimed tab could never be navigated (the opener reference is severed instead, which is the same protection); and a next-intl callback in the fetch effect's dependency chain could turn a re-render into a refetch loop, so the message helpers are read through a ref.