- Show total record count and filtered count in subtitle
- Add #N global number to each history entry row
- Add # column index inside each change detail table
- Column header already shown via headers[i] — now labeled "Column"
Co-Authored-By: claude-flow <ruv@ruv.net>
- Add bc-proxy and bc-export serverless API handlers
- Add businessCentral service with updateCpnpNoInBC and downloadBusinessCentralItemsExcel
- Sync cpnpNo to BC on save (CosmeticItemsView and handleSaveAll)
- Parallelize handleSaveAll with Promise.all
- Fix array index key, a11y click/keyboard handlers, autoFocus
- Grant Change History and Pending Validation access to jingying.shi@craze-group.com
Co-Authored-By: claude-flow <ruv@ruv.net>
- saveRowToSupabase now accepts optional status param (default 'pending')
- CosmeticItemsView saves CPNP with status 'edited' so resetAllPendingRows
does not affect it and it survives the startup merge
- Re-added CPNP_NO to editableColumns so the merge restores it from Supabase
Co-Authored-By: claude-flow <ruv@ruv.net>
Bypasses the pending queue timing issue by calling saveRowToSupabase
directly after onSaveRow. Shows a spinner while saving. Alert on error.
Co-Authored-By: claude-flow <ruv@ruv.net>
Items with a CPNP number now display it in green. Empty cells still show
the dashed 'Click to fill...' button. Both are clickable to edit inline.
Co-Authored-By: claude-flow <ruv@ruv.net>
CPNP_NO re-added to COLUMN_PATTERNS so resolveColumnIndices maps it to
the real Excel column index. Removed it from VIRTUAL_COLS and editableColumns
in App.tsx since data comes from the spreadsheet, not Supabase-only storage.
Co-Authored-By: claude-flow <ruv@ruv.net>
CPNP_NO must stay hardcoded at index 107. Removed it from COLUMN_PATTERNS
and added guard to skip empty patterns in resolveColumnIndices.
Co-Authored-By: claude-flow <ruv@ruv.net>
Show all cosmetic products regardless of CPNP status. Column filter on
CPNP No. lets user isolate items with empty value.
Co-Authored-By: claude-flow <ruv@ruv.net>
New sidebar tab for cosmetic product lines (INKEE, BATH FUN, TOP FASHION,
SENSES, BODYNESS) filtered to items with empty CPNP No. Column filters on
Item Available allow toggling zero/non-zero stock. CPNP_NO added as virtual
column (index 107) stored in Supabase.
Co-Authored-By: claude-flow <ruv@ruv.net>
After dragging to select rows, checkboxes appear in the Check Ying
and Check Anna column headers showing the count of selected rows.
Clicking one marks or unmarks that column for all selected rows,
then clears the selection. Footer shows a hint with a cancel button.
Co-Authored-By: claude-flow <ruv@ruv.net>
Dragging the mouse over rows now directly toggles Check Ying on all
covered rows on mouseup. The check value (on/off) is determined by
the state of the first row touched, so dragging over unchecked rows
marks them and vice versa. Rows light up blue during the drag to
show what will be affected.
Co-Authored-By: claude-flow <ruv@ruv.net>
Completes the fix where pinned column filter popovers were hidden
behind sticky body cells. The outerH <th> was missed in the batch
and still used the lower body-level stacking rank.
Co-Authored-By: claude-flow <ruv@ruv.net>
- Add zIndex prop to ColumnFilterPopover and TextFilterPopover
- Pass higher zIndex to popovers when column is pinned (zIndex + 100)
- Filter popovers now display correctly over sticky columns
- Include pricingEditableCols and containerCols in column order for pinned calculation
- Fix z-index stacking so all pinned columns stay visible while scrolling
- Add getStickyRank() function for layered z-index on pinned columns
- Higher z-index for rightmost pinned columns so they stack correctly
- Apply z-index dynamically based on column order in pinned list
- All pinned columns now stay visible while scrolling
- Add Pin Columns button to select columns to freeze
- Implement sticky columns with left positioning for pinned columns
- Support pinning dynamic pricing and container columns
- Add Pin icon indicator on pinned columns
- Include reset and unpin all options in pin panel
- Internal control columns (Type, Checking, etc.) now persist across Excel shifts.
- Master data columns now prioritize Dropbox source of truth.
- Added Fullscreen mode to all main tabs (Pricing, Descriptions, Matrix).
- Improved Supabase data loading with pagination.
With 1005+ products, the old query returned only the top 1000 by updated_at.
Items edited long ago (like 51016DE) were silently missing from syncedData,
so the merge never applied their saved edits. Now paginate by product_id
until we exhaust the table.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extended headers array can have empty strings that get passed as header
values; guard all .toLowerCase().includes() calls with (h || '').
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When the Excel shrinks (fewer columns than when an edit was saved), the
saved value exists in Supabase at e.g. index 103 but headers only covers
0-76, so the column never renders. Now we pad headers up to the hardcoded
virtual column indices (PRODUCT_TYPE=103, etc.) so the merge value is
visible in the UI.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Products that have entries in products_history were edited at some point.
If their status was accidentally reset to 'excel', the sync would overwrite
their data. Now also check products_history to build the protected set.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of relying on resolvedCols.PRODUCT_TYPE (which can resolve to the
wrong index if the column header doesn't match the pattern), compare the
saved Supabase row against the fresh Excel row: any index where they differ
is a user edit and gets applied. This fixes TYPE / 'Surprise Bath bomb'
not appearing after reload.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>