feat: persistent multi-step undo system in TopBar

fix: save all changes to Supabase with reliable upsert

- Replace broken PATCH→POST fallback with single atomic upsert (POST +
  Prefer: resolution=merge-duplicates). The old PATCH returned 200 OK
  with empty body for new articles, causing silent data loss on every
  first save per article.
- Fix getAllSyncedRows pagination: add explicit limit=10000 and Range
  header to bypass Supabase's default 1000-row cap.
- Add fetchWithRetry helper (2 retries on 5xx/network errors).
- handleSaveRow now returns Promise<boolean> and closes EditPanel only
  after a confirmed successful save.
- Add 'error' save status: failed rows turn red (border-l-red-500)
  across ProductDescriptions, ArticleDetails, and PricingView.
- EditPanel shows saving spinner, disables buttons while saving, and
  displays inline error message with "Retry Save" on failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Christian Vidal Wolf
2026-04-09 08:22:58 +02:00
co-authored by Claude Sonnet 4.6
parent da4673f7c4
commit c544b9b709
6 changed files with 100 additions and 74 deletions
+10 -8
View File
@@ -455,19 +455,21 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit,
<tbody>
{filteredRows.map(({ row, dataIndex, pricingErrors, unitErrors, isCritical }) => {
const hasAnyError = pricingErrors.length > 0 || unitErrors.length > 0;
const isPending = rowStatuses[String(row[COLUMNS.ARTICLE_NO])] === 'pending';
const saveStatus = rowStatuses[String(row[COLUMNS.ARTICLE_NO])];
return (
<tr
key={dataIndex}
className={cn(
'border-b border-slate-700/50 transition-colors hover:bg-slate-700/20',
isPending
? 'bg-yellow-400/20 border-l-4 border-l-yellow-400'
: isCritical
? 'bg-red-950/20'
: pricingErrors.length > 0
? 'bg-amber-950/10'
: ''
saveStatus === 'error'
? 'bg-red-400/20 border-l-4 border-l-red-500'
: saveStatus === 'pending'
? 'bg-yellow-400/20 border-l-4 border-l-yellow-400'
: isCritical
? 'bg-red-950/20'
: pricingErrors.length > 0
? 'bg-amber-950/10'
: ''
)}
>
{/* Article No */}