fix(backups): подтверждать настройки и последнюю проверку S3

This commit is contained in:
Denozordec committed 2026-10-01 15:37:00 +07:00
1 parent 8e01666e0e
commit 30bd479a6f
14 files changed
+208 -64

No files matched your search

+22 -11
View File
@@ -65,15 +65,17 @@ export const defaultStorageForm: BackupStorageForm = {
showPassword: false,
}
function storageStatus(saved: BackupStorageSettingsDto | null, form: BackupStorageForm) {
if (form.provider === "local") {
function storageStatus(saved: BackupStorageSettingsDto | null, dirty: boolean) {
if (dirty) return { label: "Не сохранено", variant: "warning-light" as const }
if (!saved) return { label: "Демонстрация", variant: "secondary" as const }
if (saved.provider === "local") {
return { label: "Локально", variant: "secondary" as const }
}
if (saved?.lastTestError) {
return { label: "Ошибка", variant: "destructive-light" as const }
}
if (saved?.lastTestAt && !saved.lastTestError) {
return { label: "Connected", variant: "success-light" as const }
return { label: "Проверено ранее", variant: "success-light" as const }
}
if (saved?.secretConfigured && saved.s3Bucket) {
return { label: "Не проверено", variant: "warning-light" as const }
@@ -96,6 +98,7 @@ export function BackupsSettings({
onSaveStorage,
scheduleKnown = true,
storageKnown = true,
storageDirty = false,
scheduleWritable = true,
storageWritable = true,
allEnabled = false,
@@ -119,6 +122,7 @@ export function BackupsSettings({
onSaveStorage: () => void
scheduleKnown?: boolean
storageKnown?: boolean
storageDirty?: boolean
scheduleWritable?: boolean
storageWritable?: boolean
allEnabled?: boolean
@@ -130,7 +134,7 @@ export function BackupsSettings({
testBusy: boolean
syncBusy: boolean
}) {
const status = storageStatus(savedStorage, storage)
const status = storageStatus(savedStorage, storageDirty)
const secretPlaceholder = savedStorage?.secretConfigured ? "•••••••• (сохранён)" : "••••••••"
return (
@@ -260,6 +264,7 @@ export function BackupsSettings({
}
contentClassName="px-5 py-5 flex flex-col gap-5"
>
{savedStorage?.lastTestAt && <p className="text-xs text-muted-foreground">Последняя проверка: {new Date(savedStorage.lastTestAt).toLocaleString("ru-RU")}. Текущая доступность может измениться.</p>}
<FormField label="Тип хранилища">
<SegmentedControl
value={storage.provider}
@@ -281,6 +286,7 @@ export function BackupsSettings({
<Input
className="font-mono"
placeholder="https://s3.amazonaws.com"
aria-label="Endpoint"
value={storage.s3Endpoint}
onChange={(e) => onStorageChange("s3Endpoint", e.target.value)}
/>
@@ -290,7 +296,8 @@ export function BackupsSettings({
<Input
className="font-mono"
placeholder="us-east-1"
value={storage.s3Region}
aria-label="Region"
value={storage.s3Region}
onChange={(e) => onStorageChange("s3Region", e.target.value)}
/>
</FormField>
@@ -298,7 +305,8 @@ export function BackupsSettings({
<Input
className="font-mono"
placeholder="mikrotik-backups"
value={storage.s3Bucket}
aria-label="Bucket"
value={storage.s3Bucket}
onChange={(e) => onStorageChange("s3Bucket", e.target.value)}
/>
</FormField>
@@ -307,6 +315,7 @@ export function BackupsSettings({
<Input
className="font-mono"
placeholder="mikrotik"
aria-label="Prefix"
value={storage.s3Prefix}
onChange={(e) => onStorageChange("s3Prefix", e.target.value)}
/>
@@ -316,7 +325,8 @@ export function BackupsSettings({
<Input
className="font-mono"
autoComplete="off"
value={storage.s3AccessKeyId}
aria-label="Access key"
value={storage.s3AccessKeyId}
onChange={(e) => onStorageChange("s3AccessKeyId", e.target.value)}
/>
</FormField>
@@ -327,7 +337,8 @@ export function BackupsSettings({
className="font-mono pr-14"
autoComplete="new-password"
placeholder={secretPlaceholder}
value={storage.s3SecretAccessKey}
aria-label="Secret key"
value={storage.s3SecretAccessKey}
onChange={(e) => onStorageChange("s3SecretAccessKey", e.target.value)}
/>
<button
@@ -345,14 +356,14 @@ export function BackupsSettings({
<p className="text-sm font-medium">Path-style</p>
<p className="text-xs text-muted-foreground mt-0.5">Нужен для MinIO и части совместимых API</p>
</div>
<FormToggle checked={storage.s3ForcePathStyle} onChange={(v) => onStorageChange("s3ForcePathStyle", v)} />
<FormToggle ariaLabel="Path-style" checked={storage.s3ForcePathStyle} onChange={(v) => onStorageChange("s3ForcePathStyle", v)} />
</div>
<div className="flex items-center justify-between gap-3">
<div>
<p className="text-sm font-medium">Оставлять локальную копию</p>
<p className="text-xs text-muted-foreground mt-0.5">После успешной загрузки в S3</p>
</div>
<FormToggle checked={storage.keepLocalCopy} onChange={(v) => onStorageChange("keepLocalCopy", v)} />
<FormToggle ariaLabel="Оставлять локальную копию" checked={storage.keepLocalCopy} onChange={(v) => onStorageChange("keepLocalCopy", v)} />
</div>
{savedStorage?.lastTestError ? (
<p className="text-xs text-destructive">{savedStorage.lastTestError}</p>
@@ -425,7 +436,7 @@ export function BackupsSettings({
})}
</div>
<p className="text-xs text-muted-foreground">
Выбрано {selectedServers.size} из {servers.length} серверов
{allEnabled ? "Все включённые устройства, включая добавленные позже" : "Выбрано " + selectedServers.size + " из " + servers.length + " серверов"}
</p>
</OpsPanel>
</fieldset>