feat(mq): improve Kafka peek and admin localization
This commit is contained in:
1 parent
a9e76dc130
commit
68b1777aa4
29 files changed
+4561
-636
No files matched your search
@@ -0,0 +1,26 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { parseNonNegativeSafeInteger } from "@/lib/mq/mqPeekFilters";
|
||||
|
||||
describe("parseNonNegativeSafeInteger", () => {
|
||||
it("accepts non-negative safe integers", () => {
|
||||
expect(parseNonNegativeSafeInteger("0")).toBe(0);
|
||||
expect(parseNonNegativeSafeInteger("20")).toBe(20);
|
||||
expect(parseNonNegativeSafeInteger(String(Number.MAX_SAFE_INTEGER))).toBe(Number.MAX_SAFE_INTEGER);
|
||||
});
|
||||
|
||||
it("rejects decimals and non-integers", () => {
|
||||
expect(parseNonNegativeSafeInteger("1.9")).toBeNull();
|
||||
expect(parseNonNegativeSafeInteger("0.1")).toBeNull();
|
||||
expect(parseNonNegativeSafeInteger("abc")).toBeNull();
|
||||
});
|
||||
|
||||
it("rejects negatives and values outside the safe integer range", () => {
|
||||
expect(parseNonNegativeSafeInteger("-1")).toBeNull();
|
||||
expect(parseNonNegativeSafeInteger(String(Number.MAX_SAFE_INTEGER + 1))).toBeNull();
|
||||
});
|
||||
|
||||
it("rejects empty input", () => {
|
||||
expect(parseNonNegativeSafeInteger("")).toBeNull();
|
||||
expect(parseNonNegativeSafeInteger(" ")).toBeNull();
|
||||
});
|
||||
});
|
||||
+2
-2
@@ -18,8 +18,8 @@ describe("mqTenantForm", () => {
|
||||
});
|
||||
|
||||
it("requires both a tenant name and at least one allowed cluster", () => {
|
||||
expect(validateTenantForm("", { adminRoles: [], allowedClusters: ["standalone"] })).toBe("Tenant name is required");
|
||||
expect(validateTenantForm("tenant-a", { adminRoles: [], allowedClusters: [] })).toBe("Allowed clusters are required");
|
||||
expect(validateTenantForm("", { adminRoles: [], allowedClusters: ["standalone"] })).toBe("mqTenants.tenantNameRequired");
|
||||
expect(validateTenantForm("tenant-a", { adminRoles: [], allowedClusters: [] })).toBe("mqTenants.allowedClustersRequired");
|
||||
expect(validateTenantForm("tenant-a", { adminRoles: [], allowedClusters: ["standalone"] })).toBeUndefined();
|
||||
});
|
||||
});
|
||||
+9
-6
@@ -2,20 +2,23 @@ import { describe, expect, it } from "vitest";
|
||||
import { formatMqTokenIssueError } from "@/lib/mq/mqTokenErrors";
|
||||
|
||||
describe("MQ token errors", () => {
|
||||
it("turns missing signing configuration backend errors into actionable Chinese copy", () => {
|
||||
it("turns missing signing configuration backend errors into locale keys", () => {
|
||||
const result = formatMqTokenIssueError("/api/mq/tokens/issue returned 500: Token signing is not configured for this MQ connection");
|
||||
|
||||
expect(result.kind).toBe("missingSigningKey");
|
||||
expect(result.title).toBe("未配置 Token 签发密钥");
|
||||
expect(result.message).toContain("无法生成客户端 Token");
|
||||
expect(result.detail).toContain("Broker Token 签发");
|
||||
if (result.kind === "missingSigningKey") {
|
||||
expect(result.titleKey).toBe("mqPermissions.missingSigningKeyTitle");
|
||||
expect(result.messageKey).toBe("mqPermissions.missingSigningKeyMessage");
|
||||
expect(result.detailKey).toBe("mqPermissions.missingSigningKeyDetail");
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps unrelated errors as ordinary messages", () => {
|
||||
const result = formatMqTokenIssueError("network failed");
|
||||
|
||||
expect(result.kind).toBe("generic");
|
||||
expect(result.title).toBeUndefined();
|
||||
expect(result.message).toBe("network failed");
|
||||
if (result.kind === "generic") {
|
||||
expect(result.message).toBe("network failed");
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
/** Parse a non-negative safe integer from user input; rejects decimals and unsafe magnitudes. */
|
||||
export function parseNonNegativeSafeInteger(text: string): number | null {
|
||||
const trimmed = text.trim();
|
||||
if (trimmed === "") {
|
||||
return null;
|
||||
}
|
||||
const value = Number(trimmed);
|
||||
if (!Number.isSafeInteger(value) || value < 0) {
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -33,10 +33,10 @@ export function defaultTenantConfig(clusterOptions: readonly string[]): TenantCo
|
||||
|
||||
export function validateTenantForm(name: string | undefined, config: TenantConfig): string | undefined {
|
||||
if (!name?.trim()) {
|
||||
return "Tenant name is required";
|
||||
return "mqTenants.tenantNameRequired";
|
||||
}
|
||||
if (!normalizeClusterOptions(config.allowedClusters).length) {
|
||||
return "Allowed clusters are required";
|
||||
return "mqTenants.allowedClustersRequired";
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
export type MqTokenIssueErrorView =
|
||||
| {
|
||||
kind: "missingSigningKey";
|
||||
title: string;
|
||||
message: string;
|
||||
detail: string;
|
||||
titleKey: "mqPermissions.missingSigningKeyTitle";
|
||||
messageKey: "mqPermissions.missingSigningKeyMessage";
|
||||
detailKey: "mqPermissions.missingSigningKeyDetail";
|
||||
}
|
||||
| {
|
||||
kind: "generic";
|
||||
title?: undefined;
|
||||
titleKey?: undefined;
|
||||
messageKey?: undefined;
|
||||
detailKey?: undefined;
|
||||
message: string;
|
||||
detail?: undefined;
|
||||
};
|
||||
|
||||
export function formatMqTokenIssueError(error: unknown): MqTokenIssueErrorView {
|
||||
@@ -17,9 +18,9 @@ export function formatMqTokenIssueError(error: unknown): MqTokenIssueErrorView {
|
||||
if (isMissingTokenSigningConfig(message)) {
|
||||
return {
|
||||
kind: "missingSigningKey",
|
||||
title: "未配置 Token 签发密钥",
|
||||
message: "当前 MQ 连接还没有配置 Broker Token 签发密钥,无法生成客户端 Token。",
|
||||
detail: "请编辑该连接,在 MQ 配置中设置“Broker Token 签发”为 HS256 SECRET 或 RS256 PRIVATE,并填写签发密钥后再生成。",
|
||||
titleKey: "mqPermissions.missingSigningKeyTitle",
|
||||
messageKey: "mqPermissions.missingSigningKeyMessage",
|
||||
detailKey: "mqPermissions.missingSigningKeyDetail",
|
||||
};
|
||||
}
|
||||
return { kind: "generic", message };
|
||||
|
||||
Reference in new issue
Block a user