Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 83 additions & 28 deletions src/components/settings/SettingsSyncPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,8 @@ function ImportExportSection() {
const [importing, setImporting] = createSignal(false);
const [exporting, setExporting] = createSignal(false);
const [importError, setImportError] = createSignal<string | null>(null);
const [confirmImport, setConfirmImport] = createSignal(false);
const [pendingImport, setPendingImport] = createSignal<string | null>(null);

let fileInputRef: HTMLInputElement | undefined;

Expand Down Expand Up @@ -749,20 +751,39 @@ function ImportExportSection() {
const file = input.files?.[0];
if (!file) return;

setImporting(true);
setImportError(null);

try {
const text = await file.text();
await importSettings(text);
setPendingImport(text);
setConfirmImport(true);
} catch (e) {
setImportError(e instanceof Error ? e.message : String(e));
} finally {
setImporting(false);
input.value = "";
}
};

const handleConfirmImport = async () => {
if (!pendingImport()) return;

setImporting(true);
try {
await importSettings(pendingImport()!);
setConfirmImport(false);
setPendingImport(null);
} catch (e) {
setImportError(e instanceof Error ? e.message : String(e));
} finally {
setImporting(false);
}
};

const handleCancelImport = () => {
setConfirmImport(false);
setPendingImport(null);
};

return (
<FormGroup title="Backup & Restore">
<div class="space-y-3">
Expand All @@ -776,31 +797,65 @@ function ImportExportSection() {
</InfoBox>
</Show>

<div class="flex items-center gap-2">
<Button
variant="secondary"
onClick={handleExport}
loading={exporting()}
icon={<DownloadIcon />}
>
Export Settings
</Button>
<Button
variant="secondary"
onClick={handleImportClick}
loading={importing()}
icon={<UploadIcon />}
>
Import Settings
</Button>
<input
ref={fileInputRef}
type="file"
accept=".json"
class="hidden"
onChange={handleFileSelect}
/>
</div>
<Show
when={confirmImport()}
fallback={
<div class="flex items-center gap-2">
<Button
variant="secondary"
onClick={handleExport}
loading={exporting()}
icon={<DownloadIcon />}
>
Export Settings
</Button>
<Button
variant="secondary"
onClick={handleImportClick}
loading={importing()}
icon={<UploadIcon />}
>
Import Settings
</Button>
<input
ref={fileInputRef}
type="file"
accept=".json"
class="hidden"
onChange={handleFileSelect}
/>
</div>
}
>
<div class="p-3 rounded-lg border border-yellow-500/30 bg-yellow-500/10">
<div class="flex items-start justify-between">
<div>
<span class="font-medium text-yellow-400">Confirm Import</span>
<p class="text-sm text-foreground-muted mt-1">
This will overwrite your current sync-managed settings with the imported backup.
This action cannot be undone.
</p>
</div>
</div>
<div class="mt-3 flex items-center gap-2">
<Button
variant="primary"
size="sm"
onClick={handleConfirmImport}
loading={importing()}
>
Yes, Import
</Button>
<Button
variant="ghost"
size="sm"
onClick={handleCancelImport}
>
Cancel
</Button>
</div>
</div>
</Show>
</div>
</FormGroup>
);
Expand Down