Fix workbench dark theme and enlarge dialogs
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
inset: 0;
|
inset: 0;
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
padding: 68px 20px 20px;
|
padding: 16px;
|
||||||
background: color-mix(in oklch, var(--background) 58%, transparent);
|
background: color-mix(in oklch, var(--background) 58%, transparent);
|
||||||
backdrop-filter: blur(6px) saturate(.9);
|
backdrop-filter: blur(6px) saturate(.9);
|
||||||
-webkit-backdrop-filter: blur(6px) saturate(.9);
|
-webkit-backdrop-filter: blur(6px) saturate(.9);
|
||||||
@@ -17,8 +17,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.console-v2 .energy-monitor-page {
|
.console-v2 .energy-monitor-page {
|
||||||
width: min(1180px, 100%);
|
width: min(1480px, 100%);
|
||||||
height: min(664px, 100%);
|
height: min(900px, 100%);
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto minmax(0, 1fr);
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
inset: 0;
|
inset: 0;
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
padding: 68px 20px 20px;
|
padding: 16px;
|
||||||
background: color-mix(in oklch, var(--background) 58%, transparent);
|
background: color-mix(in oklch, var(--background) 58%, transparent);
|
||||||
backdrop-filter: blur(6px) saturate(.9);
|
backdrop-filter: blur(6px) saturate(.9);
|
||||||
-webkit-backdrop-filter: blur(6px) saturate(.9);
|
-webkit-backdrop-filter: blur(6px) saturate(.9);
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
}
|
}
|
||||||
.console-v2 .firmware-workbench-layer[hidden] { display: none !important; }
|
.console-v2 .firmware-workbench-layer[hidden] { display: none !important; }
|
||||||
.console-v2 .firmware-workbench-page {
|
.console-v2 .firmware-workbench-page {
|
||||||
width: min(1180px, 100%);
|
width: min(1480px, 100%);
|
||||||
height: min(664px, 100%);
|
height: min(900px, 100%);
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 76px minmax(0, 1fr);
|
grid-template-rows: 76px minmax(0, 1fr);
|
||||||
|
|||||||
@@ -3,6 +3,17 @@
|
|||||||
|
|
||||||
const state = { open: false, returnFocus: null, backgroundInert: [] };
|
const state = { open: false, returnFocus: null, backgroundInert: [] };
|
||||||
|
|
||||||
|
function currentWorkbenchTheme() {
|
||||||
|
return document.documentElement.dataset.glassTheme === "light" ? "light" : "dark";
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncWorkbenchTheme(frame) {
|
||||||
|
frame?.contentWindow?.postMessage({
|
||||||
|
type: "cognitive-agent:theme-change",
|
||||||
|
theme: currentWorkbenchTheme(),
|
||||||
|
}, window.location.origin);
|
||||||
|
}
|
||||||
|
|
||||||
function setBackgroundInert(inert) {
|
function setBackgroundInert(inert) {
|
||||||
const layer = document.querySelector("#firmwareWorkbenchLayer");
|
const layer = document.querySelector("#firmwareWorkbenchLayer");
|
||||||
if (!layer) return;
|
if (!layer) return;
|
||||||
@@ -80,11 +91,19 @@
|
|||||||
</div>
|
</div>
|
||||||
<button id="firmwareWorkbenchClose" type="button" aria-label="关闭座椅固件开发工作台" title="关闭"><i data-lucide="x"></i></button>
|
<button id="firmwareWorkbenchClose" type="button" aria-label="关闭座椅固件开发工作台" title="关闭"><i data-lucide="x"></i></button>
|
||||||
</header>
|
</header>
|
||||||
<iframe class="firmware-workbench-frame" src="/firmware-workbench.html?embedded=1" title="座椅固件开发工作台"></iframe>
|
<iframe class="firmware-workbench-frame" title="座椅固件开发工作台"></iframe>
|
||||||
</section>`;
|
</section>`;
|
||||||
|
|
||||||
dock.append(trigger);
|
dock.append(trigger);
|
||||||
document.body.append(layer);
|
document.body.append(layer);
|
||||||
|
const frame = document.querySelector(".firmware-workbench-frame", layer);
|
||||||
|
frame.src = `/firmware-workbench.html?embedded=1&theme=${currentWorkbenchTheme()}`;
|
||||||
|
frame.addEventListener("load", () => syncWorkbenchTheme(frame));
|
||||||
|
window.addEventListener("cognitive-agent:theme-change", () => syncWorkbenchTheme(frame));
|
||||||
|
new MutationObserver(() => syncWorkbenchTheme(frame)).observe(document.documentElement, {
|
||||||
|
attributes: true,
|
||||||
|
attributeFilter: ["data-glass-theme"],
|
||||||
|
});
|
||||||
trigger.addEventListener("click", () => setOpen(!state.open));
|
trigger.addEventListener("click", () => setOpen(!state.open));
|
||||||
document.querySelector("#firmwareWorkbenchClose", layer).addEventListener("click", () => setOpen(false));
|
document.querySelector("#firmwareWorkbenchClose", layer).addEventListener("click", () => setOpen(false));
|
||||||
layer.addEventListener("click", (event) => { if (event.target === layer) setOpen(false); });
|
layer.addEventListener("click", (event) => { if (event.target === layer) setOpen(false); });
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
(() => {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const STORAGE_KEY = "cognitive-agent.glass-theme";
|
||||||
|
|
||||||
|
function normalizeTheme(value) {
|
||||||
|
return value === "light" ? "light" : value === "dark" ? "dark" : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function themeFromCookie() {
|
||||||
|
try {
|
||||||
|
return normalizeTheme(document.cookie
|
||||||
|
.split(";")
|
||||||
|
.map((part) => part.trim())
|
||||||
|
.find((part) => part.startsWith(`${STORAGE_KEY}=`))
|
||||||
|
?.slice(STORAGE_KEY.length + 1));
|
||||||
|
} catch (_error) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveInitialTheme() {
|
||||||
|
const requested = normalizeTheme(new URLSearchParams(window.location.search).get("theme"));
|
||||||
|
if (requested) return requested;
|
||||||
|
try {
|
||||||
|
const parentTheme = normalizeTheme(window.parent?.document?.documentElement?.dataset?.glassTheme);
|
||||||
|
if (parentTheme) return parentTheme;
|
||||||
|
} catch (_error) {
|
||||||
|
// Standalone and cross-origin rendering continue with local preferences.
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const stored = normalizeTheme(localStorage.getItem(STORAGE_KEY));
|
||||||
|
if (stored) return stored;
|
||||||
|
} catch (_error) {
|
||||||
|
// Storage may be unavailable in hardened browser contexts.
|
||||||
|
}
|
||||||
|
return themeFromCookie() || "dark";
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyTheme(theme) {
|
||||||
|
const normalized = normalizeTheme(theme) || "dark";
|
||||||
|
document.documentElement.dataset.glassTheme = normalized;
|
||||||
|
document.documentElement.style.colorScheme = normalized;
|
||||||
|
document.querySelector("#firmwareWorkbenchThemeColor")
|
||||||
|
?.setAttribute("content", normalized === "dark" ? "#0f1526" : "#f3f6fb");
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyTheme(resolveInitialTheme());
|
||||||
|
|
||||||
|
window.addEventListener("storage", (event) => {
|
||||||
|
if (event.key === STORAGE_KEY) applyTheme(event.newValue);
|
||||||
|
});
|
||||||
|
window.addEventListener("message", (event) => {
|
||||||
|
if (event.origin !== window.location.origin) return;
|
||||||
|
if (window.parent !== window && event.source !== window.parent) return;
|
||||||
|
if (event.data?.type !== "cognitive-agent:theme-change") return;
|
||||||
|
applyTheme(event.data.theme);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.CognitiveAgentFirmwareWorkbenchTheme = Object.freeze({
|
||||||
|
apply: applyTheme,
|
||||||
|
current: () => document.documentElement.dataset.glassTheme,
|
||||||
|
});
|
||||||
|
})();
|
||||||
@@ -341,7 +341,7 @@ th:nth-child(4) { width: 28%; } th:nth-child(5) { width: 8%; } th:nth-child(6) {
|
|||||||
|
|
||||||
.modal-backdrop { position: fixed; inset: 0; z-index: 50; display: grid; place-items: center; padding: 24px; background: rgba(31, 43, 61, .34); backdrop-filter: blur(4px); }
|
.modal-backdrop { position: fixed; inset: 0; z-index: 50; display: grid; place-items: center; padding: 24px; background: rgba(31, 43, 61, .34); backdrop-filter: blur(4px); }
|
||||||
.modal-backdrop[hidden] { display: none; }
|
.modal-backdrop[hidden] { display: none; }
|
||||||
.modal { width: min(780px, 100%); max-height: min(680px, calc(100dvh - 48px)); display: grid; grid-template-rows: auto minmax(0, 1fr) auto; overflow: hidden; background: #fff; border: 1px solid var(--line); border-radius: 16px; box-shadow: var(--shadow); }
|
.modal { width: min(1040px, 100%); max-height: min(820px, calc(100dvh - 48px)); display: grid; grid-template-rows: auto minmax(0, 1fr) auto; overflow: hidden; background: #fff; border: 1px solid var(--line); border-radius: 16px; box-shadow: var(--shadow); }
|
||||||
.modal header, .modal footer { padding: 14px 16px; display: flex; align-items: center; justify-content: space-between; gap: 12px; border-bottom: 1px solid var(--line); }
|
.modal header, .modal footer { padding: 14px 16px; display: flex; align-items: center; justify-content: space-between; gap: 12px; border-bottom: 1px solid var(--line); }
|
||||||
.modal footer { justify-content: flex-end; border-top: 1px solid var(--line); border-bottom: 0; }
|
.modal footer { justify-content: flex-end; border-top: 1px solid var(--line); border-bottom: 0; }
|
||||||
.modal-body { overflow: auto; padding: 16px; }
|
.modal-body { overflow: auto; padding: 16px; }
|
||||||
@@ -454,3 +454,155 @@ body.embedded .file-cell span { line-height: 1.15; }
|
|||||||
body.embedded .pipeline-card { overflow-x: auto; }
|
body.embedded .pipeline-card { overflow-x: auto; }
|
||||||
body.embedded .pipeline-card .pipeline { width: 680px; }
|
body.embedded .pipeline-card .pipeline { width: 680px; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The workbench is rendered in an iframe, so it owns a complete theme token
|
||||||
|
set instead of relying on custom properties from the parent document. */
|
||||||
|
:root[data-glass-theme="dark"] {
|
||||||
|
color-scheme: dark;
|
||||||
|
--page: #090e1c;
|
||||||
|
--surface: #171e31;
|
||||||
|
--surface-soft: #11182a;
|
||||||
|
--line: #303a55;
|
||||||
|
--line-strong: #44516d;
|
||||||
|
--text: #edf2ff;
|
||||||
|
--muted: #9ba9c0;
|
||||||
|
--primary: #7aa3ff;
|
||||||
|
--primary-soft: #1b2b53;
|
||||||
|
--success: #55d4a1;
|
||||||
|
--success-soft: #12372d;
|
||||||
|
--warning: #f2bd68;
|
||||||
|
--danger: #ff8993;
|
||||||
|
--shadow: 0 26px 70px rgba(0, 0, 0, .42), 0 4px 18px rgba(0, 0, 0, .24);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-glass-theme="dark"] body:not(.embedded) {
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 15% 8%, color-mix(in srgb, var(--primary) 18%, transparent), transparent 31%),
|
||||||
|
linear-gradient(145deg, #11182b 0%, var(--page) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-glass-theme="dark"] body.embedded { background: transparent; }
|
||||||
|
:root[data-glass-theme="dark"] .shell,
|
||||||
|
:root[data-glass-theme="dark"] body.embedded .shell {
|
||||||
|
background: color-mix(in srgb, var(--surface-soft) 86%, var(--page));
|
||||||
|
border-color: color-mix(in srgb, var(--line-strong) 78%, transparent);
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .topbar {
|
||||||
|
background: color-mix(in srgb, var(--surface) 94%, transparent);
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] :is(.back-link, .icon-button, .button-secondary) {
|
||||||
|
color: var(--muted);
|
||||||
|
background: var(--surface);
|
||||||
|
border-color: var(--line-strong);
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] :is(.back-link, .icon-button):hover {
|
||||||
|
color: var(--primary);
|
||||||
|
border-color: color-mix(in srgb, var(--primary) 50%, var(--line));
|
||||||
|
background: var(--primary-soft);
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] :is(.eyebrow, .section-kicker) { color: var(--muted); }
|
||||||
|
:root[data-glass-theme="dark"] :is(.environment-chip, .server-state) {
|
||||||
|
color: var(--muted);
|
||||||
|
background: var(--surface-soft);
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .server-state span { background: color-mix(in srgb, var(--muted) 72%, transparent); }
|
||||||
|
:root[data-glass-theme="dark"] .server-state.online,
|
||||||
|
:root[data-glass-theme="dark"] .status-badge[data-status="baseline"] {
|
||||||
|
border-color: color-mix(in srgb, var(--success) 44%, var(--line));
|
||||||
|
background: var(--success-soft);
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .card {
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, .16);
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .command-card > label { color: var(--muted); }
|
||||||
|
:root[data-glass-theme="dark"] textarea:focus { background: var(--surface); }
|
||||||
|
:root[data-glass-theme="dark"] :is(select, option) { color: var(--text); background: var(--surface); }
|
||||||
|
:root[data-glass-theme="dark"] .prompt-templates button,
|
||||||
|
:root[data-glass-theme="dark"] .cap-tags span,
|
||||||
|
:root[data-glass-theme="dark"] .table-actions :is(button, a) {
|
||||||
|
color: var(--primary);
|
||||||
|
background: var(--primary-soft);
|
||||||
|
border-color: color-mix(in srgb, var(--primary) 34%, var(--line));
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .capability-brief {
|
||||||
|
border-color: color-mix(in srgb, var(--primary) 25%, var(--line));
|
||||||
|
background: color-mix(in srgb, var(--primary-soft) 44%, var(--surface-soft));
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .capability-brief strong { color: var(--text); }
|
||||||
|
:root[data-glass-theme="dark"] .capability-brief > svg { color: var(--primary); }
|
||||||
|
:root[data-glass-theme="dark"] .pipeline-stage::after { background: var(--line); }
|
||||||
|
:root[data-glass-theme="dark"] .stage-node {
|
||||||
|
color: var(--muted);
|
||||||
|
border-color: var(--line-strong);
|
||||||
|
background: var(--surface);
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .pipeline-stage[data-status="success"] .stage-node {
|
||||||
|
border-color: color-mix(in srgb, var(--success) 62%, var(--line));
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .pipeline-stage[data-status="failed"] .stage-node,
|
||||||
|
:root[data-glass-theme="dark"] .pipeline-stage[data-status="blocked"] .stage-node,
|
||||||
|
:root[data-glass-theme="dark"] .release-result[data-state="failed"],
|
||||||
|
:root[data-glass-theme="dark"] .status-badge[data-status="failed"],
|
||||||
|
:root[data-glass-theme="dark"] .status-badge[data-status="blocked"] {
|
||||||
|
color: var(--danger);
|
||||||
|
border-color: color-mix(in srgb, var(--danger) 44%, var(--line));
|
||||||
|
background: color-mix(in srgb, var(--danger) 12%, var(--surface));
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .pipeline-stage[data-status="canceled"] .stage-node {
|
||||||
|
color: var(--muted);
|
||||||
|
background: var(--surface-soft);
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .pipeline-stage[data-status="pending_confirmation"] .stage-node,
|
||||||
|
:root[data-glass-theme="dark"] .status-badge[data-status="ready"],
|
||||||
|
:root[data-glass-theme="dark"] .status-badge[data-status="pending_confirmation"] {
|
||||||
|
color: var(--warning);
|
||||||
|
border-color: color-mix(in srgb, var(--warning) 44%, var(--line));
|
||||||
|
background: color-mix(in srgb, var(--warning) 12%, var(--surface));
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .pipeline-stage[data-status="success"]::after {
|
||||||
|
background: color-mix(in srgb, var(--success) 64%, var(--line));
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .release-result[data-state="success"],
|
||||||
|
:root[data-glass-theme="dark"] .status-badge[data-status="success"],
|
||||||
|
:root[data-glass-theme="dark"] .status-badge[data-status="published"] {
|
||||||
|
border-color: color-mix(in srgb, var(--success) 44%, var(--line));
|
||||||
|
background: var(--success-soft);
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .result-icon {
|
||||||
|
color: var(--muted);
|
||||||
|
background: color-mix(in srgb, var(--surface-soft) 78%, var(--line));
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .release-result[data-state="success"] .result-icon {
|
||||||
|
color: var(--success);
|
||||||
|
background: color-mix(in srgb, var(--success) 18%, var(--surface));
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .metrics div { border-color: var(--line); }
|
||||||
|
:root[data-glass-theme="dark"] :is(.log-stream, .log-details) { background: var(--surface-soft); }
|
||||||
|
:root[data-glass-theme="dark"] .empty-state svg { color: var(--muted); }
|
||||||
|
:root[data-glass-theme="dark"] .empty-state strong { color: var(--text); }
|
||||||
|
:root[data-glass-theme="dark"] .log-entry,
|
||||||
|
:root[data-glass-theme="dark"] :is(.change-item, .test-item) { border-color: var(--line); }
|
||||||
|
:root[data-glass-theme="dark"] .log-time { color: var(--muted); }
|
||||||
|
:root[data-glass-theme="dark"] .log-dot { background: var(--muted); }
|
||||||
|
:root[data-glass-theme="dark"] .log-copy p { color: var(--muted); }
|
||||||
|
:root[data-glass-theme="dark"] .inspector-tabs { background: var(--surface); }
|
||||||
|
:root[data-glass-theme="dark"] .inspector-tabs button { color: var(--muted); }
|
||||||
|
:root[data-glass-theme="dark"] .inspector-tabs button.active {
|
||||||
|
color: var(--primary);
|
||||||
|
background: var(--surface-soft);
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] :is(.build-output, .code-block) { color: var(--text); }
|
||||||
|
:root[data-glass-theme="dark"] .server-target strong { color: var(--text); }
|
||||||
|
:root[data-glass-theme="dark"] th { color: var(--muted); background: var(--surface); }
|
||||||
|
:root[data-glass-theme="dark"] td { color: var(--muted); border-color: var(--line); }
|
||||||
|
:root[data-glass-theme="dark"] :is(.software-name strong, .file-cell strong) { color: var(--text); }
|
||||||
|
:root[data-glass-theme="dark"] .table-actions .delete-action {
|
||||||
|
color: var(--danger);
|
||||||
|
background: color-mix(in srgb, var(--danger) 12%, var(--surface));
|
||||||
|
}
|
||||||
|
:root[data-glass-theme="dark"] .modal-backdrop { background: rgba(2, 5, 14, .68); }
|
||||||
|
:root[data-glass-theme="dark"] .modal { background: var(--surface); }
|
||||||
|
:root[data-glass-theme="dark"] .diff-panel p { color: var(--muted); }
|
||||||
|
:root[data-glass-theme="dark"] .diff-panel.added {
|
||||||
|
border-color: color-mix(in srgb, var(--success) 42%, var(--line));
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="color-scheme" content="light" />
|
<meta name="color-scheme" content="light dark" />
|
||||||
<meta name="theme-color" content="#f3f6fb" />
|
<meta name="theme-color" content="#0f1526" id="firmwareWorkbenchThemeColor" />
|
||||||
<title>座椅固件开发工作台 · 511 工程</title>
|
<title>座椅固件开发工作台 · 511 工程</title>
|
||||||
<link rel="icon" href="/icons/app-icon-192.png" />
|
<link rel="icon" href="/icons/app-icon-192.png" />
|
||||||
<link rel="stylesheet" href="/firmware-workbench.css?v=5" />
|
<script src="/firmware-workbench-theme.js?v=1"></script>
|
||||||
|
<link rel="stylesheet" href="/firmware-workbench.css?v=6" />
|
||||||
<script src="/vendor/lucide/0.468.0/lucide.min.js" defer></script>
|
<script src="/vendor/lucide/0.468.0/lucide.min.js" defer></script>
|
||||||
<script src="/firmware-workbench.js?v=3" defer></script>
|
<script src="/firmware-workbench.js?v=3" defer></script>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
document.documentElement.style.colorScheme = theme;
|
document.documentElement.style.colorScheme = theme;
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" href="/firmware-workbench-entry.css?v=1" />
|
<link rel="stylesheet" href="/firmware-workbench-entry.css?v=2" />
|
||||||
<script src="/vendor/lucide/0.468.0/lucide.min.js" defer></script>
|
<script src="/vendor/lucide/0.468.0/lucide.min.js" defer></script>
|
||||||
<script src="/vendor/three/0.147.0/three.min.js" defer></script>
|
<script src="/vendor/three/0.147.0/three.min.js" defer></script>
|
||||||
<script src="/vendor/three/0.147.0/fflate.min.js" defer></script>
|
<script src="/vendor/three/0.147.0/fflate.min.js" defer></script>
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
<script src="/self-extension.js?v=pet-settings-53-performance" defer></script>
|
<script src="/self-extension.js?v=pet-settings-53-performance" defer></script>
|
||||||
<script src="/assistant-chat.js?v=codex-assistant-34" defer></script>
|
<script src="/assistant-chat.js?v=codex-assistant-34" defer></script>
|
||||||
<script src="/energy-monitor.js?v=energy-monitor-5-performance" defer></script>
|
<script src="/energy-monitor.js?v=energy-monitor-5-performance" defer></script>
|
||||||
<script src="/firmware-workbench-entry.js?v=2" defer></script>
|
<script src="/firmware-workbench-entry.js?v=3" defer></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="console-v2">
|
<body class="console-v2">
|
||||||
<div id="app" aria-busy="true"></div>
|
<div id="app" aria-busy="true"></div>
|
||||||
|
|||||||
@@ -1493,7 +1493,7 @@ button.v2-extension-capability.preview {
|
|||||||
/* Dialogs ---------------------------------------------------------------- */
|
/* Dialogs ---------------------------------------------------------------- */
|
||||||
|
|
||||||
.v2-extension-dialog {
|
.v2-extension-dialog {
|
||||||
width: min(650px, calc(100vw - 40px));
|
width: min(780px, calc(100vw - 32px));
|
||||||
max-height: calc(100dvh - 40px);
|
max-height: calc(100dvh - 40px);
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -2307,7 +2307,7 @@ form > .v2-extension-primary {
|
|||||||
/* GSCU1B TCP runtime controls ------------------------------------------- */
|
/* GSCU1B TCP runtime controls ------------------------------------------- */
|
||||||
|
|
||||||
.v2-gscu-tcp-dialog {
|
.v2-gscu-tcp-dialog {
|
||||||
width: min(720px, calc(100vw - 30px));
|
width: min(960px, calc(100vw - 30px));
|
||||||
}
|
}
|
||||||
|
|
||||||
.v2-gscu-status {
|
.v2-gscu-status {
|
||||||
@@ -2934,9 +2934,9 @@ form > .v2-extension-primary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.v2-nfc-dialog {
|
.v2-nfc-dialog {
|
||||||
width: min(900px, calc(100vw - 28px));
|
width: min(1180px, calc(100vw - 28px));
|
||||||
max-width: 900px;
|
max-width: 1180px;
|
||||||
max-height: min(860px, calc(100dvh - 28px));
|
max-height: min(900px, calc(100dvh - 28px));
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
color: #203d3d;
|
color: #203d3d;
|
||||||
@@ -4596,8 +4596,8 @@ form > .v2-extension-primary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.v2-pet-settings-dialog {
|
.v2-pet-settings-dialog {
|
||||||
width: min(760px, calc(100vw - 32px));
|
width: min(980px, calc(100vw - 32px));
|
||||||
height: min(760px, calc(100dvh - 32px));
|
height: min(860px, calc(100dvh - 32px));
|
||||||
max-height: calc(100dvh - 32px);
|
max-height: calc(100dvh - 32px);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,33 @@
|
|||||||
const CACHE_VERSION = "cognitive-agent-pad-v322-n7-firmware-merge";
|
const CACHE_VERSION = "cognitive-agent-pad-v323-dialog-theme";
|
||||||
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
|
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
|
||||||
const RUNTIME_CACHE = `${CACHE_VERSION}-runtime`;
|
const RUNTIME_CACHE = `${CACHE_VERSION}-runtime`;
|
||||||
const APP_SHELL = [
|
const APP_SHELL = [
|
||||||
"/",
|
"/",
|
||||||
"/index.html",
|
"/index.html",
|
||||||
"/styles.css?v=dual-seat-23",
|
"/styles.css?v=dual-seat-24-dialog-size",
|
||||||
"/network.js?v=android-pad-2",
|
"/network.js?v=android-pad-2",
|
||||||
"/app.js?v=dual-seat-145-n7-dispatch",
|
"/app.js?v=dual-seat-145-n7-dispatch",
|
||||||
"/gesture-control.js?v=android-pad-9",
|
"/gesture-control.js?v=android-pad-9",
|
||||||
"/pwa.js?v=android-pad-3",
|
"/pwa.js?v=android-pad-3",
|
||||||
"/console-v2.css?v=delivery-state-69",
|
"/console-v2.css?v=delivery-state-69",
|
||||||
"/console-v2.js?v=local-first-77-performance",
|
"/console-v2.js?v=local-first-77-performance",
|
||||||
"/self-extension.css?v=pet-settings-52",
|
"/self-extension.css?v=pet-settings-54-dialog-size",
|
||||||
"/self-extension.js?v=pet-settings-53-performance",
|
"/self-extension.js?v=pet-settings-53-performance",
|
||||||
"/speech-input.css?v=sensevoice-7",
|
"/speech-input.css?v=sensevoice-7",
|
||||||
"/speech-input.js?v=sensevoice-13",
|
"/speech-input.js?v=sensevoice-13",
|
||||||
"/speech-audio-worklet.js?v=sensevoice-5",
|
"/speech-audio-worklet.js?v=sensevoice-5",
|
||||||
"/assistant-chat.css?v=codex-assistant-29",
|
"/assistant-chat.css?v=codex-assistant-29",
|
||||||
"/assistant-chat.js?v=codex-assistant-34",
|
"/assistant-chat.js?v=codex-assistant-34",
|
||||||
"/energy-monitor.css?v=energy-monitor-4",
|
"/energy-monitor.css?v=energy-monitor-5-dialog-size",
|
||||||
"/energy-monitor.js?v=energy-monitor-5-performance",
|
"/energy-monitor.js?v=energy-monitor-5-performance",
|
||||||
"/ui-consistency.css?v=spatial-ui-8",
|
"/ui-consistency.css?v=spatial-ui-8",
|
||||||
"/codepen-glass-theme.css?v=creative-cloud-6-performance",
|
"/codepen-glass-theme.css?v=creative-cloud-6-performance",
|
||||||
"/vue-ui.js?v=vue-presentation-3",
|
"/vue-ui.js?v=vue-presentation-3",
|
||||||
"/firmware-workbench-entry.css?v=1",
|
"/firmware-workbench-entry.css?v=2",
|
||||||
"/firmware-workbench-entry.js?v=2",
|
"/firmware-workbench-entry.js?v=3",
|
||||||
"/firmware-workbench.html",
|
"/firmware-workbench.html",
|
||||||
"/firmware-workbench.css?v=5",
|
"/firmware-workbench-theme.js?v=1",
|
||||||
|
"/firmware-workbench.css?v=6",
|
||||||
"/firmware-workbench.js?v=3",
|
"/firmware-workbench.js?v=3",
|
||||||
"/assets/pets/self-extension-cat.png?v=3",
|
"/assets/pets/self-extension-cat.png?v=3",
|
||||||
"/assets/pets/self-extension-cat-entrance.png?v=3",
|
"/assets/pets/self-extension-cat-entrance.png?v=3",
|
||||||
|
|||||||
@@ -395,8 +395,9 @@ body.mode-editor-open {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mode-gallery {
|
.mode-gallery {
|
||||||
width: min(1080px, calc(100vw - 32px));
|
width: min(1320px, calc(100vw - 32px));
|
||||||
max-height: min(680px, calc(100dvh - 32px));
|
height: min(860px, calc(100dvh - 32px));
|
||||||
|
max-height: min(860px, calc(100dvh - 32px));
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto auto minmax(0, 1fr) auto;
|
grid-template-rows: auto auto minmax(0, 1fr) auto;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
@@ -863,7 +864,7 @@ body.mode-editor-open {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mode-editor {
|
.mode-editor {
|
||||||
width: min(760px, calc(100vw - 28px));
|
width: min(1040px, calc(100vw - 28px));
|
||||||
height: min(900px, calc(100dvh - 28px));
|
height: min(900px, calc(100dvh - 28px));
|
||||||
max-height: calc(100dvh - 28px);
|
max-height: calc(100dvh - 28px);
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ const runtimeFiles = [
|
|||||||
"assistant-chat.js",
|
"assistant-chat.js",
|
||||||
"energy-monitor.js",
|
"energy-monitor.js",
|
||||||
"firmware-workbench-entry.js",
|
"firmware-workbench-entry.js",
|
||||||
|
"firmware-workbench-theme.js",
|
||||||
"firmware-workbench.js",
|
"firmware-workbench.js",
|
||||||
"firmware-workbench.html",
|
"firmware-workbench.html",
|
||||||
"styles.css",
|
"styles.css",
|
||||||
|
|||||||
@@ -1017,7 +1017,7 @@ operations:
|
|||||||
) as response:
|
) as response:
|
||||||
extension_script = response.read().decode("utf-8")
|
extension_script = response.read().decode("utf-8")
|
||||||
with self.opener.open(
|
with self.opener.open(
|
||||||
f"{self.base_url}/self-extension.css?v=pet-settings-52", timeout=3
|
f"{self.base_url}/self-extension.css?v=pet-settings-54-dialog-size", timeout=3
|
||||||
) as response:
|
) as response:
|
||||||
extension_styles = response.read().decode("utf-8").replace("\r\n", "\n")
|
extension_styles = response.read().decode("utf-8").replace("\r\n", "\n")
|
||||||
with self.opener.open(
|
with self.opener.open(
|
||||||
@@ -1029,7 +1029,7 @@ operations:
|
|||||||
) as response:
|
) as response:
|
||||||
energy_script = response.read().decode("utf-8")
|
energy_script = response.read().decode("utf-8")
|
||||||
with self.opener.open(
|
with self.opener.open(
|
||||||
f"{self.base_url}/energy-monitor.css?v=energy-monitor-4", timeout=3
|
f"{self.base_url}/energy-monitor.css?v=energy-monitor-5-dialog-size", timeout=3
|
||||||
) as response:
|
) as response:
|
||||||
energy_styles = response.read().decode("utf-8")
|
energy_styles = response.read().decode("utf-8")
|
||||||
with self.opener.open(
|
with self.opener.open(
|
||||||
@@ -1385,18 +1385,19 @@ operations:
|
|||||||
self.assertIn('canvas.addEventListener("webglcontextlost"', app_script)
|
self.assertIn('canvas.addEventListener("webglcontextlost"', app_script)
|
||||||
self.assertIn('"cognitive-agent:module-change"', app_script)
|
self.assertIn('"cognitive-agent:module-change"', app_script)
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
'const CACHE_VERSION = "cognitive-agent-pad-v322-n7-firmware-merge"',
|
'const CACHE_VERSION = "cognitive-agent-pad-v323-dialog-theme"',
|
||||||
service_worker,
|
service_worker,
|
||||||
)
|
)
|
||||||
self.assertIn('/console-v2.css?v=delivery-state-69', service_worker)
|
self.assertIn('/console-v2.css?v=delivery-state-69', service_worker)
|
||||||
self.assertIn('/console-v2.js?v=local-first-77-performance', service_worker)
|
self.assertIn('/console-v2.js?v=local-first-77-performance', service_worker)
|
||||||
self.assertIn('/assistant-chat.css?v=codex-assistant-29', service_worker)
|
self.assertIn('/assistant-chat.css?v=codex-assistant-29', service_worker)
|
||||||
self.assertIn('/assistant-chat.js?v=codex-assistant-34', service_worker)
|
self.assertIn('/assistant-chat.js?v=codex-assistant-34', service_worker)
|
||||||
self.assertIn('/energy-monitor.css?v=energy-monitor-4', service_worker)
|
self.assertIn('/energy-monitor.css?v=energy-monitor-5-dialog-size', service_worker)
|
||||||
self.assertIn('/energy-monitor.js?v=energy-monitor-5-performance', service_worker)
|
self.assertIn('/energy-monitor.js?v=energy-monitor-5-performance', service_worker)
|
||||||
self.assertIn('"/app.js?v=dual-seat-145-n7-dispatch"', service_worker)
|
self.assertIn('"/app.js?v=dual-seat-145-n7-dispatch"', service_worker)
|
||||||
self.assertIn('/firmware-workbench-entry.css?v=1', service_worker)
|
self.assertIn('/firmware-workbench-entry.css?v=2', service_worker)
|
||||||
self.assertIn('/firmware-workbench-entry.js?v=2', service_worker)
|
self.assertIn('/firmware-workbench-entry.js?v=3', service_worker)
|
||||||
|
self.assertIn('/firmware-workbench-theme.js?v=1', service_worker)
|
||||||
self.assertIn('/firmware-workbench.html', service_worker)
|
self.assertIn('/firmware-workbench.html', service_worker)
|
||||||
self.assertIn('"/speech-input.js?v=sensevoice-13"', 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-input.css?v=sensevoice-7"', 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():
|
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")
|
service_worker = (ROOT / "apps/web-console/service-worker.js").read_text(encoding="utf-8")
|
||||||
assert (
|
assert (
|
||||||
'const CACHE_VERSION = "cognitive-agent-pad-v322-n7-firmware-merge"'
|
'const CACHE_VERSION = "cognitive-agent-pad-v323-dialog-theme"'
|
||||||
in service_worker
|
in service_worker
|
||||||
)
|
)
|
||||||
assert '"/assistant-chat.css?v=codex-assistant-29"' in service_worker
|
assert '"/assistant-chat.css?v=codex-assistant-29"' in service_worker
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ def test_energy_monitor_assets_are_versioned_and_cached() -> None:
|
|||||||
service_worker = source("service-worker.js")
|
service_worker = source("service-worker.js")
|
||||||
|
|
||||||
for asset in (
|
for asset in (
|
||||||
"/energy-monitor.css?v=energy-monitor-4",
|
"/energy-monitor.css?v=energy-monitor-5-dialog-size",
|
||||||
"/energy-monitor.js?v=energy-monitor-5-performance",
|
"/energy-monitor.js?v=energy-monitor-5-performance",
|
||||||
):
|
):
|
||||||
assert f'"{asset}"' in service_worker
|
assert f'"{asset}"' in service_worker
|
||||||
@@ -41,7 +41,7 @@ def test_energy_monitor_assets_are_versioned_and_cached() -> None:
|
|||||||
"/energy-monitor.js?v=energy-monitor-5-performance"
|
"/energy-monitor.js?v=energy-monitor-5-performance"
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
'const CACHE_VERSION = "cognitive-agent-pad-v322-n7-firmware-merge"'
|
'const CACHE_VERSION = "cognitive-agent-pad-v323-dialog-theme"'
|
||||||
in service_worker
|
in service_worker
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -51,21 +51,59 @@ def test_workbench_exposes_artifact_actions_and_always_starts_a_new_task() -> No
|
|||||||
assert "已发布,待车机端下载升级" not in script
|
assert "已发布,待车机端下载升级" not in script
|
||||||
assert 'id = "firmwareWorkbenchToggle"' in entry
|
assert 'id = "firmwareWorkbenchToggle"' in entry
|
||||||
assert 'className = "firmware-workbench-layer"' in entry
|
assert 'className = "firmware-workbench-layer"' in entry
|
||||||
assert "/firmware-workbench-entry.js?v=2" in index
|
assert "/firmware-workbench-entry.js?v=3" in index
|
||||||
assert "/firmware-workbench-entry.css?v=1" in index
|
assert "/firmware-workbench-entry.css?v=2" in index
|
||||||
for asset in (
|
for asset in (
|
||||||
"/firmware-workbench-entry.css?v=1",
|
"/firmware-workbench-entry.css?v=2",
|
||||||
"/firmware-workbench-entry.js?v=2",
|
"/firmware-workbench-entry.js?v=3",
|
||||||
"/firmware-workbench.html",
|
"/firmware-workbench.html",
|
||||||
"/firmware-workbench.css?v=5",
|
"/firmware-workbench-theme.js?v=1",
|
||||||
|
"/firmware-workbench.css?v=6",
|
||||||
"/firmware-workbench.js?v=3",
|
"/firmware-workbench.js?v=3",
|
||||||
):
|
):
|
||||||
assert f'"{asset}"' in worker
|
assert f'"{asset}"' in worker
|
||||||
for runtime_file in (
|
for runtime_file in (
|
||||||
"firmware-workbench-entry.js",
|
"firmware-workbench-entry.js",
|
||||||
"firmware-workbench-entry.css",
|
"firmware-workbench-entry.css",
|
||||||
|
"firmware-workbench-theme.js",
|
||||||
"firmware-workbench.html",
|
"firmware-workbench.html",
|
||||||
"firmware-workbench.js",
|
"firmware-workbench.js",
|
||||||
"firmware-workbench.css",
|
"firmware-workbench.css",
|
||||||
):
|
):
|
||||||
assert f'"{runtime_file}"' in vite
|
assert f'"{runtime_file}"' in vite
|
||||||
|
|
||||||
|
|
||||||
|
def test_workbench_inherits_live_theme_and_uses_the_larger_dialog_frame() -> None:
|
||||||
|
html = source("firmware-workbench.html")
|
||||||
|
entry = source("firmware-workbench-entry.js")
|
||||||
|
entry_styles = source("firmware-workbench-entry.css")
|
||||||
|
workbench_styles = source("firmware-workbench.css")
|
||||||
|
theme = source("firmware-workbench-theme.js")
|
||||||
|
|
||||||
|
assert 'content="light dark"' in html
|
||||||
|
assert 'id="firmwareWorkbenchThemeColor"' in html
|
||||||
|
assert '/firmware-workbench-theme.js?v=1' in html
|
||||||
|
assert 'data-glass-theme="dark"' in workbench_styles
|
||||||
|
assert 'window.parent?.document?.documentElement?.dataset?.glassTheme' in theme
|
||||||
|
assert 'event.data?.type !== "cognitive-agent:theme-change"' in theme
|
||||||
|
assert 'window.addEventListener("cognitive-agent:theme-change"' in entry
|
||||||
|
assert 'attributeFilter: ["data-glass-theme"]' in entry
|
||||||
|
assert 'width: min(1480px, 100%);' in entry_styles
|
||||||
|
assert 'height: min(900px, 100%);' in entry_styles
|
||||||
|
assert 'width: min(1040px, 100%);' in workbench_styles
|
||||||
|
assert 'max-height: min(820px, calc(100dvh - 48px));' in workbench_styles
|
||||||
|
|
||||||
|
|
||||||
|
def test_peer_dialogs_share_the_expanded_desktop_size_contract() -> None:
|
||||||
|
gallery = source("styles.css")
|
||||||
|
energy = source("energy-monitor.css")
|
||||||
|
extension = source("self-extension.css")
|
||||||
|
|
||||||
|
assert 'width: min(1320px, calc(100vw - 32px));' in gallery
|
||||||
|
assert 'height: min(860px, calc(100dvh - 32px));' in gallery
|
||||||
|
assert 'width: min(1480px, 100%);' in energy
|
||||||
|
assert 'height: min(900px, 100%);' in energy
|
||||||
|
assert 'width: min(780px, calc(100vw - 32px));' in extension
|
||||||
|
assert 'width: min(960px, calc(100vw - 30px));' in extension
|
||||||
|
assert 'width: min(1180px, calc(100vw - 28px));' in extension
|
||||||
|
assert 'width: min(980px, calc(100vw - 32px));' in extension
|
||||||
|
|||||||
@@ -99,5 +99,5 @@ def test_performance_assets_have_a_new_cache_generation() -> None:
|
|||||||
):
|
):
|
||||||
assert asset in html
|
assert asset in html
|
||||||
assert f'"{asset}"' in worker
|
assert f'"{asset}"' in worker
|
||||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v322-n7-firmware-merge"' in worker
|
assert 'const CACHE_VERSION = "cognitive-agent-pad-v323-dialog-theme"' in worker
|
||||||
assert '"/codepen-glass-theme.css?v=creative-cloud-6-performance"' in worker
|
assert '"/codepen-glass-theme.css?v=creative-cloud-6-performance"' in worker
|
||||||
|
|||||||
@@ -45,16 +45,16 @@ def test_theme_asset_versions_are_consistent_with_the_pwa_shell() -> None:
|
|||||||
service_worker = source("service-worker.js")
|
service_worker = source("service-worker.js")
|
||||||
|
|
||||||
for source_asset, cached_asset in (
|
for source_asset, cached_asset in (
|
||||||
('import "../styles.css"', "/styles.css?v=dual-seat-23"),
|
('import "../styles.css"', "/styles.css?v=dual-seat-24-dialog-size"),
|
||||||
('import "../console-v2.css"', "/console-v2.css?v=delivery-state-69"),
|
('import "../console-v2.css"', "/console-v2.css?v=delivery-state-69"),
|
||||||
('import "../self-extension.css"', "/self-extension.css?v=pet-settings-52"),
|
('import "../self-extension.css"', "/self-extension.css?v=pet-settings-54-dialog-size"),
|
||||||
('import "../speech-input.css"', "/speech-input.css?v=sensevoice-7"),
|
('import "../speech-input.css"', "/speech-input.css?v=sensevoice-7"),
|
||||||
('import "../codepen-glass-theme.css"', "/codepen-glass-theme.css?v=creative-cloud-6-performance"),
|
('import "../codepen-glass-theme.css"', "/codepen-glass-theme.css?v=creative-cloud-6-performance"),
|
||||||
):
|
):
|
||||||
assert source_asset in main
|
assert source_asset in main
|
||||||
assert f'"{cached_asset}"' in service_worker
|
assert f'"{cached_asset}"' in service_worker
|
||||||
assert 'import "./styles/design-system.css"' in main
|
assert 'import "./styles/design-system.css"' in main
|
||||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v322-n7-firmware-merge"' in service_worker
|
assert 'const CACHE_VERSION = "cognitive-agent-pad-v323-dialog-theme"' in service_worker
|
||||||
|
|
||||||
|
|
||||||
def test_reference_glass_theme_covers_the_complete_workspace() -> None:
|
def test_reference_glass_theme_covers_the_complete_workspace() -> None:
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ def test_vue_vite_application_is_the_primary_frontend_entry() -> None:
|
|||||||
assert package["scripts"]["build"] == "vite build"
|
assert package["scripts"]["build"] == "vite build"
|
||||||
assert 'import vue from "@vitejs/plugin-vue"' in vite
|
assert 'import vue from "@vitejs/plugin-vue"' in vite
|
||||||
assert 'outDir: outputRoot' in vite
|
assert 'outDir: outputRoot' in vite
|
||||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v322-n7-firmware-merge"' in service_worker
|
assert 'const CACHE_VERSION = "cognitive-agent-pad-v323-dialog-theme"' in service_worker
|
||||||
assert "unpkg.com" not in html
|
assert "unpkg.com" not in html
|
||||||
assert "cdn.jsdelivr.net" not in html
|
assert "cdn.jsdelivr.net" not in html
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user