Add server monitoring and database backup pages
New sidebar sections wired to the backend's new admin APIs: - Monitoring: live request/error-rate/latency stats plus a recent-requests table, polling every 8s. - Backups: create/list/download database backups (auth'd blob download since the endpoint requires a Bearer token, not a plain link).
This commit is contained in:
@@ -306,3 +306,72 @@ export function rejectUser(id: number, reason: string) {
|
||||
body: JSON.stringify({ reason }),
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------- ادمین: مانیتورینگ ----------------
|
||||
|
||||
export interface MonitoringSummary {
|
||||
total_requests: number;
|
||||
total_errors: number;
|
||||
error_rate_pct: number;
|
||||
avg_latency_ms: number;
|
||||
p95_latency_ms: number;
|
||||
requests_last_min: number;
|
||||
started_at: string;
|
||||
uptime_seconds: number;
|
||||
}
|
||||
|
||||
export interface RequestLogEntry {
|
||||
time: string;
|
||||
method: string;
|
||||
path: string;
|
||||
status_code: number;
|
||||
duration_ms: number;
|
||||
client_ip: string;
|
||||
user_id?: number;
|
||||
}
|
||||
|
||||
export function getMonitoringSummary() {
|
||||
return authRequest<MonitoringSummary>("/admin/monitoring/summary");
|
||||
}
|
||||
|
||||
export function getRecentRequests(limit = 100) {
|
||||
return authRequest<RequestLogEntry[]>(`/admin/monitoring/requests?limit=${limit}`);
|
||||
}
|
||||
|
||||
// ---------------- ادمین: بکآپ دیتابیس ----------------
|
||||
|
||||
export interface BackupInfo {
|
||||
filename: string;
|
||||
size_bytes: number;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export function listBackups() {
|
||||
return authRequest<BackupInfo[]>("/admin/backups");
|
||||
}
|
||||
|
||||
export function createBackup() {
|
||||
return authRequest<BackupInfo>("/admin/backups", { method: "POST" });
|
||||
}
|
||||
|
||||
// دانلود بکآپ نیاز به هدر Authorization داره (اندپوینت فقط-ادمینه)، پس نمیشه
|
||||
// مستقیم از یک <a href> استفاده کرد؛ فایل رو با fetch احرازهویتشده میگیریم و
|
||||
// خودمون دانلودش رو با یک لینک موقت شبیهسازی میکنیم.
|
||||
export async function downloadBackup(filename: string) {
|
||||
const token = tokenStore.getAccess();
|
||||
const res = await fetch(`${API_BASE}/admin/backups/${encodeURIComponent(filename)}`, {
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new ApiError("دانلود بکآپ ناموفق بود", res.status);
|
||||
}
|
||||
const blob = await res.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user