feat: extend supply workbench demo and map navigation

This commit is contained in:
2026-09-23 13:19:30 +08:00
parent bebcf2a06c
commit 1752b9ef84
45 changed files with 2137 additions and 449 deletions
+23 -14
View File
@@ -10,6 +10,7 @@ describe("runtime frontend configuration", () => {
TJWATER_KEYCLOAK_ISSUER: "https://auth.example.test/realms/tjwater/",
TJWATER_KEYCLOAK_CLIENT_ID: "next-tjwater",
TJWATER_MAPBOX_ACCESS_TOKEN: "token",
TJWATER_TIANDITU_TOKEN: "tianditu-token",
TJWATER_MAP_URL: "https://maps.example.test/geoserver",
TJWATER_GEOSERVER_WORKSPACE: "project-a",
TJWATER_SERVER_API_BASE_URL: "https://server.example.test",
@@ -28,6 +29,7 @@ describe("runtime frontend configuration", () => {
TJWATER_KEYCLOAK_ISSUER: "https://auth.example.test/realms/tjwater",
TJWATER_KEYCLOAK_CLIENT_ID: "next-tjwater",
TJWATER_MAPBOX_ACCESS_TOKEN: "token",
TJWATER_TIANDITU_TOKEN: "tianditu-token",
TJWATER_MAP_URL: "https://maps.example.test/geoserver",
TJWATER_GEOSERVER_WORKSPACE: "project-a",
TJWATER_SERVER_API_BASE_URL: "https://server.example.test",
@@ -47,6 +49,7 @@ describe("runtime frontend configuration", () => {
expect(parseRuntimeConfig({ TJWATER_AUTH_MODE: "disabled" })).toMatchObject({
TJWATER_AUTH_MODE: "disabled",
TJWATER_KEYCLOAK_CLIENT_ID: "next-tjwater",
TJWATER_TIANDITU_TOKEN: "",
TJWATER_WORKBENCH_RUNTIME_MODE: "auto",
TJWATER_PERIPHERAL_SAMPLE_API_BASE_URL: "",
TJWATER_PERIPHERAL_SAMPLE_TIME_MODE: "demo",
@@ -59,10 +62,12 @@ describe("runtime frontend configuration", () => {
});
it("accepts the explicit backend history mode", () => {
expect(parseRuntimeConfig({
TJWATER_AUTH_MODE: "disabled",
TJWATER_WORKBENCH_RUNTIME_MODE: "history"
}).TJWATER_WORKBENCH_RUNTIME_MODE).toBe("history");
expect(
parseRuntimeConfig({
TJWATER_AUTH_MODE: "disabled",
TJWATER_WORKBENCH_RUNTIME_MODE: "history"
}).TJWATER_WORKBENCH_RUNTIME_MODE
).toBe("history");
});
it("requires a Realm issuer when authentication is enabled", () => {
@@ -93,15 +98,19 @@ describe("runtime frontend configuration", () => {
});
it("rejects an invalid or oversized peripheral demo window", () => {
expect(() => parseRuntimeConfig({
TJWATER_AUTH_MODE: "disabled",
TJWATER_PERIPHERAL_SAMPLE_DEMO_START: "2026-04-30T16:00:00Z",
TJWATER_PERIPHERAL_SAMPLE_DEMO_END: "2026-04-30T08:00:00Z"
})).toThrow(/演示窗口/);
expect(() => parseRuntimeConfig({
TJWATER_AUTH_MODE: "disabled",
TJWATER_PERIPHERAL_SAMPLE_DEMO_START: "2026-04-01T00:00:00Z",
TJWATER_PERIPHERAL_SAMPLE_DEMO_END: "2026-04-30T00:00:00Z"
})).toThrow(/演示窗口/);
expect(() =>
parseRuntimeConfig({
TJWATER_AUTH_MODE: "disabled",
TJWATER_PERIPHERAL_SAMPLE_DEMO_START: "2026-04-30T16:00:00Z",
TJWATER_PERIPHERAL_SAMPLE_DEMO_END: "2026-04-30T08:00:00Z"
})
).toThrow(/演示窗口/);
expect(() =>
parseRuntimeConfig({
TJWATER_AUTH_MODE: "disabled",
TJWATER_PERIPHERAL_SAMPLE_DEMO_START: "2026-04-01T00:00:00Z",
TJWATER_PERIPHERAL_SAMPLE_DEMO_END: "2026-04-30T00:00:00Z"
})
).toThrow(/演示窗口/);
});
});
+15 -4
View File
@@ -43,12 +43,18 @@ const keycloakIssuer = z
if (!value) return;
const parsed = browserHttpUrl.safeParse(value);
if (!parsed.success) {
context.addIssue({ code: z.ZodIssueCode.custom, message: "Keycloak issuer 必须是安全的 HTTP(S) 地址" });
context.addIssue({
code: z.ZodIssueCode.custom,
message: "Keycloak issuer 必须是安全的 HTTP(S) 地址"
});
return;
}
const url = new URL(value);
if (url.search || !/\/realms\/[^/]+\/?$/.test(url.pathname)) {
context.addIssue({ code: z.ZodIssueCode.custom, message: "Keycloak issuer 必须指向具体 Realm" });
context.addIssue({
code: z.ZodIssueCode.custom,
message: "Keycloak issuer 必须指向具体 Realm"
});
}
})
.transform((value) => value.replace(/\/+$/, ""));
@@ -59,6 +65,7 @@ const runtimeConfigSchema = z
TJWATER_KEYCLOAK_ISSUER: keycloakIssuer,
TJWATER_KEYCLOAK_CLIENT_ID: z.string().trim().default("next-tjwater"),
TJWATER_MAPBOX_ACCESS_TOKEN: z.string().default(""),
TJWATER_TIANDITU_TOKEN: z.string().default(""),
TJWATER_MAP_URL: browserHttpUrl.default("https://geoserver.waternetwork.cn/geoserver"),
TJWATER_GEOSERVER_WORKSPACE: z.string().trim().min(1).default("tjwater_next"),
TJWATER_SERVER_API_BASE_URL: browserHttpUrl.default("http://127.0.0.1:8000"),
@@ -66,9 +73,13 @@ const runtimeConfigSchema = z
TJWATER_WORKBENCH_RUNTIME_MODE: z.enum(["auto", "demo", "history", "backend"]).default("auto"),
TJWATER_PERIPHERAL_SAMPLE_API_BASE_URL: optionalBrowserHttpUrl,
TJWATER_PERIPHERAL_SAMPLE_TIME_MODE: z.enum(["demo", "recent"]).default("demo"),
TJWATER_PERIPHERAL_SAMPLE_DEMO_START: z.string().datetime({ offset: true })
TJWATER_PERIPHERAL_SAMPLE_DEMO_START: z
.string()
.datetime({ offset: true })
.default("2026-09-17T00:00:00Z"),
TJWATER_PERIPHERAL_SAMPLE_DEMO_END: z.string().datetime({ offset: true })
TJWATER_PERIPHERAL_SAMPLE_DEMO_END: z
.string()
.datetime({ offset: true })
.default("2026-09-17T12:00:00Z"),
TJWATER_PERIPHERAL_SAMPLE_RECENT_HOURS: z.coerce.number().int().min(1).max(168).default(8),
TJWATER_ENABLE_DEV_PANEL: runtimeBoolean(false),