From 8a27c357298f8d94b65081a4da2612384dedf265 Mon Sep 17 00:00:00 2001 From: Max Li Date: Sun, 15 Mar 2026 10:43:24 -0700 Subject: [PATCH] feat: add Import All button to cookie picker Adds an "Import All (N)" button in the source panel footer that imports all visible unimported domains in a single batch request. Respects the search filter so users can narrow down domains first. Button hides when all domains are already imported. Co-Authored-By: Claude Opus 4.6 (1M context) --- browse/src/cookie-picker-ui.ts | 66 ++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/browse/src/cookie-picker-ui.ts b/browse/src/cookie-picker-ui.ts index b2386dc4..381cf2e2 100644 --- a/browse/src/cookie-picker-ui.ts +++ b/browse/src/cookie-picker-ui.ts @@ -213,7 +213,22 @@ export function getCookiePickerHTML(serverPort: number): string { border-top: 1px solid #222; font-size: 12px; color: #666; + display: flex; + align-items: center; + justify-content: space-between; } + .btn-import-all { + padding: 4px 12px; + border-radius: 6px; + border: 1px solid #333; + background: #1a1a1a; + color: #4ade80; + font-size: 12px; + cursor: pointer; + transition: all 0.15s; + } + .btn-import-all:hover { border-color: #4ade80; background: #0a2a14; } + .btn-import-all:disabled { opacity: 0.3; cursor: not-allowed; pointer-events: none; } /* ─── Imported Panel ──────────────────── */ .imported-empty { @@ -299,7 +314,7 @@ export function getCookiePickerHTML(serverPort: number): string {
Detecting browsers...
- + @@ -327,7 +342,8 @@ export function getCookiePickerHTML(serverPort: number): string { const $search = document.getElementById('search'); const $sourceDomains = document.getElementById('source-domains'); const $importedDomains = document.getElementById('imported-domains'); - const $sourceFooter = document.getElementById('source-footer'); + const $sourceFooter = document.getElementById('source-footer-text'); + const $btnImportAll = document.getElementById('btn-import-all'); const $importedFooter = document.getElementById('imported-footer'); const $banner = document.getElementById('banner'); @@ -519,6 +535,16 @@ export function getCookiePickerHTML(serverPort: number): string { const totalCookies = allDomains.reduce((s, d) => s + d.count, 0); $sourceFooter.textContent = totalDomains + ' domains · ' + totalCookies.toLocaleString() + ' cookies'; + // Show/hide Import All button + const unimported = filtered.filter(d => !(d.domain in importedSet) && !inflight[d.domain]); + if (unimported.length > 0) { + $btnImportAll.style.display = ''; + $btnImportAll.disabled = false; + $btnImportAll.textContent = 'Import All (' + unimported.length + ')'; + } else { + $btnImportAll.style.display = 'none'; + } + // Click handlers $sourceDomains.querySelectorAll('.btn-add[data-domain]').forEach(btn => { btn.addEventListener('click', () => importDomain(btn.dataset.domain)); @@ -553,6 +579,42 @@ export function getCookiePickerHTML(serverPort: number): string { } } + // ─── Import All ─────────────────────── + async function importAll() { + const query = $search.value.toLowerCase(); + const filtered = query + ? allDomains.filter(d => d.domain.toLowerCase().includes(query)) + : allDomains; + const toImport = filtered.filter(d => !(d.domain in importedSet) && !inflight[d.domain]); + if (toImport.length === 0) return; + + $btnImportAll.disabled = true; + $btnImportAll.textContent = 'Importing...'; + + const domains = toImport.map(d => d.domain); + try { + const data = await api('/import', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ browser: activeBrowser, domains: domains, profile: activeProfile }), + }); + + if (data.domainCounts) { + for (const [d, count] of Object.entries(data.domainCounts)) { + importedSet[d] = (importedSet[d] || 0) + count; + } + } + renderImported(); + } catch (err) { + showBanner('Import all failed: ' + err.message, 'error', + err.action === 'retry' ? () => importAll() : null); + } finally { + renderSourceDomains(); + } + } + + $btnImportAll.addEventListener('click', importAll); + // ─── Render Imported ─────────────────── function renderImported() { const entries = Object.entries(importedSet).sort((a, b) => b[1] - a[1]);