Simplify task page around schedule and cron
This commit is contained in:
1 parent
d6cdaff5cf
commit
6d456ec9a0
3 files changed
+186
-129
No files matched your search
@@ -1,5 +1,23 @@
|
||||
# Progress
|
||||
|
||||
## Phase 143 (Tasks page now defaults to schedule and cron execution) — Completed
|
||||
- Scope:
|
||||
- Stop making the tasks page look empty or contradictory when staff are active through cron/ad-hoc sessions but there are no tracked task rows.
|
||||
- Make schedule and cron execution the primary view, with tracked-task boards demoted behind a secondary foldout.
|
||||
- Changed files:
|
||||
- `src/ui/server.ts`
|
||||
- `test/ui-render-smoke.test.ts`
|
||||
- `docs/PROGRESS.md`
|
||||
- Implementation:
|
||||
- Reframed the tasks-page lead copy so it explains that staff activity can come from cron or ad-hoc runtime sessions before anything lands in the tracked task store.
|
||||
- Promoted `Today and next schedule` and `Cron execution board` to the always-visible primary view.
|
||||
- Moved tracked tasks, follow-up items, execution chains, project lanes, live feed, and raw tables behind a `Tracked tasks and follow-up` detail block.
|
||||
- Updated current-task navigation anchors so overview and readiness links land on the new tracked-task summary instead of the old lane anchor.
|
||||
- Verification:
|
||||
- `npm run build`
|
||||
- `npm test`
|
||||
- `npm run smoke:ui`
|
||||
|
||||
## Phase 142 (Documents workbench now includes identity and soul markdown files) — Completed
|
||||
- Scope:
|
||||
- Fix the document workbench so Main and active agents expose their `IDENTITY.md` and `SOUL.md` files instead of hiding them behind an overly narrow core-doc whitelist.
|
||||
|
||||
+157
-123
@@ -1962,7 +1962,7 @@ function buildGlobalVisibilityDetailHref(taskType: GlobalVisibilityTaskRow["task
|
||||
return `${buildHomeHref({ quick: "all" }, true, "overview", language)}#heartbeat-health`;
|
||||
}
|
||||
if (taskType === "current_task") {
|
||||
return `${buildHomeHref({ quick: "all" }, true, "projects-tasks", language)}#task-lane`;
|
||||
return `${buildHomeHref({ quick: "all" }, true, "projects-tasks", language)}#tracked-task-view`;
|
||||
}
|
||||
return `${buildHomeHref({ quick: "all" }, true, "overview", language)}#tool-activity`;
|
||||
}
|
||||
@@ -3473,8 +3473,8 @@ async function renderHtml(
|
||||
)
|
||||
: activeSection === "projects-tasks"
|
||||
? t(
|
||||
"One task hub for schedule, review queue, runtime evidence, and cron execution.",
|
||||
"一个任务中枢,把排程、审阅队列、运行证据和 Cron 执行放在同一页。",
|
||||
"Start with schedule and cron execution. Staff can be active from cron or ad-hoc sessions even when there is no tracked task row yet.",
|
||||
"先看排程和 Cron 执行。员工显示在工作,可能只是 Cron 或临时会话在跑,不一定已经落成可跟踪的任务条目。",
|
||||
)
|
||||
: sectionMeta.blurb;
|
||||
const needsSessionPreview = activeSection === "projects-tasks" || activeSection === "overview";
|
||||
@@ -3640,8 +3640,8 @@ async function renderHtml(
|
||||
`${t("Runtime issues", "运行异常")} ${runtimeIssueCount}`,
|
||||
`${t("Budget risks", "预算风险")} ${budgetRiskCount}`,
|
||||
].join(" · ");
|
||||
const focusHref = `${buildHomeHref({ quick: "all" }, options.compactStatusStrip, "projects-tasks", options.language, options.usageView)}#task-decision-center`;
|
||||
const currentTaskHealthHref = `${buildHomeHref({ quick: "all" }, true, "projects-tasks", options.language, options.usageView)}#task-lane`;
|
||||
const focusHref = `${buildHomeHref({ quick: "all" }, options.compactStatusStrip, "projects-tasks", options.language, options.usageView)}#tracked-task-view`;
|
||||
const currentTaskHealthHref = `${buildHomeHref({ quick: "all" }, true, "projects-tasks", options.language, options.usageView)}#tracked-task-view`;
|
||||
const runtimeCronById = new Map(cronOverview.jobs.map((job) => [job.jobId, job]));
|
||||
const catalogMatchedRuntimeIds = new Set<string>();
|
||||
const catalogCronRows = openclawCronJobs.map((job) => {
|
||||
@@ -4932,128 +4932,162 @@ async function renderHtml(
|
||||
</details>
|
||||
`;
|
||||
const teamUnifiedSection = teamSection;
|
||||
const hasTrackedTaskPanels = tasks.length > 0 || pendingDecisionCount > 0 || taskCertaintyCards.length > 0;
|
||||
const trackedTaskDetailsOpen = pendingDecisionCount > 0 || taskCertaintyCards.length > 0;
|
||||
const trackedTaskSummaryText = hasTrackedTaskPanels
|
||||
? t(
|
||||
`Tracked tasks ${taskCertaintyCards.length} · Follow-up ${pendingDecisionCount}`,
|
||||
`跟踪任务 ${taskCertaintyCards.length} · 待处理 ${pendingDecisionCount}`,
|
||||
)
|
||||
: t("No tracked task rows yet", "还没有跟踪任务条目");
|
||||
const trackedTaskExplanation = hasTrackedTaskPanels
|
||||
? t(
|
||||
"This lower-priority area is only for tracked task rows, decisions, and runtime evidence.",
|
||||
"这块低优先级区域只看可跟踪任务条目、待处理事项和运行证据。",
|
||||
)
|
||||
: liveSessionCount > 0
|
||||
? t(
|
||||
"Staff status comes from live sessions. Cron jobs, heartbeat, and ad-hoc sessions can keep agents busy before anything becomes a tracked task row.",
|
||||
"员工状态来自实时会话。Cron、心跳和临时会话可能已经让智能体在工作,但还没有形成可跟踪的任务条目。",
|
||||
)
|
||||
: t(
|
||||
"There is no tracked task row visible right now. Start here only when you actually use the task store.",
|
||||
"当前还没有可见的跟踪任务条目。只有真正使用任务库时,这里才会出现内容。",
|
||||
);
|
||||
const trackedTaskDetailsBody = hasTrackedTaskPanels
|
||||
? `
|
||||
<section class="task-hub-shell" id="task-hub">
|
||||
<article class="card task-hub-primary" id="task-hub-primary">
|
||||
<div class="overview-command-head">
|
||||
<div>
|
||||
<h2>${escapeHtml(t("Task hub", "任务中枢"))}</h2>
|
||||
<div class="meta">${escapeHtml(t("One place for tracked tasks, follow-up items, and runtime evidence.", "把可跟踪任务、待处理事项和运行证据放在一起。"))}</div>
|
||||
</div>
|
||||
<div>${overviewPrimaryStatus}</div>
|
||||
</div>
|
||||
${taskHubStatCardsHtml}
|
||||
<div class="overview-task-strip">
|
||||
<div>
|
||||
<div class="meta">${escapeHtml(t("Current focus", "当前关注"))}</div>
|
||||
<div class="overview-task-metric">${badge(currentTaskHealth)} ${escapeHtml(t("Confirmed live", "已确认在跑"))} ${taskCertaintyStrongCount} · ${escapeHtml(t("Need follow-up", "需跟进"))} ${taskCertaintyFollowupCount} · ${escapeHtml(t("Needs inspection", "需排查"))} ${taskCertaintyWeakCount}</div>
|
||||
${mappingTaskHint ? `<div class="meta">${escapeHtml(mappingTaskHint)}</div>` : ""}
|
||||
</div>
|
||||
<div class="overview-quick-links">
|
||||
<a class="btn" href="${escapeHtml(currentTaskHealthHref)}">${escapeHtml(t("Open tracked tasks", "查看跟踪任务"))}</a>
|
||||
<a class="btn" href="${escapeHtml(focusHref)}">${escapeHtml(t("Open follow-up items", "查看待处理"))}</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="card" id="task-decision-center">
|
||||
<div class="overview-command-head">
|
||||
<h2>${escapeHtml(t("Waiting for your decision", "等待你决策"))}</h2>
|
||||
<div>${badge(pendingDecisionCount > 0 ? "warn" : "ok", pendingDecisionCount > 0 ? t("Queue active", "队列活跃") : t("Clear", "已清空"))}</div>
|
||||
</div>
|
||||
<div class="meta">${escapeHtml(t("Pending decisions", "待处理事项"))} ${pendingDecisionCount} · ${escapeHtml(t("Approvals", "审批"))} ${pendingApprovalsCount} · ${escapeHtml(t("Unacked alerts", "未确认告警"))} ${actionQueue.counts.unacked}</div>
|
||||
${taskDecisionPreviewHtml}
|
||||
</article>
|
||||
</section>
|
||||
${taskExecutionChainSection}
|
||||
<section class="task-hub-grid task-hub-board-grid">
|
||||
<section class="card" id="task-lane">
|
||||
<h2>${escapeHtml(t("Task lanes", "任务泳道"))}</h2>
|
||||
<div class="meta">${escapeHtml(t("Current focus", "当前关注"))}:${escapeHtml(quickFilterLabel(effectiveQuick, options.language))}</div>
|
||||
${
|
||||
controlCenterMappingTasks.length > 0
|
||||
? `<div class="meta">${escapeHtml(t(`${controlCenterMappingTasks.length} board-only mapping examples are hidden because they are not real execution tasks.`, `已隐藏 ${controlCenterMappingTasks.length} 个看板映射样例(非真实执行任务)。`))}</div>`
|
||||
: ""
|
||||
}
|
||||
<div class="quick-filters">${quickFilters}</div>
|
||||
<form method="GET" action="/" class="filters">
|
||||
<input type="hidden" name="section" value="${escapeHtml(options.section)}" />
|
||||
<input type="hidden" name="lang" value="${escapeHtml(options.language)}" />
|
||||
<input type="hidden" name="quick" value="${escapeHtml(effectiveQuick)}" />
|
||||
<input type="hidden" name="compact" value="${options.compactStatusStrip ? "1" : "0"}" />
|
||||
<input type="hidden" name="usage_view" value="${options.usageView === "today" ? "today" : "cumulative"}" />
|
||||
<div>
|
||||
<label for="status">${escapeHtml(t("Status", "状态"))}</label>
|
||||
<select id="status" name="status">
|
||||
${renderSelectOptions(
|
||||
[{ value: "", label: t("All", "全部") }, ...TASK_STATES.map((state) => ({ value: state, label: taskStateLabel(state, options.language) }))],
|
||||
filters.status ?? "",
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="owner">${escapeHtml(t("Agent", "智能体"))}</label>
|
||||
<select id="owner" name="owner">
|
||||
${renderSelectOptions(
|
||||
[{ value: "", label: t("All", "全部") }, ...ownerOptions.map((owner) => ({ value: owner, label: owner }))],
|
||||
filters.owner ?? "",
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="project">${escapeHtml(t("Project", "项目"))}</label>
|
||||
<select id="project" name="project">
|
||||
${renderSelectOptions(
|
||||
[{ value: "", label: t("All", "全部") }, ...projectOptions.map((project) => ({ value: project, label: project }))],
|
||||
filters.project ?? "",
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-actions">
|
||||
<button class="btn" type="submit">${escapeHtml(t("Apply", "应用"))}</button>
|
||||
<a href="${escapeHtml(clearHref)}">${escapeHtml(t("Clear filters", "清空筛选"))}</a>
|
||||
</div>
|
||||
</form>
|
||||
${taskBoard}
|
||||
<div style="height:10px;"></div>
|
||||
<h3 style="margin:0 0 6px 0;">${escapeHtml(t("Task groups (native view)", "任务分组列表(原生视图)"))}</h3>
|
||||
${taskGroupedListHtml}
|
||||
${
|
||||
controlCenterMappingTasks.length === 0
|
||||
? ""
|
||||
: `<details class="compact-table-details" style="margin-top:12px;" open>
|
||||
<summary>${escapeHtml(t("Open board mapping examples (non-executing)", "查看看板映射样例(不执行任务)"))}</summary>
|
||||
<div class="fold-body">
|
||||
<table>
|
||||
<thead><tr><th>${escapeHtml(t("Example task", "样例任务"))}</th><th>${escapeHtml(t("Label", "标签"))}</th><th>${escapeHtml(t("Status", "状态"))}</th></tr></thead>
|
||||
<tbody>${mappingTaskRows}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</details>`
|
||||
}
|
||||
</section>
|
||||
<div class="task-hub-sidebar">
|
||||
<section class="card" id="project-lane">
|
||||
<h2>${escapeHtml(t("Project lanes", "项目泳道"))}</h2>
|
||||
${projectBoard}
|
||||
</section>
|
||||
<section class="card" id="task-live-feed">
|
||||
<h2>${escapeHtml(t("Live activity feed", "实时活动流"))}</h2>
|
||||
<div class="meta">${escapeHtml(t("Use this to confirm what OpenClaw and its sub-agents are doing right now.", "用于确认 OpenClaw 与子智能体当前正在执行什么。"))}</div>
|
||||
<ul class="story-list">${replayMomentsRows}</ul>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
<details class="card compact-details" id="task-table">
|
||||
<summary>${escapeHtml(t(`Task table (raw detail, ${tasks.length}/${allTasks.length})`, `任务表格(原始明细,${tasks.length}/${allTasks.length})`))}</summary>
|
||||
<div class="fold-body">
|
||||
<table>
|
||||
<thead><tr><th>${escapeHtml(t("Project", "项目"))}</th><th>${escapeHtml(t("Task", "任务"))}</th><th>${escapeHtml(t("Title", "标题"))}</th><th>${escapeHtml(t("Status", "状态"))}</th><th>${escapeHtml(t("Agent", "智能体"))}</th><th>${escapeHtml(t("Due", "截止"))}</th><th>${escapeHtml(t("Updated", "更新时间"))}</th></tr></thead>
|
||||
<tbody>${taskRows}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</details>
|
||||
`
|
||||
: `<div class="meta">${escapeHtml(trackedTaskExplanation)}</div>`;
|
||||
const projectsSection = `
|
||||
<section class="task-hub-shell" id="task-hub">
|
||||
<article class="card task-hub-primary" id="task-hub-primary">
|
||||
<div class="overview-command-head">
|
||||
<div>
|
||||
<h2>${escapeHtml(t("Task hub", "任务中枢"))}</h2>
|
||||
<div class="meta">${escapeHtml(t("One place for schedule, current tasks, follow-up items, and cron execution.", "把排程、当前任务、待处理事项和 Cron 执行放在同一页。"))}</div>
|
||||
</div>
|
||||
<div>${overviewPrimaryStatus}</div>
|
||||
</div>
|
||||
${taskHubStatCardsHtml}
|
||||
<div class="overview-task-strip">
|
||||
<div>
|
||||
<div class="meta">${escapeHtml(t("Current focus", "当前关注"))}</div>
|
||||
<div class="overview-task-metric">${badge(currentTaskHealth)} ${escapeHtml(t("Confirmed live", "已确认在跑"))} ${taskCertaintyStrongCount} · ${escapeHtml(t("Need follow-up", "需跟进"))} ${taskCertaintyFollowupCount} · ${escapeHtml(t("Needs inspection", "需排查"))} ${taskCertaintyWeakCount}</div>
|
||||
${mappingTaskHint ? `<div class="meta">${escapeHtml(mappingTaskHint)}</div>` : ""}
|
||||
</div>
|
||||
<div class="overview-quick-links">
|
||||
<a class="btn" href="${escapeHtml(currentTaskHealthHref)}">${escapeHtml(t("Open task lanes", "查看任务泳道"))}</a>
|
||||
<a class="btn" href="${escapeHtml(focusHref)}">${escapeHtml(t("Open follow-up items", "查看待处理"))}</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<article class="card" id="task-decision-center">
|
||||
<div class="overview-command-head">
|
||||
<h2>${escapeHtml(t("Waiting for your decision", "等待你决策"))}</h2>
|
||||
<div>${badge(pendingDecisionCount > 0 ? "warn" : "ok", pendingDecisionCount > 0 ? t("Queue active", "队列活跃") : t("Clear", "已清空"))}</div>
|
||||
</div>
|
||||
<div class="meta">${escapeHtml(t("Pending decisions", "待处理事项"))} ${pendingDecisionCount} · ${escapeHtml(t("Approvals", "审批"))} ${pendingApprovalsCount} · ${escapeHtml(t("Unacked alerts", "未确认告警"))} ${actionQueue.counts.unacked}</div>
|
||||
${taskDecisionPreviewHtml}
|
||||
</article>
|
||||
</section>
|
||||
${taskExecutionChainSection}
|
||||
<section class="task-hub-grid">
|
||||
${calendarSection}
|
||||
${cronExecutionSection}
|
||||
</section>
|
||||
<section class="task-hub-grid task-hub-board-grid">
|
||||
<section class="card" id="task-lane">
|
||||
<h2>${escapeHtml(t("Task lanes", "任务泳道"))}</h2>
|
||||
<div class="meta">${escapeHtml(t("Current focus", "当前关注"))}:${escapeHtml(quickFilterLabel(effectiveQuick, options.language))}</div>
|
||||
${
|
||||
controlCenterMappingTasks.length > 0
|
||||
? `<div class="meta">${escapeHtml(t(`${controlCenterMappingTasks.length} board-only mapping examples are hidden because they are not real execution tasks.`, `已隐藏 ${controlCenterMappingTasks.length} 个看板映射样例(非真实执行任务)。`))}</div>`
|
||||
: ""
|
||||
}
|
||||
<div class="quick-filters">${quickFilters}</div>
|
||||
<form method="GET" action="/" class="filters">
|
||||
<input type="hidden" name="section" value="${escapeHtml(options.section)}" />
|
||||
<input type="hidden" name="lang" value="${escapeHtml(options.language)}" />
|
||||
<input type="hidden" name="quick" value="${escapeHtml(effectiveQuick)}" />
|
||||
<input type="hidden" name="compact" value="${options.compactStatusStrip ? "1" : "0"}" />
|
||||
<input type="hidden" name="usage_view" value="${options.usageView === "today" ? "today" : "cumulative"}" />
|
||||
<div>
|
||||
<label for="status">${escapeHtml(t("Status", "状态"))}</label>
|
||||
<select id="status" name="status">
|
||||
${renderSelectOptions(
|
||||
[{ value: "", label: t("All", "全部") }, ...TASK_STATES.map((state) => ({ value: state, label: taskStateLabel(state, options.language) }))],
|
||||
filters.status ?? "",
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="owner">${escapeHtml(t("Agent", "智能体"))}</label>
|
||||
<select id="owner" name="owner">
|
||||
${renderSelectOptions(
|
||||
[{ value: "", label: t("All", "全部") }, ...ownerOptions.map((owner) => ({ value: owner, label: owner }))],
|
||||
filters.owner ?? "",
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="project">${escapeHtml(t("Project", "项目"))}</label>
|
||||
<select id="project" name="project">
|
||||
${renderSelectOptions(
|
||||
[{ value: "", label: t("All", "全部") }, ...projectOptions.map((project) => ({ value: project, label: project }))],
|
||||
filters.project ?? "",
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-actions">
|
||||
<button class="btn" type="submit">${escapeHtml(t("Apply", "应用"))}</button>
|
||||
<a href="${escapeHtml(clearHref)}">${escapeHtml(t("Clear filters", "清空筛选"))}</a>
|
||||
</div>
|
||||
</form>
|
||||
${taskBoard}
|
||||
<div style="height:10px;"></div>
|
||||
<h3 style="margin:0 0 6px 0;">${escapeHtml(t("Task groups (native view)", "任务分组列表(原生视图)"))}</h3>
|
||||
${taskGroupedListHtml}
|
||||
${
|
||||
controlCenterMappingTasks.length === 0
|
||||
? ""
|
||||
: `<details class="compact-table-details" style="margin-top:12px;" open>
|
||||
<summary>${escapeHtml(t("Open board mapping examples (non-executing)", "查看看板映射样例(不执行任务)"))}</summary>
|
||||
<div class="fold-body">
|
||||
<table>
|
||||
<thead><tr><th>${escapeHtml(t("Example task", "样例任务"))}</th><th>${escapeHtml(t("Label", "标签"))}</th><th>${escapeHtml(t("Status", "状态"))}</th></tr></thead>
|
||||
<tbody>${mappingTaskRows}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</details>`
|
||||
}
|
||||
</section>
|
||||
<div class="task-hub-sidebar">
|
||||
<section class="card" id="project-lane">
|
||||
<h2>${escapeHtml(t("Project lanes", "项目泳道"))}</h2>
|
||||
${projectBoard}
|
||||
</section>
|
||||
<section class="card" id="task-live-feed">
|
||||
<h2>${escapeHtml(t("Live activity feed", "实时活动流"))}</h2>
|
||||
<div class="meta">${escapeHtml(t("Use this to confirm what OpenClaw and its sub-agents are doing right now.", "用于确认 OpenClaw 与子智能体当前正在执行什么。"))}</div>
|
||||
<ul class="story-list">${replayMomentsRows}</ul>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
<details class="card compact-details" id="task-table">
|
||||
<summary>${escapeHtml(t(`Task table (raw detail, ${tasks.length}/${allTasks.length})`, `任务表格(原始明细,${tasks.length}/${allTasks.length})`))}</summary>
|
||||
<details class="card compact-details" id="tracked-task-view"${trackedTaskDetailsOpen ? " open" : ""}>
|
||||
<summary>${escapeHtml(t("Tracked tasks and follow-up", "跟踪任务与跟进"))}</summary>
|
||||
<div class="fold-body">
|
||||
<table>
|
||||
<thead><tr><th>${escapeHtml(t("Project", "项目"))}</th><th>${escapeHtml(t("Task", "任务"))}</th><th>${escapeHtml(t("Title", "标题"))}</th><th>${escapeHtml(t("Status", "状态"))}</th><th>${escapeHtml(t("Agent", "智能体"))}</th><th>${escapeHtml(t("Due", "截止"))}</th><th>${escapeHtml(t("Updated", "更新时间"))}</th></tr></thead>
|
||||
<tbody>${taskRows}</tbody>
|
||||
</table>
|
||||
<div class="meta">${escapeHtml(trackedTaskSummaryText)}</div>
|
||||
<div class="meta">${escapeHtml(trackedTaskExplanation)}</div>
|
||||
${trackedTaskDetailsBody}
|
||||
</div>
|
||||
</details>
|
||||
`;
|
||||
@@ -11471,7 +11505,7 @@ function buildParitySurfaceRows(input: {
|
||||
{
|
||||
id: "approvals",
|
||||
name: "审批与决策队列",
|
||||
route: "/?section=projects-tasks&quick=attention#task-lane",
|
||||
route: "/?section=projects-tasks&quick=attention#tracked-task-view",
|
||||
status: "enabled",
|
||||
detail: `待审批 ${input.pendingApprovals} 条,决策队列可用。`,
|
||||
},
|
||||
@@ -12585,7 +12619,7 @@ function renderTaskDetailPage(input: {
|
||||
: `<div class="meta">${escapeHtml(pickUiText(language, "No session evidence is visible yet.", "当前还没有可显示的会话证据。"))}</div>`
|
||||
}
|
||||
</div>
|
||||
<div class="meta"><a href="${escapeHtml(buildHomeHref({ quick: "all" }, true, "projects-tasks", language))}#task-lane">${escapeHtml(pickUiText(language, "Back to task lanes", "返回任务分组列表"))}</a></div>
|
||||
<div class="meta"><a href="${escapeHtml(buildHomeHref({ quick: "all" }, true, "projects-tasks", language))}#tracked-task-view">${escapeHtml(pickUiText(language, "Back to tracked tasks", "返回跟踪任务"))}</a></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
@@ -162,16 +162,21 @@ test("legacy mission-control routes resolve to dashboard sections", async () =>
|
||||
assert.equal(resolveDashboardSection(new URLSearchParams("section=replay-audit")), "overview");
|
||||
});
|
||||
|
||||
test("tasks section includes merged schedule and board content", async () => {
|
||||
test("tasks section prioritizes schedule and cron before tracked task detail", async () => {
|
||||
const source = await readFile("src/ui/server.ts", "utf8");
|
||||
assert(source.includes('<section class="card" id="calendar-board">'));
|
||||
assert(source.includes('id="task-execution-chain"'));
|
||||
assert(source.includes('id="task-timeline"'));
|
||||
assert(source.includes('t("Today and next schedule", "今日与下一批排程")'));
|
||||
assert(source.includes('<section class="card" id="cron-execution-board">'));
|
||||
assert(source.includes('id="tracked-task-view"'));
|
||||
assert(source.includes('const hasTrackedTaskPanels = tasks.length > 0 || pendingDecisionCount > 0 || taskCertaintyCards.length > 0;'));
|
||||
assert(source.includes('t("Tracked tasks and follow-up", "跟踪任务与跟进")'));
|
||||
assert(source.includes("Start with schedule and cron execution. Staff can be active from cron or ad-hoc sessions even when there is no tracked task row yet."));
|
||||
assert(source.includes("先看排程和 Cron 执行。员工显示在工作,可能只是 Cron 或临时会话在跑,不一定已经落成可跟踪的任务条目。"));
|
||||
assert(source.includes('<section class="task-hub-shell" id="task-hub">'));
|
||||
assert(source.includes('id="task-decision-center"'));
|
||||
assert(source.includes('<section class="card" id="cron-execution-board">'));
|
||||
assert(source.includes('<section class="card" id="task-lane">'));
|
||||
assert(source.includes('id="task-execution-chain"'));
|
||||
assert(source.includes('t("Execution chain", "执行链")'));
|
||||
assert(source.includes('Accepted and spawned child sessions'));
|
||||
assert(source.includes('if (options.section === "calendar") sectionBody = projectsSection;'));
|
||||
@@ -193,7 +198,7 @@ test("global visibility card keeps plain-language EN/ZH copy for four key signal
|
||||
assert(en.includes("Active heartbeat checks: 1."));
|
||||
assert(en.includes('/?compact=1&section=overview&lang=en&quick=all#cron-health'));
|
||||
assert(en.includes('/?compact=1&section=overview&lang=en&quick=all#heartbeat-health'));
|
||||
assert(en.includes('/?compact=1&section=projects-tasks&lang=en&quick=all#task-lane'));
|
||||
assert(en.includes('/?compact=1&section=projects-tasks&lang=en&quick=all#tracked-task-view'));
|
||||
assert(en.includes('/?compact=1&section=overview&lang=en&quick=all#tool-activity'));
|
||||
assert(!en.includes('href="/cron"'));
|
||||
assert(!en.includes('href="/sessions"'));
|
||||
@@ -215,7 +220,7 @@ test("global visibility card keeps plain-language EN/ZH copy for four key signal
|
||||
assert(!zh.includes("Tasks in progress:"));
|
||||
assert(zh.includes('/?compact=1&section=overview&lang=zh&quick=all#cron-health'));
|
||||
assert(zh.includes('/?compact=1&section=overview&lang=zh&quick=all#heartbeat-health'));
|
||||
assert(zh.includes('/?compact=1&section=projects-tasks&lang=zh&quick=all#task-lane'));
|
||||
assert(zh.includes('/?compact=1&section=projects-tasks&lang=zh&quick=all#tracked-task-view'));
|
||||
assert(zh.includes('/?compact=1&section=overview&lang=zh&quick=all#tool-activity'));
|
||||
assert(!zh.includes('href="/cron"'));
|
||||
assert(!zh.includes('href="/sessions"'));
|
||||
@@ -323,7 +328,7 @@ test("dashboard keeps global visibility as overview-only block", async () => {
|
||||
assert(source.includes("replayPreview.stats.timeline.total"));
|
||||
assert(source.includes('t("Replay activity", "活动回放")'));
|
||||
assert(source.includes('t("Approval requests", "审批请求")'));
|
||||
assert(source.includes('route: "/?section=projects-tasks&quick=attention#task-lane"'));
|
||||
assert(source.includes('route: "/?section=projects-tasks&quick=attention#tracked-task-view"'));
|
||||
assert(source.includes('route: "/audit"'));
|
||||
assert(source.includes('route: "/digest/latest"'));
|
||||
assert(source.includes("void primeUiRenderCaches(toolClient);"));
|
||||
|
||||
Reference in new issue
Block a user