From 8fa001c6ed741eb5c2280ab1476fd677c3d01dfb Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Wed, 8 Apr 2026 16:11:37 +0200 Subject: [PATCH] feat: short description AI targeting 30% length + checkbox sync for near-duplicate dimensions - EditPanel: short description prompts now target ~30% of the long description character count, preserving key highlights as flowing prose - DimensionsView: near-duplicate clusters expanded view replaced with a flat checkbox list (SKU + name + current dims per row), a target-dimension dropdown, and a "Sync N selected" button that unifies inner dimensions across selected products via ConfirmModal Co-Authored-By: Claude Sonnet 4.6 --- src/components/DimensionsView.tsx | 164 ++++++++++++++++++++++-------- 1 file changed, 122 insertions(+), 42 deletions(-) diff --git a/src/components/DimensionsView.tsx b/src/components/DimensionsView.tsx index 0d597e2..31b49ac 100644 --- a/src/components/DimensionsView.tsx +++ b/src/components/DimensionsView.tsx @@ -296,49 +296,119 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat {nearDuplicateClusters.length} cluster{nearDuplicateClusters.length !== 1 ? 's' : ''} with dimensions differing <1 cm per axis - {nearDuplicateClusters.map((cluster, ci) => ( -
- - {expandedNearDuplicates.has(ci) && ( -
- {cluster.groups.map((g, gi) => ( -
- {g.key} cm -
- {cluster.volumes[gi].toLocaleString()} cm³ - · - {g.rows.length} product{g.rows.length !== 1 ? 's' : ''}: - - {g.rows.slice(0, 5).map(r => r.row[COLUMNS.ARTICLE_NO]).join(', ')} - {g.rows.length > 5 && +{g.rows.length - 5} more} - -
+ {nearDuplicateClusters.map((cluster, ci) => { + const allClusterRows = cluster.groups.flatMap(g => g.rows); + const selection = clusterSelections[ci] ?? new Set(); + const targetKey = clusterSyncTargets[ci] ?? cluster.groups[0].key; + + return ( +
+ + + {expandedNearDuplicates.has(ci) && ( +
+ {/* Sync toolbar */} +
+ Sync selected to: + + + + {selection.size > 0 && ( + + )}
- ))} -
- )} -
- ))} + + {/* Flat product list */} +
+ {allClusterRows.map(({ row, index }) => { + const isSelected = selection.has(index); + return ( +
setClusterSelections(prev => { + const current = new Set(prev[ci] ?? []); + if (current.has(index)) current.delete(index); else current.add(index); + return { ...prev, [ci]: current }; + })} + > + {}} + onClick={e => e.stopPropagation()} + className="rounded border-slate-600 bg-slate-700 text-violet-600 focus:ring-violet-500 shrink-0" + /> +
+
+ {row[COLUMNS.ARTICLE_NO]} + {row[COLUMNS.ARTICLE_NAME]} +
+
+ + {row[COLUMNS.INNER_L]} × {row[COLUMNS.INNER_W]} × {row[COLUMNS.INNER_H]} cm + +
+ ); + })} +
+
+ )} +
+ ); + })}
)} @@ -523,6 +593,16 @@ export function DimensionsView({ data, headers, onEdit, onSaveRow, onCaptureStat type="warning" confirmText="Sync Group" /> + + setPendingNearDupSync(null)} + title="Sync Inner Dimensions" + message={`Update inner dimensions to ${pendingNearDupSync?.targetGroupKey} cm for ${pendingNearDupSync?.selectedIndices.length} selected product${(pendingNearDupSync?.selectedIndices.length ?? 0) !== 1 ? 's' : ''}?`} + type="warning" + confirmText="Sync Dimensions" + /> ); }