feat(n7web): add pet settings and day night themes

This commit is contained in:
Miayui
2026-09-14 17:12:08 +08:00
parent aa6f59d3a6
commit 58f1a2da42
13 changed files with 901 additions and 114 deletions
+11 -11
View File
@@ -807,7 +807,7 @@ operations:
def test_static_console_and_runtime_endpoint(self) -> None:
with self.opener.open(f"{self.base_url}/", timeout=3) as response:
html = response.read().decode("utf-8")
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-136", timeout=3) as response:
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-139", timeout=3) as response:
app_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/gesture-control.js?v=android-pad-9", timeout=3
@@ -834,11 +834,11 @@ operations:
) as response:
speech_worklet = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/self-extension.js?v=pet-acrylic-48", timeout=3
f"{self.base_url}/self-extension.js?v=pet-settings-49", timeout=3
) as response:
extension_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/self-extension.css?v=pet-acrylic-48", timeout=3
f"{self.base_url}/self-extension.css?v=pet-settings-49", timeout=3
) as response:
extension_styles = response.read().decode("utf-8").replace("\r\n", "\n")
with self.opener.open(
@@ -854,7 +854,7 @@ operations:
) as response:
energy_styles = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/codepen-glass-theme.css?v=creative-cloud-1", timeout=3
f"{self.base_url}/codepen-glass-theme.css?v=creative-cloud-2", timeout=3
) as response:
glass_theme = response.read().decode("utf-8")
with self.opener.open(
@@ -887,7 +887,7 @@ operations:
self.assertIn("CMD 0x431 · FB 0x41A · CH1", html)
self.assertIn("CMD 0x431 · FB 0x388 · CH1", html)
self.assertNotIn("透明车体 · 实体设备", html)
self.assertIn('src="/app.js?v=dual-seat-136"', html)
self.assertIn('src="/app.js?v=dual-seat-139"', html)
self.assertIn('href="/styles.css?v=dual-seat-23"', html)
self.assertIn('src="/gesture-control.js?v=android-pad-9"', html)
self.assertNotIn('class="vehicle-system-hud"', html)
@@ -900,8 +900,8 @@ operations:
self.assertIn('<body class="console-v2">', html)
self.assertIn('id="v2BootScreen"', html)
self.assertIn('正在加载车机控制与实时状态', html)
self.assertIn('src="/self-extension.js?v=pet-acrylic-48"', html)
self.assertIn('href="/self-extension.css?v=pet-acrylic-48"', html)
self.assertIn('src="/self-extension.js?v=pet-settings-49"', html)
self.assertIn('href="/self-extension.css?v=pet-settings-49"', html)
self.assertNotIn("self-calibration", html)
self.assertNotIn("self-repair", html)
self.assertNotIn("self-evolution", html)
@@ -912,7 +912,7 @@ operations:
self.assertIn('src="/assistant-chat.js?v=codex-assistant-32"', html)
self.assertIn('href="/energy-monitor.css?v=energy-monitor-4"', html)
self.assertIn('src="/energy-monitor.js?v=energy-monitor-4"', html)
self.assertIn('href="/codepen-glass-theme.css?v=creative-cloud-1"', html)
self.assertIn('href="/codepen-glass-theme.css?v=creative-cloud-2"', html)
self.assertIn("--glass-shell:", glass_theme)
self.assertIn("backdrop-filter: blur(22px) saturate(1.25)", glass_theme)
self.assertNotIn('"admin"', console_script)
@@ -1194,14 +1194,14 @@ operations:
self.assertIn("CAN 指令已提交,等待车辆状态确认", console_script)
self.assertIn('canvas.addEventListener("webglcontextlost"', app_script)
self.assertIn('"cognitive-agent:module-change"', app_script)
self.assertIn('const CACHE_VERSION = "cognitive-agent-pad-v298"', service_worker)
self.assertIn('const CACHE_VERSION = "cognitive-agent-pad-v302"', service_worker)
self.assertIn('/console-v2.css?v=delivery-state-69', service_worker)
self.assertIn('/console-v2.js?v=local-first-70', service_worker)
self.assertIn('/assistant-chat.css?v=codex-assistant-28', service_worker)
self.assertIn('/assistant-chat.js?v=codex-assistant-32', service_worker)
self.assertIn('/energy-monitor.css?v=energy-monitor-4', service_worker)
self.assertIn('/energy-monitor.js?v=energy-monitor-4', service_worker)
self.assertIn('"/app.js?v=dual-seat-136"', service_worker)
self.assertIn('"/app.js?v=dual-seat-139"', service_worker)
self.assertIn('"/speech-input.js?v=sensevoice-13"', service_worker)
self.assertIn('"/speech-input.css?v=sensevoice-7"', service_worker)
self.assertIn('"/speech-audio-worklet.js?v=sensevoice-5"', service_worker)
@@ -1658,7 +1658,7 @@ operations:
) as response:
extension_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/app.js?v=dual-seat-136", timeout=3
f"{self.base_url}/app.js?v=dual-seat-139", timeout=3
) as response:
app_script = response.read().decode("utf-8")
@@ -19,7 +19,7 @@ def test_console_contains_ai_assistant_surface():
def test_codex_assistant_assets_are_versioned_together_in_the_service_worker():
service_worker = (ROOT / "apps/web-console/service-worker.js").read_text(encoding="utf-8")
assert 'const CACHE_VERSION = "cognitive-agent-pad-v298"' in service_worker
assert 'const CACHE_VERSION = "cognitive-agent-pad-v302"' in service_worker
assert '"/assistant-chat.css?v=codex-assistant-28"' in service_worker
assert '"/assistant-chat.js?v=codex-assistant-32"' in service_worker
@@ -38,7 +38,7 @@ def test_energy_monitor_assets_are_versioned_and_cached() -> None:
assert html.index("/assistant-chat.js?v=codex-assistant-32") < html.index(
"/energy-monitor.js?v=energy-monitor-4"
)
assert 'const CACHE_VERSION = "cognitive-agent-pad-v298"' in service_worker
assert 'const CACHE_VERSION = "cognitive-agent-pad-v302"' in service_worker
def test_energy_monitor_uses_the_fifth_shared_dock_icon_and_starts_closed() -> None:
+22 -4
View File
@@ -42,20 +42,29 @@ def test_theme_asset_versions_are_consistent_with_the_pwa_shell() -> None:
for asset in (
"/styles.css?v=dual-seat-23",
"/console-v2.css?v=delivery-state-69",
"/self-extension.css?v=pet-acrylic-48",
"/self-extension.css?v=pet-settings-49",
"/speech-input.css?v=sensevoice-7",
"/codepen-glass-theme.css?v=creative-cloud-1",
"/codepen-glass-theme.css?v=creative-cloud-2",
):
assert asset in html
assert f'"{asset}"' in service_worker
assert 'const CACHE_VERSION = "cognitive-agent-pad-v298"' in service_worker
assert 'const CACHE_VERSION = "cognitive-agent-pad-v302"' in service_worker
def test_reference_glass_theme_covers_the_complete_workspace() -> None:
html = source("index.html")
theme = source("codepen-glass-theme.css")
app = source("app.js")
assert '<meta name="theme-color" content="#17182b" />' in html
assert '<meta name="theme-color" content="#17182b" id="themeColorMeta" />' in html
assert 'const key = "cognitive-agent.glass-theme"' in html
assert 'id="glassThemeToggle"' in html
assert 'data-theme-icon="sun"' in html
assert 'data-theme-icon="moon"' in html
assert 'const GLASS_THEME_STORAGE_KEY = "cognitive-agent.glass-theme"' in app
assert "localStorage.setItem(GLASS_THEME_STORAGE_KEY, normalized)" in app
assert "document.cookie = `${GLASS_THEME_STORAGE_KEY}=${normalized}" in app
assert 'new CustomEvent("cognitive-agent:theme-change"' in app
for contract in (
"--glass-shell:",
"--glass-panel:",
@@ -66,11 +75,20 @@ def test_reference_glass_theme_covers_the_complete_workspace() -> None:
".joint-twin-shell > .twin-band",
"#v2ExtensionPanel .v2-extension-sync-mount",
".v2-pet-card",
".v2-pet-presence-card",
".v2-pet-settings-dialog",
".mode-gallery",
".v2-nfc-dialog",
".energy-monitor-page",
):
assert contract in theme
assert 'html[data-glass-theme="light"] body.console-v2' in theme
assert ".glass-theme-toggle" in theme
assert "width: 100vw !important" in theme
assert "height: 100dvh !important" in theme
assert "margin: 0 !important" in theme
assert "border: 0 !important" in theme
assert "border-radius: 0 !important" in theme
def test_vehicle_twin_icons_and_nested_overlays_use_semantic_tokens() -> None:
@@ -47,14 +47,16 @@ class FrontendVehicleStateSyncContractTests(unittest.TestCase):
self.extension_source,
)
def test_shared_twin_theme_is_fixed_to_user(self) -> None:
def test_shared_twin_theme_tracks_persistent_day_and_night_mode(self) -> None:
self.assertIn("function applyTwinSceneTheme(", self.app_source)
self.assertIn('canvas.dataset.themeRole = "user"', self.app_source)
self.assertIn("function currentTwinThemeRole()", self.app_source)
self.assertIn("function currentTwinThemePalette()", self.app_source)
self.assertIn("canvas.dataset.themeRole = role", self.app_source)
self.assertIn(
'canvas.dataset.themeAccent = `#${palette.accent.toString(16).padStart(6, "0")}`',
self.app_source,
)
for glass_theme_token in (
for night_theme_token in (
"accent: 0x7b70f5",
"sceneBackground: 0x111426",
"floor: 0x1a2038",
@@ -64,7 +66,20 @@ class FrontendVehicleStateSyncContractTests(unittest.TestCase):
"glass: 0x4d8ed2",
"lamp: 0x4385cf",
):
self.assertIn(glass_theme_token, self.app_source)
self.assertIn(night_theme_token, self.app_source)
for day_theme_token in (
"accent: 0x2f80ed",
"sceneBackground: 0xeff6ff",
"floor: 0xe5f0fd",
"vehicleBody: 0x91c6f5",
"vehicleOutline: 0x2879d8",
"seatShell: 0x2b76c9",
"glass: 0x4b9bea",
"lamp: 0x2e7fd4",
):
self.assertIn(day_theme_token, self.app_source)
self.assertIn('"cognitive-agent:theme-change"', self.app_source)
self.assertIn("applyTwinReferenceVehicleTheme(twin.referenceVehicle, palette)", self.app_source)
self.assertNotIn("accent: 0x0e7773", self.app_source)
self.assertNotIn("cognitive-agent:demo-role-change", self.app_source)
+16 -3
View File
@@ -60,8 +60,8 @@ def test_unified_console_exposes_device_id_based_nfc_authorization() -> None:
assert '.v2-nfc-command-list' in styles
assert '.v2-nfc-command-option' in styles
assert '.v2-nfc-select-all' in styles
assert 'self-extension.js?v=pet-acrylic-48' in html
assert 'self-extension.css?v=pet-acrylic-48' in html
assert 'self-extension.js?v=pet-settings-49' in html
assert 'self-extension.css?v=pet-settings-49' in html
def test_unified_console_exposes_gscu_tcp_configuration_and_actions() -> None:
@@ -134,7 +134,7 @@ def test_server_exposes_nfc_snapshot_through_same_origin_extension_api() -> None
assert "frame-src 'self' http://*:3001" in server
def test_homepage_exposes_durable_editable_pet_cards_and_nfc_only_binding() -> None:
def test_pet_settings_dialog_edits_durable_cards_and_homepage_only_shows_detected_pet() -> None:
script = source("self-extension.js")
styles = source("self-extension.css")
service = (ROOT / "src" / "cognitive_agent" / "application" / "pet_cards.py").read_text(
@@ -145,6 +145,16 @@ def test_homepage_exposes_durable_editable_pet_cards_and_nfc_only_binding() -> N
).read_text(encoding="utf-8")
assert 'class="v2-pet-card-region"' in script
assert 'id="extensionPetSettingsDialog"' in script
assert 'data-open-pet-settings' in script
assert 'function renderPetCardEditor()' in script
assert 'function renderPetSettingsDialog()' in script
assert 'function bindPetSettingsDialogEvents()' in script
assert 'function renderDetectedPetCard(card)' in script
assert 'mount.dataset.hasPets = String(Boolean(nfcPet))' in script
assert '${nfcPet ? renderDetectedPetCard(nfcPet) : ""}' in script
assert '${renderPetCardRegion()}' not in script
assert 'function renderPetCardRegion()' not in script
assert 'data-pet-field="pet_name"' in script
assert 'data-pet-field="action"' in script
assert '<output>${card.nfc_id ?' in script
@@ -165,6 +175,9 @@ def test_homepage_exposes_durable_editable_pet_cards_and_nfc_only_binding() -> N
assert 'if (nextRevision < petCardSnapshot.revision) return false' in script
assert '.v2-pet-card-region' in styles
assert '.v2-pet-card-list' in styles
assert '.v2-pet-settings-dialog' in styles
assert '.v2-pet-settings-body' in styles
assert '.v2-pet-presence-card' in styles
assert '.v2-nfc-pet-binding' in styles
assert 'grid-template-columns: minmax(0, 1fr);' in styles
assert 'scrollbar-gutter: stable' in styles
+2 -2
View File
@@ -18,14 +18,14 @@ def test_vue_presentation_assets_are_local_ordered_and_cached() -> None:
presentation = "/vue-ui.js?v=vue-presentation-3"
assert html.index(runtime) < html.index(presentation) < html.index(
"/app.js?v=dual-seat-136"
"/app.js?v=dual-seat-139"
)
assert html.index(presentation) < html.index(
"/assistant-chat.js?v=codex-assistant-32"
)
assert f'"{runtime}"' in service_worker
assert f'"{presentation}"' in service_worker
assert 'const CACHE_VERSION = "cognitive-agent-pad-v298"' in service_worker
assert 'const CACHE_VERSION = "cognitive-agent-pad-v302"' in service_worker
assert "unpkg.com" not in html
assert "cdn.jsdelivr.net" not in html