feat: add project-aware agent workspace
Generic Container CI/CD / test-build-publish (push) Successful in 2m9s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 2m39s

This commit is contained in:
2026-10-22 18:52:18 +08:00
parent c6a0e74e72
commit 2d8506fea0
191 changed files with 12373 additions and 3556 deletions
@@ -1,5 +1,47 @@
import { expect, test, type Locator, type Page } from "@playwright/test";
import { mockFlatWorkOrder } from "./support/mock-hierarchical-work-order";
import { mockWorkbenchContext } from "./support/mock-workbench-context";
test.beforeEach(async ({ page }) => {
await mockWorkbenchContext(page);
});
test("shows mock scheduled conditions outside the demo project", async ({ page }) => {
const project = {
project_id: "b962c44e-8433-4a10-81e9-a64b70ac1152",
name: "凤阳(新版)",
code: "fengyang_v2",
gs_workspace: "fengyang_v2",
status: "active"
};
await mockWorkbenchContext(page, undefined, {
metadata: { ...project, map_config: {}, map_extent: null, project_role: "member" },
accessContext: {
user_id: "operator",
username: "project.operator",
system_role: "user",
is_system_admin: false,
project_id: project.project_id,
project_role: "member",
permissions: ["webgis.view"]
}
});
await page.route("https://tjwater-api.invalid/api/v1/projects?**", (route) => route.fulfill({
headers: { "Access-Control-Allow-Origin": "*" },
json: { items: [project], total: 1, limit: 1000, offset: 0 }
}));
await page.goto("/", { waitUntil: "domcontentloaded" });
await openConditionFeed(page);
const panel = page.getByRole("region", { name: "工况任务", exact: true });
await panel.getByRole("button", { name: "展开工况任务" }).focus();
await page.keyboard.press("Enter");
await expect(panel.getByRole("button", { name: /定时任务/ })).toContainText("模拟数据");
await expect(
panel.getByTestId("scheduled-condition-timeline").getByRole("button", { name: /SCADA 数据诊断/ }).first()
).toBeVisible();
});
test("keeps the open scheduled report when the rolling history refreshes", async ({ page }) => {
await page.clock.install({ time: new Date("2026-09-24T09:20:53Z") });
@@ -11,13 +53,17 @@ test("keeps the open scheduled report when the rolling history refreshes", async
const rows = panel.getByTestId("scheduled-condition-timeline").locator("button[aria-pressed]");
const oldestReport = rows.last();
const reportTitle = await oldestReport.textContent();
const reportId = await oldestReport.getAttribute("data-condition-id");
expect(reportTitle).toContain("11:20SCADA 数据诊断");
expect(reportId).not.toBeNull();
await oldestReport.click();
await expect(oldestReport).toHaveAttribute("aria-pressed", "true");
await page.clock.runFor(12_000);
await expect(rows.filter({ hasText: reportTitle ?? "" })).toHaveAttribute("aria-pressed", "true");
await expect(
panel.locator(`[data-condition-id="${reportId}"]`)
).toHaveAttribute("aria-pressed", "true");
await expect(panel.getByTestId("scheduled-condition-detail-scroll"))
.toContainText("11:20 的SCADA 数据诊断");
@@ -116,9 +162,11 @@ test("narrow desktop keeps Agent and expanded conditions from overlapping", asyn
24
);
await panel.getByRole("button", { name: "展开工况任务" }).click();
await panel.getByRole("button", { name: "展开工况任务" }).focus();
await page.keyboard.press("Enter");
await expect(page.locator('aside[aria-label="Agent 折叠栏"]')).toBeVisible();
await expect(panel).toHaveCSS("width", "852px");
await expect.poll(async () => (await panel.boundingBox())?.width ?? 0).toBeGreaterThan(800);
await expect.poll(async () => (await panel.boundingBox())?.width ?? Infinity).toBeLessThanOrEqual(880);
const expandedConditionBox = await panel.boundingBox();
const collapsedAgentBox = await page