diff --git a/web/storyforge-web-v4/assets/app.js b/web/storyforge-web-v4/assets/app.js index ff666be..0eed9a4 100644 --- a/web/storyforge-web-v4/assets/app.js +++ b/web/storyforge-web-v4/assets/app.js @@ -5794,6 +5794,12 @@ function renderPlaybookScreen() {
先处理你当前真的会用到的 Agent 信息,系统治理内容已移到管理员配置台。
+
+ 主 Agent ${escapeHtml(appState.onelinerProfile?.display_name || "OneLiner")} + ${escapeHtml(currentAssistant ? `当前 ${currentAssistant.name}` : "当前未选 Agent")} + 模型 ${escapeHtml(formatNumber(models.length))} + ${escapeHtml(activeAdminOverrideNotice?.title ? "有管理员覆盖" : "无管理员覆盖")} +
${renderDetailTabs("playbookDetailTab", tabs)} ${activeTab === "workspace" ? `
@@ -6268,6 +6274,12 @@ function renderStrategyScreen() {
先看当前生效,再回看你自己的历史和管理员覆盖,不必再通过多个弹窗来回切。
+
+ 当前生效 ${escapeHtml(formatNumber(safeArray(appState.onelinerGovernanceEffective?.layers).length))} 层 + ${escapeHtml(platformLabel(platform))} 平台策略 + 变更 ${escapeHtml(formatNumber(safeArray(appState.userPolicyAudits).length))} + ${escapeHtml(activeAdminOverrideNotice?.title ? "管理员覆盖生效" : "无管理员覆盖")} +
${renderDetailTabs("strategyDetailTab", tabs)} ${activeTab === "effective" ? `
diff --git a/web/storyforge-web-v4/assets/styles.css b/web/storyforge-web-v4/assets/styles.css index b0e9545..d0fca0d 100644 --- a/web/storyforge-web-v4/assets/styles.css +++ b/web/storyforge-web-v4/assets/styles.css @@ -2040,6 +2040,13 @@ tbody tr:hover { overflow: hidden; } + .panel-subtitle { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + } + .action-row { width: 100%; flex-wrap: nowrap; @@ -2186,6 +2193,17 @@ tbody tr:hover { align-items: flex-start; } + .task-item p, + .entity-card p, + .topic-card p, + .queue-card p, + .review-card p { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + } + .avatar-lg { width: 40px; height: 40px; diff --git a/web/storyforge-web-v4/tests/workbench-pages.test.mjs b/web/storyforge-web-v4/tests/workbench-pages.test.mjs index 6086e5f..bc24df7 100644 --- a/web/storyforge-web-v4/tests/workbench-pages.test.mjs +++ b/web/storyforge-web-v4/tests/workbench-pages.test.mjs @@ -81,6 +81,13 @@ test("strategy navigation and screen are real routes", () => { assert.match(APP, /screenMap\.strategy\.innerHTML = renderStrategyScreen\(\);/); }); +test("strategy screen exposes a compact mobile summary for current governance state", () => { + const source = extractBetween(APP, "function renderStrategyScreen()", "function renderCreditsScreen()"); + assert.match(source, /mobile-only compact-summary-row/); + assert.match(source, /当前生效/); + assert.match(source, /平台策略/); +}); + test("automation screen stays user-facing and excludes admin-only panels", () => { const source = extractBetween(APP, "function renderAutomationScreen()", "function renderOwnedScreen()"); assert.doesNotMatch(source, /renderTenantQuotaPanel\(/); @@ -94,6 +101,7 @@ test("agent screen excludes quota and registry panels and uses page tabs", () => assert.doesNotMatch(source, /renderTenantQuotaPanel\(/); assert.doesNotMatch(source, /renderOneLinerActionRegistryPanel\(/); assert.match(source, /renderDetailTabs\("playbookDetailTab"/); + assert.match(source, /mobile-only compact-summary-row/); assert.match(source, /renderGovernanceSummaryCard\(/); assert.match(source, /open-user-global-policy/); assert.match(source, /open-user-platform-policy/); @@ -122,6 +130,11 @@ test("projects screen uses an adaptive project grid instead of a fixed three-col assert.match(CSS, /\.entity-card\.pad\s*\{[\s\S]*padding:\s*15px/); }); +test("mobile typography clamps subtitles and dense card copy on small screens", () => { + assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.panel-subtitle\s*\{[\s\S]*-webkit-line-clamp:\s*2/); + assert.match(CSS, /@media \(max-width: 760px\)[\s\S]*\.task-item p,[\s\S]*\.review-card p\s*\{[\s\S]*-webkit-line-clamp:\s*3/); +}); + test("dashboard and project screens distinguish auto-connecting from truly disconnected", () => { const dashboard = extractBetween(APP, "function renderDashboardScreen()", "function renderProjectsScreen()"); const projects = extractBetween(APP, "function renderProjectsScreen()", "function getActiveDetailTab(");