feat(server,contracts,web): dashboard library counts and engine runs triggeredBy/multi-status filters
- GET /dashboard: automation.library {entities, movies, series, seasons,
episodes, assets} and automation.slotSatisfiedRate; home media overview
shows the counts instead of placeholders.
- GET /engine/runs: `status` accepts comma-separated values; new
`triggeredBy` filter (comma-separated) evaluated server-side by scanning
batches and paging with the last inspected row's cursor (scan cap 2000).
- Task stream: source filter and the "active" tab (running,pending) are now
one paginated server query.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
615917bb45
commit
363f85b1a1
13 files changed
+165
-250
No files matched your search
@@ -208,6 +208,28 @@ export type AuditEventQuery = z.infer<typeof AuditEventQuery>;
|
||||
|
||||
// ── 引擎面板(只读直查 openworkflow schema,仅 admin;docs/design/openworkflow-dashboard-reference.md) ──
|
||||
|
||||
/** 逗号分隔的枚举多选(查询串):`a,b` → ["a","b"],未知值报错 */
|
||||
function csvEnum<T extends string>(e: z.ZodType<T>, name: string) {
|
||||
return z
|
||||
.string()
|
||||
.max(200)
|
||||
.transform((s, ctx) => {
|
||||
const out: T[] = [];
|
||||
for (const p of s
|
||||
.split(",")
|
||||
.map((x) => x.trim())
|
||||
.filter(Boolean)) {
|
||||
const r = e.safeParse(p);
|
||||
if (!r.success) {
|
||||
ctx.addIssue({ code: "custom", message: `未知 ${name}: ${p}` });
|
||||
return z.NEVER;
|
||||
}
|
||||
if (!out.includes(r.data)) out.push(r.data);
|
||||
}
|
||||
return out;
|
||||
});
|
||||
}
|
||||
|
||||
/** 引擎 run 状态(含 legacy sleeping/succeeded) */
|
||||
export const EngineRunStatus = z.enum([
|
||||
"pending",
|
||||
@@ -273,7 +295,8 @@ export type EngineRun = z.infer<typeof EngineRun>;
|
||||
export const EngineRunQuery = z.object({
|
||||
cursor: z.string().min(1).optional(),
|
||||
limit: z.coerce.number().int().min(1).max(200).default(50),
|
||||
status: EngineRunStatus.optional(),
|
||||
/** 单值或逗号分隔多值,如 status=running,pending */
|
||||
status: csvEnum(EngineRunStatus, "status").optional(),
|
||||
workflowName: z.string().max(200).optional(),
|
||||
/** created_at 下界(含) */
|
||||
from: Timestamp.optional(),
|
||||
@@ -283,6 +306,8 @@ export const EngineRunQuery = z.object({
|
||||
businessKind: EngineBusinessKind.optional(),
|
||||
/** 按关联业务对象 id 筛选(可与 businessKind 同用) */
|
||||
businessRefId: z.string().min(1).max(200).optional(),
|
||||
/** 按触发来源筛选(单值或逗号分隔多值);来源在服务端逐页推断,一页可能少于 limit,以 nextCursor 为准 */
|
||||
triggeredBy: csvEnum(EngineTriggeredBy, "triggeredBy").optional(),
|
||||
});
|
||||
export type EngineRunQuery = z.infer<typeof EngineRunQuery>;
|
||||
|
||||
|
||||
Reference in new issue
Block a user