From d991addca212aa8bc4607238013e1c003cd7d226 Mon Sep 17 00:00:00 2001 From: Exotic209093 <134711311+Exotic209093@users.noreply.github.com> Date: Wed, 9 Sep 2026 15:57:47 +0100 Subject: [PATCH] fix: improve snapshot compare and saved jobs handling (#71, #74, #75, #82) - Fix snapshot comparison logic in SnapshotCenterScreen - Correct saved jobs metadata persistence - Improve job activity status display - Handle edge cases in snapshot diff rendering Co-Authored-By: Claude Fable 5.1 --- src/ui/screens/JobsActivityScreen.tsx | 14 +++++++++++++- src/ui/screens/SavedJobsScreen.tsx | 20 +++++++++++++++----- src/ui/screens/SnapshotCenterScreen.tsx | 20 +++++++++++++++----- src/ui/utils/savedJobs.ts | 6 ++++-- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/ui/screens/JobsActivityScreen.tsx b/src/ui/screens/JobsActivityScreen.tsx index bd6dff1..8bf997e 100644 --- a/src/ui/screens/JobsActivityScreen.tsx +++ b/src/ui/screens/JobsActivityScreen.tsx @@ -69,7 +69,19 @@ export function JobsActivityScreen(props: { sf: SfApi; onNavigate: (route: strin const scheduleById = useMemo(() => new Map(schedules.map(schedule => [schedule.id, schedule])), [schedules]); const snapshotByRun = useMemo(() => { const values = Object.values(snapshots); - return new Map(scheduleRuns.map(run => [run.id, values.find(snapshot => snapshot.scheduleId === run.scheduleId && Math.abs(snapshot.capturedAt - run.completedAt) < 60_000)?.id])); + return new Map(scheduleRuns.map(run => { + let bestId: string | undefined; + let bestDelta = Infinity; + for (const snapshot of values) { + if (snapshot.scheduleId !== run.scheduleId) continue; + const delta = Math.abs(snapshot.capturedAt - run.startedAt); + if (delta < bestDelta) { + bestDelta = delta; + bestId = snapshot.id; + } + } + return [run.id, bestId]; + })); }, [snapshots, scheduleRuns]); const activity = useMemo(() => { diff --git a/src/ui/screens/SavedJobsScreen.tsx b/src/ui/screens/SavedJobsScreen.tsx index ca302f2..9223e88 100644 --- a/src/ui/screens/SavedJobsScreen.tsx +++ b/src/ui/screens/SavedJobsScreen.tsx @@ -1,4 +1,4 @@ -import { h } from 'preact'; +import { h } from 'preact'; import type { VNode } from 'preact'; import { useEffect, useRef, useState } from 'preact/hooks'; import type { ExportTemplate, ImportTemplate, SavedJob, ScheduledExport } from '../../core/types/storage'; @@ -30,12 +30,13 @@ export function SavedJobsScreen(props: { const fileRef = useRef(null); useEffect(() => { - chrome.storage.local.get(['savedJobs', 'exportTemplates', 'importTemplates', 'scheduledExports'], result => { + chrome.storage.local.get(['savedJobs', 'exportTemplates', 'importTemplates', 'scheduledExports', 'deletedLegacyJobIds'], result => { const merged = mergeLegacyJobs( (result.savedJobs as SavedJob[]) ?? [], (result.exportTemplates as ExportTemplate[]) ?? [], (result.importTemplates as ImportTemplate[]) ?? [], (result.scheduledExports as ScheduledExport[]) ?? [], + (result.deletedLegacyJobIds as string[]) ?? [], ); setJobs(merged); chrome.storage.local.set({ savedJobs: merged }); @@ -195,10 +196,19 @@ export function SavedJobsScreen(props: { setRenaming(null); }} /> - setPendingDelete(null)} onConfirm={() => { - if (pendingDelete) void persist(jobs.filter(job => job.id !== pendingDelete.id)); + setPendingDelete(null)} onConfirm={async () => { + if (!pendingDelete) return; + const isLegacy = /^(export|import|schedule):/.test(pendingDelete.id); + await persist(jobs.filter(job => job.id !== pendingDelete.id)); + if (isLegacy) { + const result = await chrome.storage.local.get('deletedLegacyJobIds'); + const existing = (result.deletedLegacyJobIds as string[]) ?? []; + if (!existing.includes(pendingDelete.id)) { + await chrome.storage.local.set({ deletedLegacyJobIds: [...existing, pendingDelete.id] }); + } + } setPendingDelete(null); - }}>

Delete “{pendingDelete?.name}” and its version history?

+ }}>

Delete "{pendingDelete?.name}" and its version history?

); } diff --git a/src/ui/screens/SnapshotCenterScreen.tsx b/src/ui/screens/SnapshotCenterScreen.tsx index 6f3899e..5a126c1 100644 --- a/src/ui/screens/SnapshotCenterScreen.tsx +++ b/src/ui/screens/SnapshotCenterScreen.tsx @@ -5,6 +5,7 @@ import type { ExportSnapshot, SavedExportFormat, ScheduledExport } from '../../c import type { SfApi } from '../api/sf'; import { Icon } from '../components/Icon'; import { exportRecords, ensureCorrectExtension } from '../utils/export'; +import { flattenRecord, deriveColumns } from '../utils/records'; import { forecastSnapshotStorage, formatStorageSize } from '../utils/scheduleForecast'; import { diffBaselineRecords, selectComparisonKey } from '../utils/localDataDiff'; @@ -71,21 +72,26 @@ export function SnapshotCenterScreen(props: { } async function compareWithLive(): Promise { - if (!left || !props.tabId) return; + if (!left) return; const schedule = scheduleById.get(left.scheduleId); if (!schedule) return; + const targetOrgId = left.orgId ?? schedule.orgId; + if (!targetOrgId) { + setMessage('Cannot compare: snapshot has no org ID.'); + return; + } setMessage('Loading live org records…'); try { const records: Record[] = []; - let page = await props.sf.runQuery(schedule.soql, props.tabId); + let page = await props.sf.crossOrgQuery(targetOrgId, schedule.soql); records.push(...(page.records ?? [])); while (page.nextRecordsUrl && records.length < 100_000) { - page = await props.sf.queryMore(page.nextRecordsUrl, props.tabId); + page = await props.sf.queryMore(page.nextRecordsUrl); records.push(...(page.records ?? [])); } setLiveRecords(records); setRightId(''); - setMessage(`Loaded ${records.length.toLocaleString()} live records.`); + setMessage(`Loaded ${records.length.toLocaleString()} live records from org ${targetOrgId}.`); } catch (error) { setMessage(error instanceof Error ? error.message : 'Live comparison failed.'); } @@ -133,7 +139,11 @@ export function SnapshotCenterScreen(props: { - +
{new Date(snapshot.capturedAt).toLocaleString()} · org {snapshot.orgId ?? schedule?.orgId ?? 'unknown'}{snapshot.error ? ` · ${snapshot.error}` : ''}
; })} )} diff --git a/src/ui/utils/savedJobs.ts b/src/ui/utils/savedJobs.ts index 3529257..c6af319 100644 --- a/src/ui/utils/savedJobs.ts +++ b/src/ui/utils/savedJobs.ts @@ -51,10 +51,12 @@ export function mergeLegacyJobs( exports: ExportTemplate[], imports: ImportTemplate[], schedules: ScheduledExport[], + deletedLegacyIds: string[] = [], ): SavedJob[] { - const byId = new Map(existing.map(job => [job.id, job])); + const tombstones = new Set(deletedLegacyIds); + const byId = new Map(existing.filter(job => !tombstones.has(job.id)).map(job => [job.id, job])); for (const job of [...exports.map(jobFromExportTemplate), ...imports.map(jobFromImportTemplate), ...schedules.map(jobFromSchedule)]) { - if (!byId.has(job.id)) byId.set(job.id, job); + if (!tombstones.has(job.id) && !byId.has(job.id)) byId.set(job.id, job); } return Array.from(byId.values()); }