feat(space): route workbench execution items
This commit is contained in:
parent
a7008bb3cc
commit
6c0f6dac53
|
|
@ -165,6 +165,10 @@ function projectHref(projectId: string): string {
|
||||||
return `/pmflow-os?projectId=${encodeURIComponent(projectId)}`;
|
return `/pmflow-os?projectId=${encodeURIComponent(projectId)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function executionHref(projectId: string): string {
|
||||||
|
return `/execution-bridge?projectId=${encodeURIComponent(projectId)}`;
|
||||||
|
}
|
||||||
|
|
||||||
function pendingChangeItems(truth: ProjectTruthState | null): ChangeItem[] {
|
function pendingChangeItems(truth: ProjectTruthState | null): ChangeItem[] {
|
||||||
if (!truth) return [];
|
if (!truth) return [];
|
||||||
return truth.changeItems.filter((item) => item.status === "pending_review");
|
return truth.changeItems.filter((item) => item.status === "pending_review");
|
||||||
|
|
@ -249,7 +253,7 @@ function deriveAIProgress(snapshot: ProjectSnapshot): SpaceAIProgressItem[] {
|
||||||
const { project, truth, execution } = snapshot;
|
const { project, truth, execution } = snapshot;
|
||||||
const projectId = String(project.id);
|
const projectId = String(project.id);
|
||||||
const projectTitle = project.title || truth?.project.name || `项目 ${projectId}`;
|
const projectTitle = project.title || truth?.project.name || `项目 ${projectId}`;
|
||||||
const href = projectHref(projectId);
|
const href = executionHref(projectId);
|
||||||
const items: SpaceAIProgressItem[] = [];
|
const items: SpaceAIProgressItem[] = [];
|
||||||
|
|
||||||
if (execution && ACTIVE_EXECUTION_STATUSES.includes(execution.execution.status)) {
|
if (execution && ACTIVE_EXECUTION_STATUSES.includes(execution.execution.status)) {
|
||||||
|
|
|
||||||
|
|
@ -47,4 +47,97 @@ describe("PersonalSpacePage", () => {
|
||||||
expect(screen.getByText("暂存想法只读聚合尚未接入后端合同,当前不使用 mock 数据冒充真实内容。")).toBeInTheDocument();
|
expect(screen.getByText("暂存想法只读聚合尚未接入后端合同,当前不使用 mock 数据冒充真实内容。")).toBeInTheDocument();
|
||||||
expect(screen.queryByText("AI 周报助手")).not.toBeInTheDocument();
|
expect(screen.queryByText("AI 周报助手")).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps workbench actions as navigation-only links into the main flows", async () => {
|
||||||
|
vi.mocked(spaceApi.getWorkbench).mockResolvedValue({
|
||||||
|
...emptyWorkbench,
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
id: "17",
|
||||||
|
title: "真实项目",
|
||||||
|
summary: "真实项目摘要",
|
||||||
|
status: "进行中",
|
||||||
|
stage: "开发",
|
||||||
|
progress: 62,
|
||||||
|
pendingCount: 1,
|
||||||
|
activeTaskCount: 2,
|
||||||
|
riskLabel: "中",
|
||||||
|
nextAction: "继续推进核心任务",
|
||||||
|
updatedAt: "2026-04-26T08:00:00.000Z",
|
||||||
|
href: "/pmflow-os?projectId=17",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
pendingConfirmations: [
|
||||||
|
{
|
||||||
|
id: "change-91",
|
||||||
|
projectId: "17",
|
||||||
|
projectTitle: "真实项目",
|
||||||
|
title: "确认需求变更",
|
||||||
|
summary: "等待在主流程确认变更。",
|
||||||
|
source: "changeset",
|
||||||
|
stage: "需求",
|
||||||
|
riskLevel: "medium",
|
||||||
|
createdAt: "2026-04-26T08:00:00.000Z",
|
||||||
|
href: "/change-review?projectId=17&changeSetId=91",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
aiProgress: [
|
||||||
|
{
|
||||||
|
id: "execution-17",
|
||||||
|
projectId: "17",
|
||||||
|
projectTitle: "真实项目",
|
||||||
|
title: "AI 正在推进执行链路",
|
||||||
|
summary: "正在聚合执行进度与回写状态。",
|
||||||
|
status: "coding",
|
||||||
|
progress: 52,
|
||||||
|
updatedAt: "2026-04-26T08:00:00.000Z",
|
||||||
|
href: "/execution-bridge?projectId=17",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
drafts: [
|
||||||
|
{
|
||||||
|
id: "17-需求-draft-1",
|
||||||
|
projectId: "17",
|
||||||
|
projectTitle: "真实项目",
|
||||||
|
title: "待确认草案",
|
||||||
|
summary: "待确认草案摘要",
|
||||||
|
objectType: "需求",
|
||||||
|
status: "draft",
|
||||||
|
updatedAt: "2026-04-26T08:00:00.000Z",
|
||||||
|
href: "/pmflow-os?projectId=17",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
recentProjects: [
|
||||||
|
{
|
||||||
|
id: "17",
|
||||||
|
title: "真实项目",
|
||||||
|
summary: "真实项目摘要",
|
||||||
|
status: "进行中",
|
||||||
|
stage: "开发",
|
||||||
|
progress: 62,
|
||||||
|
pendingCount: 1,
|
||||||
|
activeTaskCount: 2,
|
||||||
|
riskLabel: "中",
|
||||||
|
nextAction: "继续推进核心任务",
|
||||||
|
updatedAt: "2026-04-26T08:00:00.000Z",
|
||||||
|
href: "/pmflow-os?projectId=17",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
renderWithProviders(<PersonalSpacePage />, ["/space"]);
|
||||||
|
|
||||||
|
expect(await screen.findByRole("link", { name: /进入主流程/ })).toHaveAttribute(
|
||||||
|
"href",
|
||||||
|
"/pmflow-os?projectId=17"
|
||||||
|
);
|
||||||
|
expect(screen.getAllByRole("link", { name: /确认需求变更/ })[0]).toHaveAttribute(
|
||||||
|
"href",
|
||||||
|
"/change-review?projectId=17&changeSetId=91"
|
||||||
|
);
|
||||||
|
expect(screen.getAllByRole("link", { name: /AI 正在推进执行链路/ })[0]).toHaveAttribute(
|
||||||
|
"href",
|
||||||
|
"/execution-bridge?projectId=17"
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -299,13 +299,13 @@ function WorkbenchHeader({
|
||||||
</div>
|
</div>
|
||||||
<h1 className="mt-2 text-3xl font-semibold tracking-tight text-slate-950">个人工作面</h1>
|
<h1 className="mt-2 text-3xl font-semibold tracking-tight text-slate-950">个人工作面</h1>
|
||||||
<p className="mt-2 text-sm leading-6 text-slate-500">
|
<p className="mt-2 text-sm leading-6 text-slate-500">
|
||||||
聚合继续推进、待确认、AI 正在推进、暂存想法和草案箱;点击项目后回到主流程处理。
|
聚合继续推进、待确认、执行中、暂存想法、草案箱和最近项目;点击项目后回到主流程处理。
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid min-w-[420px] grid-cols-3 gap-3">
|
<div className="grid min-w-[420px] grid-cols-3 gap-3">
|
||||||
<MetricTile label="最近项目" value={projectCount} />
|
<MetricTile label="最近项目" value={projectCount} />
|
||||||
<MetricTile label="待确认" value={pendingCount} tone="orange" />
|
<MetricTile label="待确认" value={pendingCount} tone="orange" />
|
||||||
<MetricTile label="AI 推进" value={aiCount} tone="blue" />
|
<MetricTile label="执行中" value={aiCount} tone="blue" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 flex items-center gap-2 text-xs text-slate-500">
|
<div className="mt-4 flex items-center gap-2 text-xs text-slate-500">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue