Files
knowledge-governance/web/src/scopeRules.ts
T
姚章浩 e34306b2db
build / build (push) Failing after 18s
fix(ui): 已释放窗口不再渲染 held 文案,版本页不再把 500 说成未接线
发布管理:maintenanceSummary 只看 job.state === 'failed' 就给 held 处置文案;
窗口已 released 的旧作业(libsync-internal-1793399248431728863)因此自相矛盾。
改为仅 held 时给 recoveryError,已释放时给 releasedFailure(如实记录失败,不提供强制成功)。

版本记录:LoadVersionHistorySyncState 把可空的 finished_at 扫进 time.Time;
部署重启触发的同步在"进行中"时该列为 NULL,扫描失败使整页 500
(nginx access log:GET /api/v1/version-history?limit=30 → 500,74 字节错误体)。
改为指针接值再判空。前端同时区分"未配置/加载失败"并显示服务端 code。

RED/GREEN:新增 Go 集成用例(NULL finished_at)、两条前端用例;
make verify 16/16 通过(local 档案)。
2026-11-01 19:34:31 +08:00

64 lines
2.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { newOperationID } from './operationKey'
export type ScopeTargetType = 'directory' | 'item'
export type Visibility = 'internal' | 'external'
export interface ScopeRule {
target_type: ScopeTargetType
connection_id?: string
directory_path?: string
source_item_id?: string
visibility: Visibility
updated_by: string
reason: string
updated_at: string
}
export interface ScopeRuleTarget {
target_type: ScopeTargetType
connection_id: string
directory_path: string
source_item_id: string
}
export interface ScopeRuleDecision extends ScopeRuleTarget {
visibility: Visibility
reason: string
}
export interface ClearScopeRuleDecision extends ScopeRuleTarget {
reason: string
}
export async function fetchScopeRules(connectionID: string, signal?: AbortSignal): Promise<ScopeRule[]> {
const response = await fetch(`/api/v1/scope-rules?${new URLSearchParams({ connection_id: connectionID })}`, {
headers: { Accept: 'application/json' },
signal,
})
if (!response.ok) throw new Error(`加载范围规则失败(HTTP ${response.status})`)
const value = (await response.json()) as { data?: unknown }
if (!Array.isArray(value.data)) throw new Error('范围规则响应无效')
return value.data as ScopeRule[]
}
async function mutateScopeRule(
method: 'PUT' | 'DELETE',
body: ScopeRuleDecision | ClearScopeRuleDecision
): Promise<ScopeRule> {
const response = await fetch('/api/v1/scope-rules', {
method,
headers: { Accept: 'application/json', 'Content-Type': 'application/json', 'Idempotency-Key': newOperationID() },
body: JSON.stringify(body),
})
if (!response.ok) throw new Error(`${method === 'PUT' ? '保存' : '清除'}范围规则失败(HTTP ${response.status})`)
const value = (await response.json()) as { data?: ScopeRule }
if (!value.data || typeof value.data !== 'object') throw new Error('范围规则响应无效')
return value.data
}
export function setScopeRule(decision: ScopeRuleDecision) {
return mutateScopeRule('PUT', decision)
}
export function clearScopeRule(decision: ClearScopeRuleDecision) {
return mutateScopeRule('DELETE', decision)
}