Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: simstudioai/sim
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: simstudioai/sim
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: staging
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 5 commits
  • 71 files changed
  • 4 contributors

Commits on Apr 18, 2026

  1. feat(tables): column selection, keyboard shortcuts, drag reorder, and…

    … undo improvements (#4222)
    
    * feat(tables): add column selection, missing keyboard shortcuts, and Sheets-aligned operations
    
    Click column headers to select entire columns, shift-click to extend to
    a column range. Delete, cut, and copy operations work on column
    selections with full undo/redo support. Adds Home, End, Ctrl+Home,
    Ctrl+End, PageUp, PageDown, Ctrl+Space, and all Shift variants.
    Changes Ctrl+A to select all cells instead of checkbox rows. Column
    header dropdown menu now opens on right-click instead of left-click.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): chevron opens dropdown, drag header to reorder columns
    
    Split column header into label area (click to select, draggable for
    reorder) and chevron button (click to open dropdown menu). Remove
    the grip handle — dragging the header itself now reorders columns.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): full-column highlight during drag reorder
    
    Replace the thin 2px line drop indicator with a full-column highlight
    that spans the entire table height, matching Google Sheets behavior.
    The insertion line is still shown at the drop edge for precision.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): handle drag reorder edge cases, dim source column
    
    Suppress drop indicator when drag would result in no position change
    (dragging onto self or adjacent no-op positions). Dim the source
    column body cells during drag with a background overlay. Skip the
    API call when the computed order is identical to the current order.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * feat(tables): add column reorder undo/redo, body drop targets, and escape cancel
    
    Column drag-and-drop now supports dropping anywhere in a column (not just headers),
    pressing Escape to cancel a drag, and full undo/redo integration for column reordering.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): merge partial updates in updateRow to prevent column data loss
    
    When Mothership called updateRow directly (bypassing the PATCH API route),
    it passed only the changed fields — which were written as the entire row,
    wiping all other columns. Move the merge logic into updateRow itself so
    all callers get correct partial-update semantics, and remove the now-redundant
    pre-merge from both PATCH routes.
    
    * test(tables): add updateRow partial merge tests
    
    Covers the bug where partial updates wiped unmentioned columns — verifies
    that fields not in the update payload are preserved, nulling a field works,
    full-row updates are idempotent, and missing rows throw correctly.
    
    * feat(tables): add delete-column undo/redo, rename metadata sync, and comprehensive row ID patching
    
    - Delete column now captures column definition, cell data, order, and width for full undo/redo
    - Column rename undo/redo now properly syncs columnWidths and columnOrder metadata
    - patchRedoRowId/patchUndoRowId extended to handle all action types containing row IDs
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): remove source column dimming during drag reorder
    
    Only show the insertion line at the drop position, matching Google Sheets
    behavior. Remove dragSourceBounds memo and isDragging prop.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): preserve selection on right-click, auto-resize on double-click, fix escape during drag
    
    - Right-clicking within an existing selection now preserves it instead of
      resetting to a single cell, so context menu operations apply to the full range
    - Double-clicking a column border auto-resizes the column to fit its content
    - Escape during column drag now immediately clears refs before state update,
      preventing the dragend handler from executing the reorder
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): add aria-hidden value and aria-label for column header accessibility
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): tighten auto-resize padding to match Google Sheets
    
    Reduce header padding from +48px to +36px (icon + cell padding) and cell
    padding from +20px to +17px (cell padding + border) for a snug fit.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): clean drag ghost and clear selection on drag start
    
    - Create a minimal custom drag image showing only the column name instead
      of the browser's default ghost that includes adjacent columns/checkboxes
    - Clear any existing cell/column selection when starting a column drag to
      prevent stale highlights from persisting during reorder
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * feat(tables): add Shift+Space row selection and Ctrl+D fill down
    
    Shift+Space now selects the entire row (all columns) instead of toggling
    a checkbox, matching Google Sheets behavior. Ctrl+D copies the top cell's
    value down through the selected range with full undo/redo support.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): show toast on incompatible column type change
    
    The server validates type compatibility and returns a clear error message
    (e.g. "3 row(s) have incompatible values"), but the client was silently
    swallowing it. Now surfaces the error via toast notification. Also moved
    the undo push to onSuccess so a failed type change doesn't pollute the
    undo stack.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): scroll-into-view for selection focus, Home/End origin, delete-column undo timing
    
    - Scroll-into-view now tracks selectionFocus (not just anchor), so
      Shift+Arrow extending selection off-screen properly auto-scrolls
    - Shift+Home/End now uses the current focus as origin (matching
      Shift+Arrow behavior) instead of always using anchor
    - Delete column undo entry is now pushed in onSuccess, preventing
      a corrupted undo stack if the server rejects the deletion
    - Dialog copy updated from "cannot be undone" to "You can undo this
      action" since undo/redo is supported
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix: resolve duplicate declarations from rebase against staging
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix file upload
    
    * fix(tables): merge column widths on delete-column undo, try/finally for auto-resize
    
    - Delete-column undo now reads current column widths via getColumnWidths
      callback and merges the restored column's width into the full map,
      preventing other columns' widths from being wiped
    - Auto-resize measurement span is now wrapped in try/finally to ensure
      DOM cleanup if an exception occurs during measurement
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix: revert accidental home.tsx change from rebase conflict resolution
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): clear isColumnSelection on double-click and right-click, skip scroll for column select
    
    - Clear isColumnSelection when double-clicking a cell to edit, preventing
      the column selection effect from fighting with the editing state
    - Clear isColumnSelection when right-clicking outside the current
      selection, preventing stale column selection from re-expanding
    - Skip scroll-into-view when isColumnSelection is true, preventing
      the viewport from jumping to the bottom row when clicking a column header
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): remove inline font override in auto-resize, guard undefined columnOrder
    
    - Remove `font:inherit` from measurement span inline style so Tailwind
      classes (font-medium, text-small) control font properties for accurate
      column width measurement
    - Only include columnOrder in metadata update when defined, preventing
      handleColumnRename from clearing a persisted column order when
      columnOrderRef is null
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): capture columnRequired in delete-column undo for full restoration
    
    The delete-column undo action captured columnUnique but not columnRequired,
    so undoing a delete on a required column would silently drop the constraint.
    Now captures and restores both constraints.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): restore width independently of order on delete-column undo, batch fill-down
    
    - Column width restoration in delete-column undo no longer requires
      previousOrder to be non-null — width is restored independently
    - Ctrl+D fill-down now uses batchUpdateRef (single API call) instead
      of calling mutateRef per row in a loop
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): multi-column delete, select-all cell model, cut flash, chevron alignment
    
    - Multi-select delete: detect column selection range and delete all selected
      columns sequentially with individual undo entries
    - Select all (header checkbox): use cell selection model instead of checkbox
      model for consistent highlighting
    - Cut flash: batch cell clears into single mutation to prevent stale data
      flashing from multiple onSettled invalidations
    - Chevron alignment: adjust right padding from pr-2 to pr-2.5
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): restore column width locally on delete-column undo
    
    Add onColumnWidthsChange callback to undo hook so restored column
    widths update local component state, not just server metadata.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): prevent Ctrl+D bookmark dialog, batch Delete/Backspace mutations
    
    - Move e.preventDefault() before early returns in Ctrl+D handler so
      the browser bookmark dialog is always suppressed
    - Replace per-row mutateRef calls with single batchUpdateRef call in
      both Delete/Backspace handlers (checked rows and cell selection),
      consistent with cut and fill-down
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): adjust column positions for multi-column delete undo
    
    Capture original schema positions upfront and adjust each by the
    count of previously-deleted columns with lower positions, so undo
    restores columns at correct server-side positions in LIFO order.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): only multi-delete when clicked column is within selection
    
    Check that the right-clicked column is within the selected column
    range before using multi-column delete. If the click is outside the
    selection, delete only the clicked column.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): prevent duplicate undo entry on column drag-drop
    
    Clear dragColumnNameRef immediately in handleColumnDragEnd so the
    second invocation (from dragend after drop already fired) is a no-op.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): clean up width on delete-column redo, suppress click during drag
    
    - Redo path for delete-column now removes the column's width from
      metadata and local state, preventing stale width entries
    - Add didDragRef to ColumnHeaderMenu to suppress the click event
      that fires after a drag operation, preventing selection flash
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): remove unstable mutation object from useCallback deps
    
    deleteTableMutation is not referentially stable — only .mutateAsync()
    is. Including the mutation object causes unnecessary callback recreation
    on every mutation state change.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): fix auto-resize header padding, deduplicate rename metadata logic
    
    Increase header text measurement padding from 36px to 57px to account
    for the chevron dropdown button (pl-0.5 + 9px icon + pr-2.5) that
    always occupies layout space. Prevents header text truncation on
    auto-resize.
    
    Deduplicate column rename metadata logic by having columnRename.onSave
    call handleColumnRename instead of reimplementing the same width/order
    transfer and metadata persist.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): log error on cell data restoration failure during undo
    
    Add onError handler to the batchUpdateRowsMutation inside
    delete-column undo so failures are logged instead of silently
    swallowed. The column schema restores first, and the cell data
    restoration is a separate async call that the outer try/catch
    cannot intercept.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): address audit findings across table, undo hook, and store
    
    - Add missing bounds check in handleCopy (c >= cols.length) matching
      handleCut for defensive consistency
    - Clear lastCheckboxRowRef in Ctrl+Space and Shift+Space to prevent
      stale shift-click checkbox range after keyboard selection
    - Fix stale snapshot race in patchRedoRowId/patchUndoRowId by reading
      state inside the set() updater instead of via get() outside it
    - Add metadata cleanup to create-column undo so column width is removed
      from both local state and server, symmetric with delete-column redo
    - Remove stale width key from columnWidths on column delete instead of
      persisting orphaned entries
    - Normalize undefined vs null in handleInlineSave change detection to
      prevent unnecessary mutations when oldValue is undefined
    - Use ghost.parentNode?.removeChild instead of document.body.removeChild
      in drag ghost cleanup to prevent throw on component unmount
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(tables): reset didDragRef in handleDragEnd to prevent stale flag
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 <[email protected]>
    waleedlatif1 and claude authored Apr 18, 2026
    Configuration menu
    Copy the full SHA
    a01f80c View commit details
    Browse the repository at this point in the history
  2. chore(readme): update tech stack section (#4227)

    * chore(readme): update tech stack section
    
    * fix
    icecrasher321 authored Apr 18, 2026
    Configuration menu
    Copy the full SHA
    32541e7 View commit details
    Browse the repository at this point in the history
  3. fix(blocks): resolve variable display in mothership resource preview (#…

    …4226)
    
    * fix(blocks): resolve variable display in mothership resource preview
    
    Variables block showed empty assignments in the embedded workflow preview
    because currentWorkflowId was read from URL params, which don't contain
    workflowId in the mothership route. Fall back to activeWorkflowId from
    the workflow registry.
    
    * fix(blocks): narrow currentWorkflowId to string to satisfy strict null checks
    waleedlatif1 authored Apr 18, 2026
    Configuration menu
    Copy the full SHA
    28b4c4c View commit details
    Browse the repository at this point in the history
  4. improvement(billing): route scope by subscription referenceId, sync p…

    …lan from Stripe, transfer storage on org join, outbox service (#4219)
    
    * fix(billing): route scope by subscription referenceId, sync plan from Stripe, transfer storage on org join
    
    Route every billing decision (usage limits, credits, storage, rate
    limit, threshold billing, webhooks, UI permissions) through the
    subscription's `referenceId` instead of plan-name heuristics. Fixes
    the production state where a `pro_6000` subscription attached to an
    organization was treated as personal Pro by display/edit code while
    execution correctly enforced the org cap.
    
    Scope
    - Add `isOrgScopedSubscription(sub, userId)` (pure) and
      `isSubscriptionOrgScoped(sub)` (async DB-backed) helpers. One is
      used wherever a user perspective is available; the other in webhook
      handlers that only have a subscription row.
    - Replace plan-name scope checks in ~20 files: usage/limit readers,
      credits balance + purchase, threshold billing, storage limits +
      tracking, rate limiter, invoice + subscription webhooks, seat
      management, membership join/leave, `switch-plan` admin gate,
      admin credits/billing routes, copilot 402 handler, UI subscription
      settings + permissions + sidebar indicator, React Query types.
    
    Plan sync
    - Add `syncSubscriptionPlan(subscriptionId, currentPlan, planFromStripe)`
      called from `onSubscriptionComplete` and `onSubscriptionUpdate` so
      the DB `plan` column heals on every Stripe event. Pro->Team upgrades
      previously updated price, seats, and referenceId but left `plan`
      stale — this is what produced the `pro_6000`-on-org row.
    
    Priority + grace period
    - `getHighestPrioritySubscription` now prefers org over personal
      within each tier (Enterprise > Team > Pro, org > personal at each).
      A user with a `cancelAtPeriodEnd` personal Pro who joins a paid org
      routes pooled resources to the org through the grace window.
    - `calculateSubscriptionOverage` personal-Pro branch reads user_stats
      directly (bypassing priority) and bills only `proPeriodCostSnapshot`
      when the user joined a paid org mid-cycle, so post-join org usage
      isn't double-charged on the personal Pro's final invoice.
      `resetUsageForSubscription` mirrors this: preserves
      `currentPeriodCost` / `currentPeriodCopilotCost` when
      `proPeriodCostSnapshot > 0` so the org's next cycle-close captures
      post-join usage correctly.
    
    Uniform base-price formula
    - `basePrice × (seats ?? 1)` everywhere: `getOrgUsageLimit`,
      `updateOrganizationUsageLimit`, `setUsageLimitForCredits`,
      `calculateSubscriptionOverage`, threshold billing,
      `syncSubscriptionUsageLimits`, `getOrganizationBillingData`.
      Admin dashboard math now agrees with enforcement math.
    
    Storage transfer on join
    - Invitation-accept flow moves `user_stats.storageUsedBytes` into
      `organization.storageUsedBytes` inside the same transaction when
      the org is paid.
    - `syncSubscriptionUsageLimits` runs a bulk-backfill version so
      members who joined before this fix, or orgs that upgraded from
      free to paid after members joined, get pulled into the org pool
      on the next subscription event. Idempotent.
    
    UX polish
    - Copilot 402 handler differentiates personal-scoped ("increase your
      usage limit") from org-scoped ("ask an owner or admin to raise the
      limit") while keeping the `increase_limit` action code the parser
      already understands.
    - Duplicate-subscription error on team upgrade names the existing
      plan via `getDisplayPlanName`.
    - Invitation-accept invalidates subscription + organization React
      Query caches before redirect so settings doesn't flash the user's
      pre-join personal view.
    
    Dead code removal
    - Remove unused `calculateUserOverage`, and the following fields on
      `SubscriptionBillingData` / `getSimplifiedBillingSummary` that no
      consumer in the monorepo read: `basePrice`, `overageAmount`,
      `totalProjected`, `tierCredits`, `basePriceCredits`,
      `currentUsageCredits`, `overageAmountCredits`, `totalProjectedCredits`,
      `usageLimitCredits`, `currentCredits`, `limitCredits`,
      `lastPeriodCostCredits`, `lastPeriodCopilotCostCredits`,
      `copilotCostCredits`, and the `organizationData` subobject. Add
      `metadata: unknown` to match what the server returns.
    
    Notes for the triggering customer
    - The `pro_6000`-on-org row self-heals on the next Stripe event via
      `syncSubscriptionPlan`. For the one known customer, a direct
      UPDATE is sufficient:
      `UPDATE subscription SET plan='team_6000' WHERE id='aq2...' AND plan='pro_6000'`.
    
    Made-with: Cursor
    
    * fix tests
    
    * address more comments
    
    * progress
    
    * harden further
    
    * outbox service
    
    * address comments
    
    * address comment on check
    
    * simplify
    
    * cleanup code
    
    * minor improvement
    icecrasher321 authored Apr 18, 2026
    Configuration menu
    Copy the full SHA
    c246f5c View commit details
    Browse the repository at this point in the history
  5. fix(ui): stop scrolling on leaving workflow sidebar for drag-drop (#4139

    )
    
    * fix(ui): stop scrolling on leaving workflow sidebar for drag-drop
    
    * Address comments, fix hover state
    
    * address comments
    TheodoreSpeaks authored Apr 18, 2026
    Configuration menu
    Copy the full SHA
    c191872 View commit details
    Browse the repository at this point in the history
Loading