fix(web-console): align status cards and command history
This commit is contained in:
@@ -723,6 +723,19 @@
|
||||
return "binary";
|
||||
}
|
||||
|
||||
function focusLatestDispatchedControls(container) {
|
||||
requestAnimationFrame(() => {
|
||||
const transcript = $("#assistantMessages");
|
||||
const activeCard = container?.matches?.(".assistant-dispatched-controls")
|
||||
? container
|
||||
: $(".assistant-dispatched-controls", container);
|
||||
if (!transcript || !activeCard) return;
|
||||
transcript.querySelectorAll(".assistant-dispatched-controls").forEach((card) => {
|
||||
card.open = card === activeCard;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function appendDispatchedControls(message, result = {}) {
|
||||
if (!message?.body || !result || typeof result !== "object") return;
|
||||
const previous = message.dispatchedControlResult || {};
|
||||
@@ -767,6 +780,7 @@
|
||||
if (vueRenderer(host, viewCommands)) {
|
||||
host.dataset.commandSignature = signature;
|
||||
message.article?.classList.add("assistant-message-with-dispatched-controls");
|
||||
focusLatestDispatchedControls(host);
|
||||
followLatest(true);
|
||||
return;
|
||||
}
|
||||
@@ -778,6 +792,13 @@
|
||||
card = document.createElement("details");
|
||||
card.className = "assistant-dispatched-controls";
|
||||
card.open = true;
|
||||
card.addEventListener("toggle", () => {
|
||||
if (!card.open) return;
|
||||
const transcript = $("#assistantMessages");
|
||||
transcript?.querySelectorAll(".assistant-dispatched-controls[open]").forEach((otherCard) => {
|
||||
if (otherCard !== card) otherCard.open = false;
|
||||
});
|
||||
});
|
||||
const summary = document.createElement("summary");
|
||||
const headingIcon = document.createElement("span");
|
||||
headingIcon.className = "assistant-dispatched-controls-heading-icon";
|
||||
@@ -829,6 +850,7 @@
|
||||
list.append(row);
|
||||
});
|
||||
message.article?.classList.add("assistant-message-with-dispatched-controls");
|
||||
focusLatestDispatchedControls(card);
|
||||
window.lucide?.createIcons({ attrs: { "aria-hidden": "true" } });
|
||||
followLatest(true);
|
||||
}
|
||||
|
||||
@@ -1100,9 +1100,9 @@
|
||||
sidebarToggle.setAttribute("aria-expanded", "false");
|
||||
sidebarToggle.title = "展开左侧控制台";
|
||||
|
||||
const footer = make("footer", "v2-sidebar-footer", `
|
||||
const footer = make("footer", "v2-sidebar-footer v2-control-link-card", `
|
||||
<span class="v2-live-dot"></span>
|
||||
<div><strong>智舱控制链路</strong><small id="v2ConnectionText">正在连接服务</small></div>
|
||||
<div><strong>智舱控制链路</strong><small id="v2ConnectionText" aria-live="polite">正在连接服务</small></div>
|
||||
<button type="button" id="v2LogoutButton" title="退出登录" aria-label="退出登录"><i data-lucide="log-out"></i></button>`);
|
||||
|
||||
commandPanel.append(sidebarToggle, footer);
|
||||
@@ -1675,6 +1675,11 @@
|
||||
if (!list) return;
|
||||
const filter = $("#v2LogFilter")?.value || "all";
|
||||
const items = displaySync.logs.filter((item) => filter === "all" || item.category === filter);
|
||||
const count = $("#v2SyncLogCount");
|
||||
if (count) {
|
||||
count.textContent = String(items.length);
|
||||
count.title = `${items.length} 条记录`;
|
||||
}
|
||||
const icons = { task: "route", sync: "refresh-cw", extension: "usb", device: "activity" };
|
||||
list.innerHTML = items.length ? items.map((item) => `
|
||||
<li data-log-status="${escapeHtml(item.status)}">
|
||||
@@ -1685,6 +1690,21 @@
|
||||
window.lucide?.createIcons({ attrs: { "aria-hidden": "true" } });
|
||||
}
|
||||
|
||||
function setSyncLogCollapsed(collapsed) {
|
||||
const panel = $(".v2-sync-log");
|
||||
const list = $("#v2SyncLogList");
|
||||
const toggle = $("#v2SyncLogToggle");
|
||||
if (!panel || !list || !toggle) return;
|
||||
const nextCollapsed = Boolean(collapsed);
|
||||
const label = nextCollapsed ? "展开运行日志与同步记录" : "折叠运行日志与同步记录";
|
||||
panel.dataset.collapsed = String(nextCollapsed);
|
||||
list.hidden = nextCollapsed;
|
||||
toggle.setAttribute("aria-expanded", String(!nextCollapsed));
|
||||
toggle.setAttribute("aria-label", label);
|
||||
toggle.title = label;
|
||||
requestAnimationFrame(syncSidebarLogBaseline);
|
||||
}
|
||||
|
||||
function panelVisible(key) {
|
||||
const panel = key === "devices" ? $("#v2DevicePanel") : $("#v2ExtensionPanel");
|
||||
if (panel) return !panel.classList.contains("is-collapsed");
|
||||
@@ -2439,9 +2459,15 @@
|
||||
const sidebarFooter = $(".v2-sidebar-footer", sidebar);
|
||||
const syncSidebar = make("section", "v2-sync-sidebar", `
|
||||
<div class="v2-sync-sidebar-overview"></div>
|
||||
<section class="v2-sync-log" aria-labelledby="v2SyncLogTitle">
|
||||
<header><div><h3 id="v2SyncLogTitle">运行日志 / 同步记录</h3></div><select id="v2LogFilter" aria-label="筛选同步日志"><option value="all">全部</option><option value="task">任务</option><option value="sync">同步</option><option value="extension">外设</option><option value="device">设备</option></select></header>
|
||||
<ol id="v2SyncLogList" aria-live="polite"></ol>
|
||||
<section class="v2-sync-log" aria-labelledby="v2SyncLogTitle" data-collapsed="true">
|
||||
<header>
|
||||
<div><h3 id="v2SyncLogTitle">运行日志 / 同步记录</h3></div>
|
||||
<div class="v2-sync-log-actions">
|
||||
<select id="v2LogFilter" aria-label="筛选同步日志"><option value="all">全部</option><option value="task">任务</option><option value="sync">同步</option><option value="extension">外设</option><option value="device">设备</option></select>
|
||||
<button type="button" class="v2-sync-log-toggle" id="v2SyncLogToggle" aria-controls="v2SyncLogList" aria-expanded="false" aria-label="展开运行日志与同步记录" title="展开运行日志与同步记录"><span id="v2SyncLogCount">0</span><i data-lucide="chevron-down"></i></button>
|
||||
</div>
|
||||
</header>
|
||||
<ol id="v2SyncLogList" aria-live="polite" hidden></ol>
|
||||
</section>`);
|
||||
if (sidebar && sidebarFooter) {
|
||||
sidebar.insertBefore(syncSidebar, sidebarFooter);
|
||||
@@ -2574,6 +2600,10 @@
|
||||
if (event.target.matches("select[data-device-control]")) storeDeviceControlDraft(event.target);
|
||||
});
|
||||
$("#v2LogFilter")?.addEventListener("change", renderSyncLogs);
|
||||
$("#v2SyncLogToggle")?.addEventListener("click", () => {
|
||||
setSyncLogCollapsed($(".v2-sync-log")?.dataset.collapsed !== "true");
|
||||
});
|
||||
setSyncLogCollapsed(true);
|
||||
const beginPendingControlRequest = (request = {}) => {
|
||||
beginCommandTiming(request);
|
||||
resetValidatedCommandContext();
|
||||
@@ -2879,18 +2909,38 @@
|
||||
const connectionText = $("#v2ConnectionText");
|
||||
if (connectionText) {
|
||||
const status = connectionState?.status || "connecting";
|
||||
const labels = {
|
||||
connecting: "正在连接服务",
|
||||
online: "服务已连接",
|
||||
degraded: "连接不稳定",
|
||||
offline: "服务已断开",
|
||||
};
|
||||
connectionText.textContent = labels[status] || labels.connecting;
|
||||
connectionText.title = connectionState?.lastError || connectionText.textContent;
|
||||
$(".v2-sidebar-footer")?.classList.toggle(
|
||||
"offline",
|
||||
status === "offline" || status === "degraded",
|
||||
);
|
||||
const selectedTransport = $('.vehicle-transport-options [data-control-transport][aria-pressed="true"]')
|
||||
|| $('.vehicle-transport-options [data-control-transport].active');
|
||||
const transport = selectedTransport?.dataset.controlTransport || "";
|
||||
const transportOnline = selectedTransport?.dataset.connectionState === "online";
|
||||
const transportLabel = transport === "wireless_mqtt" ? "无线 CAN" : "有线 CAN";
|
||||
const footer = connectionText.closest(".v2-control-link-card");
|
||||
let presentationState = status;
|
||||
let label = "正在连接服务";
|
||||
|
||||
if (status === "online" && transport) {
|
||||
presentationState = transportOnline ? "online" : "offline";
|
||||
label = transport === "wireless_mqtt"
|
||||
? `${transportLabel} · MQTT ${transportOnline ? "已连接" : "未连接"}`
|
||||
: `${transportLabel} · 信号链路${transportOnline ? "正常" : "断开"}`;
|
||||
} else if (status === "online") {
|
||||
presentationState = "online";
|
||||
label = "服务已连接";
|
||||
} else if (status === "degraded") {
|
||||
label = transport ? `${transportLabel} · 主服务连接不稳定` : "主服务连接不稳定";
|
||||
} else if (status === "offline") {
|
||||
label = transport ? `${transportLabel} · 主服务已断开` : "主服务已断开";
|
||||
}
|
||||
|
||||
connectionText.textContent = label;
|
||||
connectionText.title = connectionState?.lastError
|
||||
|| (!transportOnline ? selectedTransport?.title : "")
|
||||
|| label;
|
||||
if (footer) {
|
||||
footer.dataset.transport = transport || "service";
|
||||
footer.dataset.state = presentationState;
|
||||
footer.classList.toggle("offline", presentationState !== "online");
|
||||
}
|
||||
}
|
||||
keepRunButtonAvailable();
|
||||
}
|
||||
@@ -2927,6 +2977,7 @@
|
||||
syncRuntimePresentation(event.detail);
|
||||
});
|
||||
window.addEventListener("cognitive-agent:vehicle-feedback-state", () => {
|
||||
syncRuntimePresentation();
|
||||
renderSyncedDevices();
|
||||
if (displaySync.activeDevice) {
|
||||
presentTwinDevice(displaySync.activeDevice, {
|
||||
@@ -2935,6 +2986,14 @@
|
||||
});
|
||||
}
|
||||
});
|
||||
const transportOptions = $(".vehicle-transport-options");
|
||||
if (transportOptions) {
|
||||
new MutationObserver(() => syncRuntimePresentation()).observe(transportOptions, {
|
||||
attributes: true,
|
||||
attributeFilter: ["aria-pressed", "class", "data-connection-state", "title"],
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
const observer = new MutationObserver(() => keepRunButtonAvailable());
|
||||
[$("#hardwareMode"), $("#simulationMode")]
|
||||
.filter(Boolean)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const CACHE_VERSION = "cognitive-agent-pad-v315-vue-vite";
|
||||
const CACHE_VERSION = "cognitive-agent-pad-v316-sidebar-accordion";
|
||||
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
|
||||
const RUNTIME_CACHE = `${CACHE_VERSION}-runtime`;
|
||||
const APP_SHELL = [
|
||||
|
||||
@@ -44,6 +44,7 @@ body.console-v2 :is(
|
||||
.v2-sync-transport-field,
|
||||
.v2-sync-execution-field,
|
||||
.v2-can-command-panel,
|
||||
.v2-control-link-card,
|
||||
.v2-nfc-inline,
|
||||
.v2-extension-gateway,
|
||||
.v2-extension-synced-device,
|
||||
@@ -132,6 +133,119 @@ body.console-v2 .v2-sync-log h3 {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Sidebar disclosure, connection status and control-command readability use
|
||||
* the same semantic tokens in both day and night themes. */
|
||||
body.console-v2 .v2-sync-log[data-collapsed="true"] {
|
||||
min-height: 0;
|
||||
align-self: start;
|
||||
grid-template-rows: auto;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
body.console-v2 .v2-sync-log[data-collapsed="true"] > header {
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
body.console-v2 .v2-sync-log[data-collapsed="true"] #v2LogFilter {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.console-v2 .v2-sync-log #v2SyncLogList[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
body.console-v2 .v2-sync-log > header > div:first-child {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
body.console-v2 .v2-sync-log .v2-sync-log-actions {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
body.console-v2 .v2-sync-log .v2-sync-log-toggle {
|
||||
min-width: 46px;
|
||||
min-height: var(--n7-control-height-sm);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
padding: 0 7px;
|
||||
color: var(--muted-foreground);
|
||||
background: var(--secondary);
|
||||
border: 1px solid var(--input);
|
||||
border-radius: var(--n7-radius-control);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
body.console-v2 .v2-sync-log .v2-sync-log-toggle:is(:hover, :focus-visible) {
|
||||
color: var(--accent-foreground);
|
||||
background: var(--accent);
|
||||
border-color: var(--ring);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
body.console-v2 .v2-sync-log .v2-sync-log-toggle svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
transition: transform 160ms ease;
|
||||
}
|
||||
|
||||
body.console-v2 .v2-sync-log .v2-sync-log-toggle[aria-expanded="true"] svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
body.console-v2.v2-passive-display.v2-interactive-sync .v2-control-link-card {
|
||||
min-height: 56px;
|
||||
grid-template-columns: 10px minmax(0, 1fr);
|
||||
gap: 10px;
|
||||
margin: 0 !important;
|
||||
padding: 10px 11px !important;
|
||||
color: var(--card-foreground);
|
||||
background: var(--glass-card) !important;
|
||||
border: 1px solid var(--glass-line) !important;
|
||||
border-radius: var(--n7-radius-card) !important;
|
||||
box-shadow: var(--n7-shadow-card) !important;
|
||||
-webkit-backdrop-filter: blur(16px) saturate(1.2);
|
||||
backdrop-filter: blur(16px) saturate(1.2);
|
||||
}
|
||||
|
||||
body.console-v2 .v2-control-link-card strong {
|
||||
color: var(--card-foreground) !important;
|
||||
}
|
||||
|
||||
body.console-v2 .v2-control-link-card small {
|
||||
color: var(--muted-foreground) !important;
|
||||
}
|
||||
|
||||
body.console-v2 .v2-control-link-card[data-state="online"] .v2-live-dot {
|
||||
background: var(--status-online);
|
||||
box-shadow: 0 0 0 4px color-mix(in oklch, var(--status-online) 18%, transparent);
|
||||
}
|
||||
|
||||
body.console-v2 .v2-control-link-card[data-state="connecting"] .v2-live-dot {
|
||||
background: var(--status-info);
|
||||
box-shadow: 0 0 0 4px color-mix(in oklch, var(--status-info) 18%, transparent);
|
||||
}
|
||||
|
||||
body.console-v2 .v2-control-link-card[data-state="degraded"] .v2-live-dot {
|
||||
background: var(--status-warning);
|
||||
box-shadow: 0 0 0 4px color-mix(in oklch, var(--status-warning) 18%, transparent);
|
||||
}
|
||||
|
||||
body.console-v2 .v2-control-link-card[data-state="offline"] .v2-live-dot {
|
||||
background: var(--status-offline);
|
||||
box-shadow: 0 0 0 4px color-mix(in oklch, var(--status-offline) 18%, transparent);
|
||||
}
|
||||
|
||||
body.console-v2.v2-passive-display.v2-interactive-sync
|
||||
.v2-can-command-list li[data-can-channel]
|
||||
.v2-can-command-actual code {
|
||||
color: var(--card-foreground) !important;
|
||||
}
|
||||
|
||||
body.console-v2 :is(
|
||||
.mode-gallery-header h2,
|
||||
.mode-editor-header h2,
|
||||
|
||||
@@ -120,6 +120,11 @@ import { Fragment, createApp, h, nextTick, reactive } from "vue";
|
||||
open: state.open,
|
||||
onToggle(event) {
|
||||
state.open = event.currentTarget.open;
|
||||
if (!state.open) return;
|
||||
const transcript = document.querySelector("#assistantMessages");
|
||||
transcript?.querySelectorAll(".assistant-dispatched-controls[open]").forEach((card) => {
|
||||
if (card !== event.currentTarget) card.open = false;
|
||||
});
|
||||
},
|
||||
}, [
|
||||
h("summary", null, [
|
||||
|
||||
@@ -1363,7 +1363,7 @@ operations:
|
||||
self.assertIn('canvas.addEventListener("webglcontextlost"', app_script)
|
||||
self.assertIn('"cognitive-agent:module-change"', app_script)
|
||||
self.assertIn(
|
||||
'const CACHE_VERSION = "cognitive-agent-pad-v315-vue-vite"',
|
||||
'const CACHE_VERSION = "cognitive-agent-pad-v316-sidebar-accordion"',
|
||||
service_worker,
|
||||
)
|
||||
self.assertIn('/console-v2.css?v=delivery-state-69', service_worker)
|
||||
|
||||
@@ -27,7 +27,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-v315-vue-vite"'
|
||||
'const CACHE_VERSION = "cognitive-agent-pad-v316-sidebar-accordion"'
|
||||
in service_worker
|
||||
)
|
||||
assert '"/assistant-chat.css?v=codex-assistant-29"' in service_worker
|
||||
@@ -120,6 +120,22 @@ def test_validated_controls_are_mirrored_into_a_compact_assistant_card():
|
||||
assert ".assistant-dispatched-controls[open]" in css
|
||||
|
||||
|
||||
def test_latest_dispatched_control_group_is_the_only_group_expanded():
|
||||
assistant = (ROOT / "apps/web-console/assistant-chat.js").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
vue_ui = (ROOT / "apps/web-console/vue-ui.js").read_text(encoding="utf-8")
|
||||
|
||||
assert "function focusLatestDispatchedControls(container)" in assistant
|
||||
assert 'transcript.querySelectorAll(".assistant-dispatched-controls")' in assistant
|
||||
assert "card.open = card === activeCard" in assistant
|
||||
assert "focusLatestDispatchedControls(host)" in assistant
|
||||
assert "focusLatestDispatchedControls(card)" in assistant
|
||||
assert 'querySelectorAll(".assistant-dispatched-controls[open]")' in assistant
|
||||
assert 'querySelectorAll(".assistant-dispatched-controls[open]")' in vue_ui
|
||||
assert "if (card !== event.currentTarget) card.open = false" in vue_ui
|
||||
|
||||
|
||||
def test_saved_mode_execution_opens_with_pending_flow_before_http_completion():
|
||||
app = (ROOT / "apps/web-console/app.js").read_text(encoding="utf-8")
|
||||
flow = app.split(
|
||||
|
||||
@@ -41,7 +41,7 @@ def test_energy_monitor_assets_are_versioned_and_cached() -> None:
|
||||
"/energy-monitor.js?v=energy-monitor-4"
|
||||
)
|
||||
assert (
|
||||
'const CACHE_VERSION = "cognitive-agent-pad-v315-vue-vite"'
|
||||
'const CACHE_VERSION = "cognitive-agent-pad-v316-sidebar-accordion"'
|
||||
in service_worker
|
||||
)
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ def test_theme_asset_versions_are_consistent_with_the_pwa_shell() -> None:
|
||||
assert source_asset in main
|
||||
assert f'"{cached_asset}"' in service_worker
|
||||
assert 'import "./styles/design-system.css"' in main
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v315-vue-vite"' in service_worker
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v316-sidebar-accordion"' in service_worker
|
||||
|
||||
|
||||
def test_reference_glass_theme_covers_the_complete_workspace() -> None:
|
||||
@@ -247,6 +247,22 @@ def test_command_fields_use_distinct_semantic_colors() -> None:
|
||||
assert mapping in console
|
||||
|
||||
|
||||
def test_sidebar_command_and_transport_status_use_theme_semantics() -> None:
|
||||
console = source("console-v2.js")
|
||||
design_system = source("src/styles/design-system.css")
|
||||
|
||||
assert '"v2-sidebar-footer v2-control-link-card"' in console
|
||||
assert 'transport === "wireless_mqtt" ? "无线 CAN" : "有线 CAN"' in console
|
||||
assert 'MQTT ${transportOnline ? "已连接" : "未连接"}' in console
|
||||
assert 'footer.dataset.state = presentationState' in console
|
||||
assert 'attributeFilter: ["aria-pressed", "class", "data-connection-state", "title"]' in console
|
||||
assert ".v2-control-link-card" in design_system
|
||||
assert 'data-state="online"' in design_system
|
||||
assert 'data-state="offline"' in design_system
|
||||
assert ".v2-can-command-actual code" in design_system
|
||||
assert "color: var(--card-foreground) !important" in design_system
|
||||
|
||||
|
||||
def test_function_modes_use_an_inline_accessible_collapsible() -> None:
|
||||
html = source("index.html")
|
||||
app = source("app.js")
|
||||
|
||||
@@ -133,6 +133,22 @@ def test_compact_sidebar_overrides_cannot_break_shared_geometry() -> None:
|
||||
assert "white-space: nowrap" in design_system
|
||||
|
||||
|
||||
def test_runtime_log_starts_collapsed_with_an_accessible_disclosure() -> None:
|
||||
console = source("console-v2.js")
|
||||
design_system = source("src/styles/design-system.css")
|
||||
|
||||
assert 'class="v2-sync-log" aria-labelledby="v2SyncLogTitle" data-collapsed="true"' in console
|
||||
assert 'id="v2SyncLogList" aria-live="polite" hidden' in console
|
||||
assert 'id="v2SyncLogToggle"' in console
|
||||
assert 'aria-controls="v2SyncLogList"' in console
|
||||
assert 'aria-expanded="false"' in console
|
||||
assert "function setSyncLogCollapsed(collapsed)" in console
|
||||
assert "setSyncLogCollapsed(true)" in console
|
||||
assert '.v2-sync-log[data-collapsed="true"]' in design_system
|
||||
assert '.v2-sync-log[data-collapsed="true"] #v2LogFilter' in design_system
|
||||
assert '#v2SyncLogList[hidden]' in design_system
|
||||
|
||||
|
||||
def test_assistant_composer_hint_stays_inside_narrow_input() -> None:
|
||||
styles = source("ui-consistency.css")
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ def test_vue_vite_application_is_the_primary_frontend_entry() -> None:
|
||||
assert package["scripts"]["build"] == "vite build"
|
||||
assert 'import vue from "@vitejs/plugin-vue"' in vite
|
||||
assert 'outDir: outputRoot' in vite
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v315-vue-vite"' in service_worker
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v316-sidebar-accordion"' in service_worker
|
||||
assert "unpkg.com" not in html
|
||||
assert "cdn.jsdelivr.net" not in html
|
||||
|
||||
|
||||
Reference in New Issue
Block a user