diff --git a/apps/presentation/dashboard/src/features/personal-workspace/lark-settings-page.tsx b/apps/presentation/dashboard/src/features/personal-workspace/lark-settings-page.tsx index 2b013d371d..1f9470e3e8 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/lark-settings-page.tsx +++ b/apps/presentation/dashboard/src/features/personal-workspace/lark-settings-page.tsx @@ -570,7 +570,7 @@ export function LarkSettingsPage({

{t("lark.goalConnections", { count: connections.filter((connection) => connection.app_ref === app.app_ref).length })}{app.ready && !app.reply_ready ? ` · ${t("lark.autoReplyUnavailable")}` : ""}

))} - {appsLoading ?

{t("lark.loading")}

: apps.length === 0 && !appsError ?

{t("lark.noProfiles")}

: null} + {appsLoading ?

{t("lark.loading")}

: apps.length === 0 && !appsError ?

{t("lark.noProfiles")}

: null} ) : null} @@ -609,7 +609,7 @@ export function LarkSettingsPage({ ; })} - {filteredConnections.length === 0 ?

{t("lark.noConnections")}

: null} + {filteredConnections.length === 0 ?

{t("lark.noConnections")}

: null} ) : null} diff --git a/apps/presentation/dashboard/src/features/personal-workspace/personal-workspace.css b/apps/presentation/dashboard/src/features/personal-workspace/personal-workspace.css index f3061f1a22..0af36c0a02 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/personal-workspace.css +++ b/apps/presentation/dashboard/src/features/personal-workspace/personal-workspace.css @@ -798,7 +798,7 @@ button.personal-execution-chip:focus-visible { outline: 2px solid #0070f3; outli .personal-machine-unavailable { display: grid; justify-items: start; gap: 8px; min-height: 180px; padding: 26px; border: 1px dashed var(--pw-line-strong); border-radius: 14px; background: #fff; color: var(--pw-muted); } .personal-machine-unavailable strong { color: var(--pw-text); font-size: var(--text-body); line-height: var(--leading-body); } .personal-machine-unavailable p { max-width: 540px; margin: 0; font-size: var(--text-caption); line-height: var(--leading-caption); } -.personal-lark-loading, .personal-lark-empty { display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 130px; color: var(--pw-muted); font-size: var(--text-body); line-height: var(--leading-body); } +.personal-lark-loading { display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 130px; color: var(--pw-muted); font-size: var(--text-body); line-height: var(--leading-body); } .personal-lark-apps { max-width: 1180px; margin: 0 auto; } .personal-lark-app-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; color: var(--pw-muted); font-size: var(--text-caption); line-height: var(--leading-caption); } .personal-lark-app-actions { display: flex; align-items: center; gap: 8px; } diff --git a/examples/personal-workspace-browser/evidence/lark-context-help/catalog-after-narrow.png b/examples/personal-workspace-browser/evidence/lark-context-help/catalog-after-narrow.png new file mode 100644 index 0000000000..267e12a82e Binary files /dev/null and b/examples/personal-workspace-browser/evidence/lark-context-help/catalog-after-narrow.png differ diff --git a/examples/personal-workspace-browser/evidence/lark-context-help/catalog-before-narrow.png b/examples/personal-workspace-browser/evidence/lark-context-help/catalog-before-narrow.png new file mode 100644 index 0000000000..f79491b8db Binary files /dev/null and b/examples/personal-workspace-browser/evidence/lark-context-help/catalog-before-narrow.png differ diff --git a/examples/personal-workspace-browser/evidence/lark-context-help/connections-after-narrow.png b/examples/personal-workspace-browser/evidence/lark-context-help/connections-after-narrow.png new file mode 100644 index 0000000000..0edcf009b8 Binary files /dev/null and b/examples/personal-workspace-browser/evidence/lark-context-help/connections-after-narrow.png differ diff --git a/examples/personal-workspace-browser/evidence/lark-context-help/progressive-desktop.png b/examples/personal-workspace-browser/evidence/lark-context-help/progressive-desktop.png new file mode 100644 index 0000000000..58384e57e5 Binary files /dev/null and b/examples/personal-workspace-browser/evidence/lark-context-help/progressive-desktop.png differ diff --git a/examples/personal-workspace-browser/progressive-loading.mjs b/examples/personal-workspace-browser/progressive-loading.mjs index f13dd97253..0ec62c74b5 100644 --- a/examples/personal-workspace-browser/progressive-loading.mjs +++ b/examples/personal-workspace-browser/progressive-loading.mjs @@ -37,6 +37,15 @@ async function verifyLarkLoading(browser, url, collectCoverage) { }); }}); const {page} = context; + const emptyHelp = page.getByRole("button", {name: "暂无飞书应用档案", exact: true}); + const emptyExplanation = page.getByRole("tooltip").filter({hasText: "暂无飞书应用档案"}); + async function verifyCompactHelp(explanation) { + const layout = await explanation.locator("p").evaluate(node => { + const style = getComputedStyle(node); + return {minHeight: parseFloat(style.minHeight) || 0, leading: parseFloat(style.lineHeight)}; + }); + if (!Number.isFinite(layout.leading) || layout.minHeight > layout.leading) throw new Error("Optional help inherited full empty-state spacing"); + } async function openSettings() { const menu = page.locator(".personal-mobile-menu"); if (await menu.isVisible()) await menu.click(); @@ -51,7 +60,7 @@ async function verifyLarkLoading(browser, url, collectCoverage) { // as an empty directory, regardless of the component's state variable names. await appTab.getByText("…", {exact: true}).waitFor(); await page.screenshot({path: resolve(outputDir, "lark-catalog-pending-desktop.png"), animations: "disabled"}); - if (await appTab.getByText("0", {exact: true}).count() || await page.locator(".personal-lark-empty").count()) throw new Error("Pending catalog displayed a false empty directory"); + if (await appTab.getByText("0", {exact: true}).count() || await emptyHelp.count()) throw new Error("Pending catalog displayed a false empty directory"); if ((await page.locator(".personal-lark-app-toolbar > span").innerText()) !== "… 个可复用 App") throw new Error("Pending catalog toolbar displayed a false App count"); await page.setViewportSize({width: 390, height: 844}); if (await page.evaluate(() => document.documentElement.scrollWidth > innerWidth)) throw new Error("Pending Lark catalog overflows at 390px"); @@ -78,19 +87,42 @@ async function verifyLarkLoading(browser, url, collectCoverage) { revision = 3; await page.getByRole("button", {name: "刷新配置并重试核验", exact: true}).click(); await appTab.getByText("0", {exact: true}).waitFor(); - await page.locator(".personal-lark-empty").waitFor(); + await emptyHelp.waitFor(); + if (await emptyExplanation.isVisible()) throw new Error("Empty catalog explanation was expanded by default"); + await page.screenshot({path: resolve(outputDir, "lark-catalog-empty-desktop.png"), animations: "disabled"}); + // Empty is a confirmed source state. Its optional explanation remains + // reachable through the same keyboard/tap help as the rest of Settings. + await emptyHelp.focus(); + await emptyExplanation.waitFor(); if (await page.locator(".personal-lark-app-card").count() || catalogs !== 3 || probes.length !== 6) throw new Error("Empty catalog retained stale profiles or started verification"); + await page.keyboard.press("Escape"); + await page.setViewportSize({width: 390, height: 844}); + await emptyHelp.click(); + await emptyExplanation.waitFor(); + if (await page.evaluate(() => document.documentElement.scrollWidth > innerWidth)) throw new Error("Empty catalog help overflows at 390px"); + await page.screenshot({path: resolve(outputDir, "lark-catalog-empty-narrow.png"), animations: "disabled"}); + await verifyCompactHelp(emptyExplanation); + await page.keyboard.press("Escape"); + await page.locator(".personal-lark-tabs").getByRole("button", {name: /^连接/u}).click(); + await page.getByRole("button", {name: "暂无 Goal 连接", exact: true}).click(); + const connectionExplanation = page.getByRole("tooltip").filter({hasText: "暂无 Goal 连接"}); + await connectionExplanation.waitFor(); + await verifyCompactHelp(connectionExplanation); + await page.screenshot({path: resolve(outputDir, "lark-connections-empty-narrow.png"), animations: "disabled"}); + await page.keyboard.press("Escape"); + await appTab.click(); + await page.setViewportSize({width: 1512, height: 982}); // A failed read is unknown, never a confirmed zero; its visible error and // retry stay available without retaining the previous directory's cards. revision = 4; await page.getByRole("button", {name: "刷新配置并重试核验", exact: true}).click(); await page.locator(".personal-notification-error").waitFor(); await page.screenshot({path: resolve(outputDir, "lark-catalog-failed.png"), animations: "disabled"}); - if (await appTab.getByText("…", {exact: true}).count() !== 1 || (await page.locator(".personal-lark-app-toolbar > span").innerText()) !== "… 个可复用 App" || await page.locator(".personal-lark-empty, .personal-lark-app-card").count() || catalogs !== 4 || probes.length !== 6) throw new Error("Failed catalog masqueraded as an empty or stale directory"); + if (await appTab.getByText("…", {exact: true}).count() !== 1 || (await page.locator(".personal-lark-app-toolbar > span").innerText()) !== "… 个可复用 App" || await page.locator(".personal-lark-app-card").count() || await emptyHelp.count() || catalogs !== 4 || probes.length !== 6) throw new Error("Failed catalog masqueraded as an empty or stale directory"); revision = 5; await page.getByRole("button", {name: "刷新配置并重试核验", exact: true}).click(); await page.locator(".personal-lark-app-card").filter({hasText: "slow 5"}).getByText("自动回复可用", {exact: true}).waitFor(); - if (catalogs !== 5 || probes.length !== 9 || await page.locator(".personal-lark-empty, .personal-notification-error").count()) throw new Error("Failed catalog did not recover without duplicate reads"); + if (catalogs !== 5 || probes.length !== 9 || await emptyHelp.count() || await page.locator(".personal-notification-error").count()) throw new Error("Failed catalog did not recover without duplicate reads"); await page.setViewportSize({width: 390, height: 844}); if (await page.evaluate(() => document.documentElement.scrollWidth > innerWidth)) throw new Error("Lark configuration overflows at 390px"); await page.screenshot({path: resolve(outputDir, "lark-progressive-narrow.png"), animations: "disabled"});