e34306b2db
build / build (push) Failing after 18s
发布管理: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 档案)。
64 lines
2.1 KiB
TypeScript
64 lines
2.1 KiB
TypeScript
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)
|
||
}
|