Add governed Files integrity operations UI
This commit is contained in:
@@ -207,6 +207,57 @@ export type FileConnectorCredentialUpdatePayload = Partial<Omit<FileConnectorCre
|
||||
clear_token?: boolean;
|
||||
};
|
||||
|
||||
export type FileIntegrityScan = {
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
storage_backend: string;
|
||||
storage_prefix: string;
|
||||
status: string;
|
||||
revision: number;
|
||||
phase: string;
|
||||
verify_checksums: boolean;
|
||||
batch_size: number;
|
||||
scanned_blob_count: number;
|
||||
verified_blob_count: number;
|
||||
quarantined_blob_count: number;
|
||||
scanned_object_count: number;
|
||||
orphan_object_count: number;
|
||||
created_by_user_id?: string | null;
|
||||
started_at?: string | null;
|
||||
completed_at?: string | null;
|
||||
last_error?: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type FileIntegrityFinding = {
|
||||
id: string;
|
||||
scan_id: string;
|
||||
tenant_id: string;
|
||||
kind: string;
|
||||
state: string;
|
||||
revision: number;
|
||||
blob_id?: string | null;
|
||||
storage_key: string;
|
||||
expected_size_bytes?: number | null;
|
||||
observed_size_bytes?: number | null;
|
||||
expected_checksum_sha256?: string | null;
|
||||
observed_checksum_sha256?: string | null;
|
||||
resolved_at?: string | null;
|
||||
resolved_by_user_id?: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type FileIntegrityActionResult = {
|
||||
action: string;
|
||||
changed: boolean;
|
||||
dry_run: boolean;
|
||||
finding: FileIntegrityFinding;
|
||||
inspection_kind?: string | null;
|
||||
inspection_valid?: boolean | null;
|
||||
};
|
||||
|
||||
export type FileConnectorBrowseItem = {
|
||||
kind: "library" | "folder" | "file";
|
||||
name: string;
|
||||
@@ -1039,6 +1090,91 @@ payload: {
|
||||
return apiFetch<TransferResponse>(settings, "/api/v1/files/transfer", { method: "POST", body: JSON.stringify(payload) });
|
||||
}
|
||||
|
||||
export async function listFileIntegrityScans(
|
||||
settings: ApiSettings,
|
||||
limit = 100
|
||||
): Promise<FileIntegrityScan[]> {
|
||||
const response = await apiFetch<{ scans: FileIntegrityScan[] }>(
|
||||
settings,
|
||||
`/api/v1/files/integrity/scans?limit=${Math.max(1, Math.min(limit, 200))}`
|
||||
);
|
||||
return response.scans;
|
||||
}
|
||||
|
||||
export function createFileIntegrityScan(
|
||||
settings: ApiSettings,
|
||||
payload: { verify_checksums: boolean; batch_size: number }
|
||||
): Promise<FileIntegrityScan> {
|
||||
return apiFetch<FileIntegrityScan>(settings, "/api/v1/files/integrity/scans", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
}
|
||||
|
||||
export function runFileIntegrityScanBatch(
|
||||
settings: ApiSettings,
|
||||
scan: Pick<FileIntegrityScan, "id" | "revision">
|
||||
): Promise<FileIntegrityScan> {
|
||||
return apiFetch<FileIntegrityScan>(
|
||||
settings,
|
||||
`/api/v1/files/integrity/scans/${encodeURIComponent(scan.id)}/run`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({ expected_revision: scan.revision })
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export async function listFileIntegrityFindings(
|
||||
settings: ApiSettings,
|
||||
scanId: string,
|
||||
state?: string
|
||||
): Promise<FileIntegrityFinding[]> {
|
||||
const search = new URLSearchParams({ limit: "1000" });
|
||||
if (state) search.set("state", state);
|
||||
const response = await apiFetch<{ findings: FileIntegrityFinding[] }>(
|
||||
settings,
|
||||
`/api/v1/files/integrity/scans/${encodeURIComponent(scanId)}/findings?${search}`
|
||||
);
|
||||
return response.findings;
|
||||
}
|
||||
|
||||
export function recheckFileIntegrityFinding(
|
||||
settings: ApiSettings,
|
||||
finding: Pick<FileIntegrityFinding, "id" | "revision">,
|
||||
dryRun = false
|
||||
): Promise<FileIntegrityActionResult> {
|
||||
return apiFetch<FileIntegrityActionResult>(
|
||||
settings,
|
||||
`/api/v1/files/integrity/findings/${encodeURIComponent(finding.id)}/recheck`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
dry_run: dryRun,
|
||||
expected_revision: finding.revision
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function cleanupFileIntegrityFinding(
|
||||
settings: ApiSettings,
|
||||
finding: Pick<FileIntegrityFinding, "id" | "revision">,
|
||||
dryRun: boolean
|
||||
): Promise<FileIntegrityActionResult> {
|
||||
return apiFetch<FileIntegrityActionResult>(
|
||||
settings,
|
||||
`/api/v1/files/integrity/findings/${encodeURIComponent(finding.id)}/cleanup`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
dry_run: dryRun,
|
||||
expected_revision: finding.revision
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export async function downloadFile(settings: ApiSettings, file: ManagedFile): Promise<void> {
|
||||
const response = await fetch(apiUrl(settings, `/api/v1/files/${file.id}/download`), { headers: authHeaders(settings), credentials: "include" });
|
||||
if (!response.ok) throw new Error(`${response.status} ${response.statusText}: ${await response.text()}`);
|
||||
|
||||
Reference in New Issue
Block a user