fix(client): give the portal row an icon, and assert every gated nav has one
All checks were successful
PR Checks / server-tests (pull_request) Successful in 19s
PR Checks / client-build (pull_request) Successful in 8m49s

The §7.7 smoke, running the pair together: registering the player row without an
`icon` blanked the whole portal with React error #130, because core's
PlayerPortalLayout rendered `<n.icon />` unguarded. Core is guarded now
(website), and this is the other half — the row had an icon before it moved and
should have kept one.

A second glyph rather than reusing IconShard: these two rows sit in different
navs and each matched its neighbours before the extraction. The admin sidebar's
UO rows were gems; the portal's Characters row was a person beside Appeals'
shield and Account's gear. Matching the nav a row lands in is the whole reason
`icon` is in the contract.

`registration.test.js` now asserts it for admin AND player rows, which is the
cheap place to catch the next one. The public header is text buttons and is
deliberately excluded.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-11 18:54:42 -05:00
parent e4af7dd9a8
commit 9d559091c5
3 changed files with 45 additions and 5 deletions

View File

@@ -139,9 +139,21 @@ it('every nav row points at a route this module actually registered', () => {
}
})
it('admin nav rows carry an icon; core rows all have one and a text-only row reads as breakage', () => {
for (const row of registered.nav.admin) {
assert.equal(typeof row.icon, 'function', `admin nav row "${row.label}" has no icon`)
it('every admin and player nav row carries an icon', () => {
// Both of those navs render a glyph on every core row, so a row without one
// reads as breakage rather than as a design. The PUBLIC header is text
// buttons and is deliberately excluded.
//
// The player half of this assertion is not symmetry for its own sake. Core's
// PlayerPortalLayout rendered `<n.icon />` UNGUARDED — fine for as long as
// every row in it was core's own and had one, and React error #130 with a
// blank portal the moment a module registered one without. Core is guarded
// now, but a missing icon there is still a visible defect and this is the
// cheap place to catch it.
for (const area of ['admin', 'player']) {
for (const row of registered.nav[area]) {
assert.equal(typeof row.icon, 'function', `${area} nav row "${row.label}" has no icon`)
}
}
})