From 02a3526f91ba526c8b760362ae44d614e6a5b6f9 Mon Sep 17 00:00:00 2001 From: iberlob Date: Sun, 24 May 2026 23:05:54 +0200 Subject: [PATCH 1/2] Add DB source filtering to prevent selection for restoration --- .../storage/restore/restore-client.tsx | 10 +++ src/components/adapter/adapter-form.tsx | 7 +- src/components/adapter/form-sections.tsx | 64 +++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/src/app/dashboard/storage/restore/restore-client.tsx b/src/app/dashboard/storage/restore/restore-client.tsx index cd88a28d..30b76c90 100644 --- a/src/app/dashboard/storage/restore/restore-client.tsx +++ b/src/app/dashboard/storage/restore/restore-client.tsx @@ -37,6 +37,7 @@ interface AdapterConfig { id: string; name: string; adapterId: string; + metadata?: string; } interface DbConfig { @@ -520,6 +521,15 @@ export function RestoreClient() { {sources .filter(s => { + // Filter out restore-excluded sources + try { + if (s.metadata) { + const meta = JSON.parse(s.metadata); + if (meta.isRestoreExcluded) return false; + } + } catch { } + + // Filter by source type compatibility if (!file?.sourceType) return true; const type = file.sourceType.toLowerCase(); const adapter = s.adapterId.toLowerCase(); diff --git a/src/components/adapter/adapter-form.tsx b/src/components/adapter/adapter-form.tsx index 2020dd40..4259be6c 100644 --- a/src/components/adapter/adapter-form.tsx +++ b/src/components/adapter/adapter-form.tsx @@ -59,6 +59,9 @@ export function AdapterForm({ type, adapters, onSuccess, initialData, onBack }: const initialMeta = initialData?.metadata ? JSON.parse(initialData.metadata) : {}; const [healthNotificationsDisabled, setHealthNotificationsDisabled] = useState(initialMeta.healthNotificationsDisabled === true); + // Exclude from restore (database only) + const [isRestoreExcluded, setIsRestoreExcluded] = useState(initialMeta.isRestoreExcluded === true); + // Credential profile assignments (Phase 4 - Generic Credential Profile System) const [primaryCredentialId, setPrimaryCredentialId] = useState(initialData?.primaryCredentialId ?? null); const [sshCredentialId, setSshCredentialId] = useState(initialData?.sshCredentialId ?? null); @@ -198,7 +201,7 @@ export function AdapterForm({ type, adapters, onSuccess, initialData, onBack }: // Build metadata with health notification preference for database/storage adapters const existingMeta = initialData?.metadata ? JSON.parse(initialData.metadata) : {}; const metadata = (type === 'database' || type === 'storage') - ? { ...existingMeta, healthNotificationsDisabled } + ? { ...existingMeta, healthNotificationsDisabled, ...(type === 'database' ? { isRestoreExcluded } : {}) } : existingMeta; const payload = { @@ -394,6 +397,8 @@ export function AdapterForm({ type, adapters, onSuccess, initialData, onBack }: detectedVersion={detectedVersion} healthNotificationsDisabled={healthNotificationsDisabled} onHealthNotificationsDisabledChange={setHealthNotificationsDisabled} + isRestoreExcluded={isRestoreExcluded} + onIsRestoreExcludedChange={setIsRestoreExcluded} primaryCredentialId={primaryCredentialId} sshCredentialId={sshCredentialId} onPrimaryChange={setPrimaryCredentialId} diff --git a/src/components/adapter/form-sections.tsx b/src/components/adapter/form-sections.tsx index 7bb4cac5..750e153f 100644 --- a/src/components/adapter/form-sections.tsx +++ b/src/components/adapter/form-sections.tsx @@ -54,6 +54,8 @@ interface SectionProps extends CredentialPickerHostProps { detectedVersion?: string | null; healthNotificationsDisabled?: boolean; onHealthNotificationsDisabledChange?: (disabled: boolean) => void; + isRestoreExcluded?: boolean; + onIsRestoreExcludedChange?: (excluded: boolean) => void; } /** @@ -127,11 +129,37 @@ function HealthCheckNotificationSwitch({ ); } +function RestoreExcludedSwitch({ + excluded, + onChange, +}: { + excluded: boolean; + onChange: (excluded: boolean) => void; +}) { + return ( +
+
+ +

+ This source will not appear as a restore target when recovering backups. Backups can still be created from this source. +

+
+ +
+ ); +} + export function DatabaseFormContent({ adapter, detectedVersion, healthNotificationsDisabled, onHealthNotificationsDisabledChange, + isRestoreExcluded, + onIsRestoreExcludedChange, primaryCredentialId, sshCredentialId, onPrimaryChange, @@ -200,6 +228,12 @@ export function DatabaseFormContent({ onChange={onHealthNotificationsDisabledChange} /> )} + {onIsRestoreExcludedChange && ( + + )} ) : ( @@ -258,6 +292,12 @@ export function DatabaseFormContent({ onChange={onHealthNotificationsDisabledChange} /> )} + {onIsRestoreExcludedChange && ( + + )} )} @@ -293,6 +333,8 @@ export function DatabaseFormContent({ detectedVersion={detectedVersion} healthNotificationsDisabled={healthNotificationsDisabled} onHealthNotificationsDisabledChange={onHealthNotificationsDisabledChange} + isRestoreExcluded={isRestoreExcluded} + onIsRestoreExcludedChange={onIsRestoreExcludedChange} primaryCredentialId={primaryCredentialId} sshCredentialId={sshCredentialId} onPrimaryChange={onPrimaryChange} @@ -364,6 +406,12 @@ export function DatabaseFormContent({ onChange={onHealthNotificationsDisabledChange} /> )} + {onIsRestoreExcludedChange && ( + + )} {isMSSQL && ( @@ -406,6 +454,8 @@ function SshAwareTabLayout({ detectedVersion, healthNotificationsDisabled, onHealthNotificationsDisabledChange, + isRestoreExcluded, + onIsRestoreExcludedChange, primaryCredentialId, sshCredentialId, onPrimaryChange, @@ -418,6 +468,8 @@ function SshAwareTabLayout({ detectedVersion?: string | null; healthNotificationsDisabled?: boolean; onHealthNotificationsDisabledChange?: (disabled: boolean) => void; + isRestoreExcluded?: boolean; + onIsRestoreExcludedChange?: (excluded: boolean) => void; } & CredentialPickerHostProps) { return (
@@ -478,6 +530,12 @@ function SshAwareTabLayout({ onChange={onHealthNotificationsDisabledChange} /> )} + {onIsRestoreExcludedChange && ( + + )} ) : ( @@ -515,6 +573,12 @@ function SshAwareTabLayout({ onChange={onHealthNotificationsDisabledChange} /> )} + {onIsRestoreExcludedChange && ( + + )} )} From 177cd88eb5d1cc5608ce9a310808673381865b5b Mon Sep 17 00:00:00 2001 From: Manu Date: Mon, 25 May 2026 11:27:41 +0200 Subject: [PATCH 2/2] Simplify 'Exclude from Restore' help text Remove a redundant/misleading sentence from the Exclude from Restore helper text in src/components/adapter/form-sections.tsx so the message only states the source won't appear as a restore target, avoiding confusion about backup creation. --- src/components/adapter/form-sections.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/adapter/form-sections.tsx b/src/components/adapter/form-sections.tsx index 750e153f..794c4a66 100644 --- a/src/components/adapter/form-sections.tsx +++ b/src/components/adapter/form-sections.tsx @@ -141,7 +141,7 @@ function RestoreExcludedSwitch({

- This source will not appear as a restore target when recovering backups. Backups can still be created from this source. + This source will not appear as a restore target when recovering backups.