fix(backups): подтверждать настройки и последнюю проверку S3
This commit is contained in:
1 parent
8e01666e0e
commit
30bd479a6f
14 files changed
+208
-64
No files matched your search
@@ -5,7 +5,7 @@ import { PageHeader } from "@/components/page-header"
|
||||
import { backups as mockBackups, servers as mockServers, type Backup, type Server } from "@/lib/data"
|
||||
import { createFilterQuery } from "@/components/reui/filters/filters-query"
|
||||
import type { FilterQuery } from "@/components/reui/filters/filters-types"
|
||||
import type { BackupScheduleSettingsDto, BackupStorageSettingsDto } from "@mmapp/contracts/backups"
|
||||
import { backupStorageSettingsDtoSchema, type BackupScheduleSettingsDto, type BackupStorageSettingsDto } from "@mmapp/contracts/backups"
|
||||
import { KpiStatGrid } from "@/components/reui-kit/kpi-stat-grid"
|
||||
import { Alert, AlertAction, AlertDescription, AlertTitle } from "@/components/reui/alert"
|
||||
import { Button } from "@/components/ui/button"
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
testBackupStorage,
|
||||
type BackupItem,
|
||||
} from "@/shared/api/backups"
|
||||
import { requestJson, requestBlob } from "@/shared/api/http-client"
|
||||
import { ApiClientError, requestJson, requestBlob } from "@/shared/api/http-client"
|
||||
import { toast } from "sonner"
|
||||
import { backupSchedulePayload, backupStoragePayload } from "@/lib/backup-settings"
|
||||
import { BackupsHistory } from "@/components/backups/backups-history"
|
||||
@@ -95,6 +95,7 @@ function BackupsContent() {
|
||||
const [syncBusy, setSyncBusy] = useState(false)
|
||||
const [schedule, setSchedule] = useState<BackupScheduleForm>(defaultSchedule)
|
||||
const [storage, setStorage] = useState<BackupStorageForm>(defaultStorageForm)
|
||||
const [storageIsDirty, setStorageIsDirty] = useState(false)
|
||||
const [savedSchedule, setSavedSchedule] = useState<BackupScheduleSettingsDto | null>(null)
|
||||
const [savedStorage, setSavedStorage] = useState<BackupStorageSettingsDto | null>(null)
|
||||
const [scheduleLastError, setScheduleLastError] = useState<string | null>(null)
|
||||
@@ -108,7 +109,7 @@ function BackupsContent() {
|
||||
const [restoreTarget, setRestoreTarget] = useState<Backup | null>(null)
|
||||
|
||||
const setSched = <K extends keyof BackupScheduleForm>(k: K, v: BackupScheduleForm[K]) => { scheduleDirty.current = true; setSchedule(s => ({ ...s, [k]: v })) }
|
||||
const setStore = <K extends keyof BackupStorageForm>(k: K, v: BackupStorageForm[K]) => { storageDirty.current = true; setStorage(s => ({ ...s, [k]: v })) }
|
||||
const setStore = <K extends keyof BackupStorageForm>(k: K, v: BackupStorageForm[K]) => { if (k !== "showPassword") { storageDirty.current = true; setStorageIsDirty(true) } setStorage(s => ({ ...s, [k]: v })) }
|
||||
|
||||
const mapApiBackupToUi = useCallback((b: BackupItem): Backup => {
|
||||
const kb = Math.round(b.sizeBytes / 1024)
|
||||
@@ -199,9 +200,9 @@ function BackupsContent() {
|
||||
if (!canWrite || !current("storage")) return
|
||||
const abort = startSettingsMutation(); if (!abort) return
|
||||
try {
|
||||
const result = await putBackupStorageSettings(backendUrl, backupStoragePayload(storage), { signal: abort.signal })
|
||||
const result = await putBackupStorageSettings(backendUrl, backupStoragePayload(storage, savedStorage?.secretConfigured), { signal: abort.signal })
|
||||
if (!alive.current || abort.signal.aborted) return
|
||||
setSavedStorage(result); setStorage(prev => ({ ...prev, ...result, s3SecretAccessKey: "" })); storageDirty.current = false; settingsConfirmed("storage")
|
||||
setSavedStorage(result); setStorage(prev => ({ ...prev, ...result, s3SecretAccessKey: "" })); storageDirty.current = false; setStorageIsDirty(false); settingsConfirmed("storage")
|
||||
toast.success("Хранилище сохранено")
|
||||
} catch (error) { if (alive.current && !abort.signal.aborted) setOpError(userApiError(error)) }
|
||||
finally { finishSettingsMutation(abort) }
|
||||
@@ -218,7 +219,15 @@ function BackupsContent() {
|
||||
setSavedStorage(result); settingsConfirmed("storage")
|
||||
if (result.lastTestError || !result.lastTestAt || result.provider !== "s3") throw new Error(result.lastTestError || "Проверка S3 не подтверждена")
|
||||
toast.success("Доступ к S3 подтверждён")
|
||||
} catch (error) { if (alive.current && !abort.signal.aborted) setOpError(userApiError(error)) }
|
||||
} catch (error) {
|
||||
if (alive.current && !abort.signal.aborted) {
|
||||
if (error instanceof ApiClientError && error.payload && typeof error.payload === "object" && "settings" in error.payload) {
|
||||
const parsed = backupStorageSettingsDtoSchema.safeParse(error.payload.settings)
|
||||
if (parsed.success) setSavedStorage(parsed.data)
|
||||
}
|
||||
setOpError(userApiError(error))
|
||||
}
|
||||
}
|
||||
finally { finishSettingsMutation(abort) }
|
||||
}
|
||||
async function handleSyncStorage() {
|
||||
@@ -522,6 +531,7 @@ function BackupsContent() {
|
||||
onSaveStorage={handleSaveStorage}
|
||||
scheduleKnown={known("schedule")}
|
||||
storageKnown={known("storage")}
|
||||
storageDirty={storageIsDirty}
|
||||
scheduleWritable={canWrite && canReadServers && current("schedule") && current("servers")}
|
||||
storageWritable={canWrite && current("storage")}
|
||||
allEnabled={allEnabled}
|
||||
|
||||
Reference in new issue
Block a user