feat: 新增 target description 字段,收紧 id/name 长度,调整延迟列和名称列
This commit is contained in:
@@ -144,6 +144,7 @@ function resolveTarget(
|
||||
|
||||
result.intervalMs = intervalMs;
|
||||
result.timeoutMs = timeoutMs;
|
||||
result.description = target.description ?? null;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -187,6 +187,7 @@ export class CommandChecker implements CheckerDefinition<ResolvedCommandTarget>
|
||||
exec: t.cmd.exec,
|
||||
maxOutputBytes,
|
||||
},
|
||||
description: null,
|
||||
expect: target.expect as CommandExpectConfig | undefined,
|
||||
group: target.group ?? "default",
|
||||
id: t.id,
|
||||
|
||||
@@ -180,6 +180,7 @@ export class DbChecker implements CheckerDefinition<ResolvedDbTarget> {
|
||||
query: t.db.query,
|
||||
url: t.db.url,
|
||||
},
|
||||
description: null,
|
||||
expect: target.expect as DbExpectConfig | undefined,
|
||||
group: target.group ?? "default",
|
||||
id: t.id,
|
||||
|
||||
@@ -112,6 +112,7 @@ export class HttpChecker implements CheckerDefinition<ResolvedHttpTarget> {
|
||||
const maxBodyBytes = parseSize(t.http.maxBodyBytes ?? httpDefaults?.maxBodyBytes ?? "100MB");
|
||||
|
||||
return {
|
||||
description: null,
|
||||
expect: target.expect as HttpExpectConfig | undefined,
|
||||
group: target.group ?? "default",
|
||||
http: {
|
||||
|
||||
@@ -49,11 +49,12 @@ export function createProbeConfigSchema(checkers: CheckerDefinition[], external
|
||||
|
||||
export function createTargetSchema(checker: CheckerDefinition): TSchema {
|
||||
const properties: Record<string, TSchema> = {
|
||||
description: Type.Optional(Type.String({ maxLength: 500 })),
|
||||
expect: Type.Optional(checker.schemas.expect),
|
||||
group: Type.Optional(Type.String()),
|
||||
id: Type.String({ minLength: 1 }),
|
||||
id: Type.String({ maxLength: 30, minLength: 1 }),
|
||||
interval: Type.Optional(durationSchema),
|
||||
name: Type.Optional(Type.String({ minLength: 1 })),
|
||||
name: Type.Optional(Type.String({ maxLength: 30, minLength: 1 })),
|
||||
timeout: Type.Optional(durationSchema),
|
||||
type: Type.Literal(checker.type),
|
||||
};
|
||||
@@ -68,10 +69,11 @@ function cloneSchema(schema: TSchema): Record<string, unknown> {
|
||||
function createBaseTargetSchema(checkers: CheckerDefinition[]): TSchema {
|
||||
return Type.Object(
|
||||
{
|
||||
description: Type.Optional(Type.String({ maxLength: 500 })),
|
||||
group: Type.Optional(Type.String()),
|
||||
id: Type.String({ minLength: 1 }),
|
||||
id: Type.String({ maxLength: 30, minLength: 1 }),
|
||||
interval: Type.Optional(durationSchema),
|
||||
name: Type.Optional(Type.String({ minLength: 1 })),
|
||||
name: Type.Optional(Type.String({ maxLength: 30, minLength: 1 })),
|
||||
timeout: Type.Optional(durationSchema),
|
||||
type: Type.Union(checkers.map((checker) => Type.Literal(checker.type)) as unknown as [TSchema, ...TSchema[]]),
|
||||
},
|
||||
|
||||
@@ -10,6 +10,7 @@ const CREATE_TARGETS_TABLE = `
|
||||
CREATE TABLE IF NOT EXISTS targets (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
type TEXT NOT NULL,
|
||||
target TEXT NOT NULL,
|
||||
config TEXT NOT NULL DEFAULT '{}',
|
||||
@@ -316,10 +317,10 @@ export class ProbeStore {
|
||||
const configIds = new Set(targets.map((t) => t.id));
|
||||
|
||||
const insertStmt = this.db.prepare(
|
||||
"INSERT INTO targets (id, name, type, target, config, interval_ms, timeout_ms, expect, grp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
"INSERT INTO targets (id, name, description, type, target, config, interval_ms, timeout_ms, expect, grp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
);
|
||||
const updateStmt = this.db.prepare(
|
||||
"UPDATE targets SET name = ?, type = ?, target = ?, config = ?, interval_ms = ?, timeout_ms = ?, expect = ?, grp = ? WHERE id = ?",
|
||||
"UPDATE targets SET name = ?, description = ?, type = ?, target = ?, config = ?, interval_ms = ?, timeout_ms = ?, expect = ?, grp = ? WHERE id = ?",
|
||||
);
|
||||
const deleteStmt = this.db.prepare("DELETE FROM targets WHERE id = ?");
|
||||
|
||||
@@ -332,9 +333,9 @@ export class ProbeStore {
|
||||
const expect = t.expect ? JSON.stringify(t.expect) : null;
|
||||
|
||||
if (existingIds.has(t.id)) {
|
||||
updateStmt.run(t.name, type, target, config, t.intervalMs, t.timeoutMs, expect, t.group, t.id);
|
||||
updateStmt.run(t.name, t.description, type, target, config, t.intervalMs, t.timeoutMs, expect, t.group, t.id);
|
||||
} else {
|
||||
insertStmt.run(t.id, t.name, type, target, config, t.intervalMs, t.timeoutMs, expect, t.group);
|
||||
insertStmt.run(t.id, t.name, t.description, type, target, config, t.intervalMs, t.timeoutMs, expect, t.group);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ export interface ProbeConfig {
|
||||
|
||||
export interface RawTargetConfig {
|
||||
[configKey: string]: unknown;
|
||||
description?: string;
|
||||
expect?: unknown;
|
||||
group?: string;
|
||||
id: string;
|
||||
@@ -52,6 +53,7 @@ export interface RawTargetConfig {
|
||||
|
||||
export interface ResolvedTargetBase {
|
||||
[key: string]: unknown;
|
||||
description: null | string;
|
||||
expect?: unknown;
|
||||
group: string;
|
||||
id: string;
|
||||
@@ -79,6 +81,7 @@ export interface StoredCheckResult {
|
||||
|
||||
export interface StoredTarget {
|
||||
config: string;
|
||||
description: null | string;
|
||||
expect: null | string;
|
||||
grp: string;
|
||||
id: string;
|
||||
|
||||
@@ -56,6 +56,7 @@ export function handleDashboard(url: URL, store: ProbeStore, mode: RuntimeMode):
|
||||
|
||||
return {
|
||||
currentStreak,
|
||||
description: target.description,
|
||||
group: target.grp,
|
||||
id: target.id,
|
||||
interval: formatDuration(target.interval_ms),
|
||||
|
||||
@@ -99,6 +99,7 @@ export interface TargetStats {
|
||||
|
||||
export interface TargetStatus {
|
||||
currentStreak: CurrentStreak | null;
|
||||
description: null | string;
|
||||
group: string;
|
||||
id: string;
|
||||
interval: string;
|
||||
|
||||
@@ -38,6 +38,7 @@ export function OverviewTab({ metricsData, metricsLoading, target }: OverviewTab
|
||||
label: "最新检查时间",
|
||||
},
|
||||
{ content: target.latestCheck?.statusDetail ?? "-", label: "状态详情" },
|
||||
{ content: target.description ?? "", label: "描述", span: 2 },
|
||||
]}
|
||||
/>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { StatusBar } from "../components/StatusBar";
|
||||
import { StatusDot } from "../components/StatusDot";
|
||||
import { getAvailabilityProgressColor } from "./color-threshold";
|
||||
import { statusFilter } from "./target-table-filters";
|
||||
import { availabilitySorter, latencySorter, nameSorter } from "./target-table-sorters";
|
||||
import { availabilitySorter, latencySorter } from "./target-table-sorters";
|
||||
|
||||
export function createTargetTableColumns(checkerTypes: string[]): Array<PrimaryTableCol<TargetStatus>> {
|
||||
return [
|
||||
@@ -24,8 +24,6 @@ export function createTargetTableColumns(checkerTypes: string[]): Array<PrimaryT
|
||||
{
|
||||
colKey: "name",
|
||||
ellipsis: true,
|
||||
sorter: nameSorter,
|
||||
sortType: "all",
|
||||
title: "名称",
|
||||
},
|
||||
{
|
||||
@@ -88,13 +86,13 @@ export function createTargetTableColumns(checkerTypes: string[]): Array<PrimaryT
|
||||
const ms = row.latestCheck?.durationMs;
|
||||
if (ms === null || ms === undefined) return <span className="text-disabled">-</span>;
|
||||
const colorClass = ms <= 100 ? "latency-ok" : ms <= 500 ? "latency-warn" : "latency-error";
|
||||
const latencyText = ms > 9999 ? "9999+ms" : `${Math.round(ms)}ms`;
|
||||
const latencyText = ms > 9999 ? "9999+" : `${Math.round(ms)}`;
|
||||
return <span className={`${colorClass} latency-value tabular-nums`}>{latencyText}</span>;
|
||||
},
|
||||
colKey: "latestCheck.durationMs",
|
||||
sorter: latencySorter,
|
||||
sortType: "all",
|
||||
title: "延迟",
|
||||
title: "延迟(ms)",
|
||||
width: 75,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -13,10 +13,6 @@ export function latencySorter(a: TargetStatus, b: TargetStatus): number {
|
||||
return (a.latestCheck?.durationMs ?? Infinity) - (b.latestCheck?.durationMs ?? Infinity);
|
||||
}
|
||||
|
||||
export function nameSorter(a: TargetStatus, b: TargetStatus): number {
|
||||
return a.name.localeCompare(b.name, "zh-CN");
|
||||
}
|
||||
|
||||
export function statusSorter(a: TargetStatus, b: TargetStatus): number {
|
||||
return getStatusRank(a) - getStatusRank(b);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user