- Added UI components for downloading and restoring the application database, enhancing data management capabilities. - Integrated new API routes for system database operations in the backend. - Implemented state management for backup and restore processes, including loading indicators and user notifications.
61 lines
2.0 KiB
TypeScript
61 lines
2.0 KiB
TypeScript
import { ApiClientError } from "@/shared/api/http-client"
|
|
|
|
function trimBaseUrl(baseUrl: string): string {
|
|
return baseUrl.replace(/\/$/, "")
|
|
}
|
|
|
|
function parseFilename(contentDisposition: string | null, fallback: string): string {
|
|
if (!contentDisposition) return fallback
|
|
const utfMatch = /filename\*=UTF-8''([^;]+)/i.exec(contentDisposition)
|
|
if (utfMatch?.[1]) {
|
|
try {
|
|
return decodeURIComponent(utfMatch[1])
|
|
} catch {
|
|
return utfMatch[1]
|
|
}
|
|
}
|
|
const plainMatch = /filename="([^"]+)"/i.exec(contentDisposition)
|
|
if (plainMatch?.[1]) return plainMatch[1]
|
|
return fallback
|
|
}
|
|
|
|
export async function downloadSystemDatabaseBackup(
|
|
baseUrl: string,
|
|
): Promise<{ blob: Blob; filename: string }> {
|
|
const res = await fetch(`${trimBaseUrl(baseUrl)}/api/system/database/backup`)
|
|
if (!res.ok) {
|
|
const payload = await res.json().catch(() => undefined)
|
|
const msg =
|
|
typeof payload === "object" &&
|
|
payload !== null &&
|
|
"error" in payload &&
|
|
typeof (payload as { error?: unknown }).error === "string"
|
|
? (payload as { error: string }).error
|
|
: res.statusText
|
|
throw new ApiClientError(msg, res.status, payload)
|
|
}
|
|
const blob = await res.blob()
|
|
const filename = parseFilename(res.headers.get("Content-Disposition"), "mikrotik-manager.db")
|
|
return { blob, filename }
|
|
}
|
|
|
|
export async function restoreSystemDatabaseBackup(baseUrl: string, file: File): Promise<void> {
|
|
const body = await file.arrayBuffer()
|
|
const res = await fetch(`${trimBaseUrl(baseUrl)}/api/system/database/restore`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/octet-stream" },
|
|
body,
|
|
})
|
|
if (!res.ok) {
|
|
const payload = await res.json().catch(() => undefined)
|
|
const msg =
|
|
typeof payload === "object" &&
|
|
payload !== null &&
|
|
"error" in payload &&
|
|
typeof (payload as { error?: unknown }).error === "string"
|
|
? (payload as { error: string }).error
|
|
: res.statusText
|
|
throw new ApiClientError(msg, res.status, payload)
|
|
}
|
|
}
|