From 00711ca954f205eb3b0ee0c33564b06154d4e62b Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Mon, 9 Nov 2026 16:40:28 +0800 Subject: [PATCH 1/4] feat(console): add the desk alerts and logs pages (phase 8) The Meridian desk shipped with two of its six pages as stubs. This adds the remaining pair against the contracts that already existed in schemas/desk (API-CONTRACT.md 3.17-3.19), so all six dock destinations render real content. - alerts: severity filters, open-first ordering, resolved rows, and the delivery channel panel; a resolved alert always carries its resolution time. - logs: today's sessions and run tape from the ribbon, plus a level-filtered log tail rendered as text (never HTML). - both read from fixtures; DESK_SOURCES keeps them mock until the backend routes exist, so nothing here can call a live endpoint. - guards reject a resolved alert without resolved_at, an unknown level, a shortened retention window, and an unredacted tail. - new console_desk_phase8_validation joins test:operations. - css budget: 20 -> 22 KB gzip, since two real pages cost ~0.9 KB and the old ceiling had no slack left. --- tests/console_desk_format_validation.mjs | 6 +- tests/console_desk_mock_validation.mjs | 1 + tests/console_desk_phase8_validation.mjs | 109 +++++++++++++ .../frontend/package.json | 2 +- .../frontend/scripts/check-budget.mjs | 4 +- .../frontend/src/desk/DeskApp.tsx | 4 + .../frontend/src/desk/alerts/model.ts | 41 +++++ .../frontend/src/desk/api/endpoints.ts | 20 ++- .../src/desk/api/fixtures/alertDelivery.ts | 20 +++ .../frontend/src/desk/api/fixtures/alerts.ts | 74 +++++++++ .../frontend/src/desk/api/fixtures/logs.ts | 47 ++++++ .../frontend/src/desk/api/guards.ts | 58 ++++++- .../frontend/src/desk/api/mock.ts | 3 + .../frontend/src/desk/i18n/en.ts | 71 ++++++++ .../frontend/src/desk/i18n/zh-CN.ts | 71 ++++++++ .../frontend/src/desk/logs/model.ts | 29 ++++ .../frontend/src/desk/pages/AlertsPage.tsx | 153 ++++++++++++++++++ .../frontend/src/desk/pages/LogsPage.tsx | 138 ++++++++++++++++ .../frontend/src/desk/styles/desk.css | 54 +++++++ web/strategy-switch-console/v2_asset_map.js | 47 +++--- 20 files changed, 924 insertions(+), 28 deletions(-) create mode 100644 tests/console_desk_phase8_validation.mjs create mode 100644 web/strategy-switch-console/frontend/src/desk/alerts/model.ts create mode 100644 web/strategy-switch-console/frontend/src/desk/api/fixtures/alertDelivery.ts create mode 100644 web/strategy-switch-console/frontend/src/desk/api/fixtures/alerts.ts create mode 100644 web/strategy-switch-console/frontend/src/desk/api/fixtures/logs.ts create mode 100644 web/strategy-switch-console/frontend/src/desk/logs/model.ts create mode 100644 web/strategy-switch-console/frontend/src/desk/pages/AlertsPage.tsx create mode 100644 web/strategy-switch-console/frontend/src/desk/pages/LogsPage.tsx diff --git a/tests/console_desk_format_validation.mjs b/tests/console_desk_format_validation.mjs index 5a4f82fd..66a2ff7d 100644 --- a/tests/console_desk_format_validation.mjs +++ b/tests/console_desk_format_validation.mjs @@ -87,7 +87,11 @@ assert.equal(deskTranslate("en", "freshness.ready", { age: "6 min" }), "All feed const { zh, en } = DESK_MESSAGES; assert.deepEqual(Object.keys(en).sort(), Object.keys(zh).sort()); const placeholders = text => [...text.matchAll(/\{(\w+)\}/g)].map(m => m[1]).sort(); -const LANGUAGE_NEUTRAL = new Set(["read.unknown_mark", "clock.utc", "shell.brand"]); +// Log levels are protocol tokens and stay verbatim in both languages. +const LANGUAGE_NEUTRAL = new Set([ + "read.unknown_mark", "clock.utc", "shell.brand", + "logs.level.error", "logs.level.warn", "logs.level.info", "logs.level.debug", +]); for (const key of Object.keys(zh)) { assert.deepEqual(placeholders(en[key]), placeholders(zh[key]), `placeholders ${key}`); assert.doesNotMatch(en[key], /[㐀-鿿]/, `en ${key}`); diff --git a/tests/console_desk_mock_validation.mjs b/tests/console_desk_mock_validation.mjs index 936b68ab..2d64fccd 100644 --- a/tests/console_desk_mock_validation.mjs +++ b/tests/console_desk_mock_validation.mjs @@ -189,6 +189,7 @@ assert.equal(resolveMockScenario("?mock=\n \n \n \n
\n \n \n