feat: extend supply workbench demo and map navigation
This commit is contained in:
@@ -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(/演示窗口/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user