Files
Agent-System-Frontend/src/rdmAuditTree.ts
T
weichen ad503c9535 Complete recursive audit tree navigation
Why: Review found unsupported node detail calls, discarded child pages, shallow trace selection, stale detail responses, invalid operation filters, and missing audit identity.

Evidence: 35 frontend test files with 285 tests pass; production build, knip baseline, and diff check pass.

Impact: Both trees paginate recursively, trace selection covers every depth, and audit rows preserve valid operation, object, and source semantics.

Refs: rdm-two-trees-latest-templates
2026-10-15 06:19:33 +00:00

60 lines
2.0 KiB
TypeScript

export interface AuditTreeItem {
kind: string
id: string
title: string
state?: string
hasChildren?: boolean
order?: number
templateBlockId?: string
}
export interface AuditTreePage {
items: AuditTreeItem[]
nextCursor?: string
hasMore: boolean
truncated: boolean
}
type AuditTreePageFetcher = (parent: string, cursor: string) => Promise<AuditTreePage>
export function mergeTreePage(current: AuditTreePage, next: AuditTreePage): AuditTreePage {
return { ...next, items: [...current.items, ...next.items] }
}
async function collectParentPages(fetchPage: AuditTreePageFetcher, parent: string): Promise<AuditTreeItem[]> {
const items: AuditTreeItem[] = []
const seenCursors = new Set<string>()
let cursor = ''
for (let pageNo = 0; pageNo < 100; pageNo++) {
if (seenCursors.has(cursor)) throw new Error('树分页游标重复,已停止加载')
seenCursors.add(cursor)
const page = await fetchPage(parent, cursor)
items.push(...page.items)
if (!page.hasMore) return items
if (!page.nextCursor) throw new Error('树分页缺少后续游标')
cursor = page.nextCursor
}
throw new Error('树分页超过安全上限')
}
export async function collectRecursiveTree(fetchPage: AuditTreePageFetcher): Promise<AuditTreeItem[]> {
const roots = await collectParentPages(fetchPage, '')
const out = [...roots]
const queue = roots.filter(item => item.hasChildren === true)
const seenParents = new Set<string>()
while (queue.length > 0) {
const parent = queue.shift()!
if (seenParents.has(parent.id)) continue
seenParents.add(parent.id)
const children = await collectParentPages(fetchPage, parent.id)
out.push(...children)
if (out.length > 5000) throw new Error('树节点超过安全上限')
queue.push(...children.filter(item => item.hasChildren === true))
}
return out
}
export function isTreeItemInspectable(item: AuditTreeItem): boolean {
return item.kind === 'section' && !item.templateBlockId && !item.id.startsWith('dn-')
}