Skip to content

feat(datagrid): paste cells from clipboard (Cmd/Ctrl+V) - #612

Open
ymadd wants to merge 2 commits into
TabularisDB:mainfrom
ymadd:feat/datagrid-paste
Open

feat(datagrid): paste cells from clipboard (Cmd/Ctrl+V)#612
ymadd wants to merge 2 commits into
TabularisDB:mainfrom
ymadd:feat/datagrid-paste

Conversation

@ymadd

@ymadd ymadd commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Closes #611

Summary

The data grid supports copying cells/rows/ranges but not pasting. This PR adds spreadsheet-style paste as staged edits — pasted values go through the existing pending-changes flow (apply/rollback), never directly to the database.

Behavior

  • Cmd/Ctrl+V pastes at the selection, in priority order: cell range top-left → right-clicked cell (context-menu "Paste") → top of row selection → focused cell.
  • Parsing: tab-separated cells win (spreadsheet convention). Multi-line text without tabs is parsed as CSV with double-quote escaping, preferring the configured CSV delimiter — so the grid's own copy formats (comma/semicolon/pipe) round-trip. A single line without tabs is always one value, so free text like hello, world lands in one cell.
  • A leading header row is dropped only when it matches the grid's column names positionally from the paste anchor (round-trips the "export column names" option without swallowing external data that merely mentions column names).
  • A single copied value fills the whole selected range / selected rows.
  • The matrix is clipped at the grid edges. Existing rows require an identifiable row key (keyless grids: only pending-insertion rows accept a paste). Aliases and computed result columns are skipped — same guard as inline editing.
  • Pasting a cell's original value back clears its pending change, same as inline editing.

Prerequisite fix (first commit)

handlePendingChange / handlePendingInsertionChange computed the next pending state from a tabsRef snapshot; with N staged cells in one tick, React batches the updates and only the last cell survived. updateTab now also accepts an updater function and both handlers compute inside it. Multi-cell paste is the first caller that hits this, but it hardens every rapid-succession staging path.

Known limitations

  • The grid's CSV copy output does not quote embedded delimiters/newlines (rowToCSV), so values containing the delimiter don't survive a copy→paste round-trip. Robust CSV serialization is follow-up material.
  • Cells containing quoted newlines (Excel multi-line cells) are split on the newline before quote handling.
  • A single-line, no-tab copy of one row (headers off) pastes as one value by design — single-line splitting can't be distinguished from free text with commas.
  • NULL copies as the literal string null, so pasting it into another cell stages that string, not SQL NULL.
  • Rows are not auto-created on overflow: pasting more rows than exist below the anchor clips at the last row (add pending-insertion rows first).

Testing

  • tests/utils/dataGrid.test.ts: 23 new cases for parsePasteMatrix / stripHeaderRow / computePasteTargets (TSV/CSV/quotes/delimiter detection/positional header stripping/range fill/clipping).
  • Manually verified against a MySQL database: range/row/single-cell paste, single-value fill, header round-trip, alias-column skip, keyless fallback, toast counts.
  • tsc --noEmit, eslint, and the vitest suite are green (the 3 failing files on main — ThemeProvider/SettingsProvider/useSidebarResize — fail identically without this change).

i18n

3 new keys (pasteCells, pastedCells, pasteNotEditable) added to all 11 locales.

ymadd added 2 commits August 6, 2026 02:33
handlePendingChange / handlePendingInsertionChange computed the next
pending state from a tabsRef snapshot taken before the update. When many
cells are staged in the same tick (e.g. a multi-cell clipboard paste),
every call reads the same stale snapshot and React batches the setState
calls, so only the last cell's change survives.

updateTab now also accepts an updater function ((tab) => partial) and
both handlers compute the next pending state inside it, so rapid
successive updates compose instead of clobbering each other.
Copying cells has been supported for a while, but there was no way to
paste back into the grid. This adds spreadsheet-style paste as staged
edits (pending changes), applied via the existing commit/rollback flow:

- Cmd/Ctrl+V pastes at the selection: the cell range's top-left, the
  top of the row selection, or the focused cell. A context-menu Paste
  entry pastes at the right-clicked cell.
- Tab-separated cells win (spreadsheet convention). Multi-line text
  without tabs is parsed as CSV with double-quote escaping, preferring
  the configured CSV delimiter, so the grid's own copy formats
  (comma/semicolon/pipe) round-trip. A single line without tabs is
  always one value, so free text like "hello, world" lands in one cell.
- A leading header row is dropped when every cell matches a column name
  (round-trip of the "export column names" option).
- A single copied value fills the whole selected range / selected rows.
- The paste matrix is clipped at the grid edges; existing rows require
  an identifiable key (insertion rows accept a paste regardless).
- Pasting a cell's original value back clears its pending change, same
  as inline editing.
@kilo-code-bot

kilo-code-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (18 files)
  • src/components/ui/DataGrid.tsx
  • src/contexts/EditorContext.ts
  • src/contexts/EditorProvider.tsx
  • src/i18n/locales/de.json
  • src/i18n/locales/en.json
  • src/i18n/locales/es.json
  • src/i18n/locales/fr.json
  • src/i18n/locales/it.json
  • src/i18n/locales/ja.json
  • src/i18n/locales/ko.json
  • src/i18n/locales/pt-BR.json
  • src/i18n/locales/ru.json
  • src/i18n/locales/tl.json
  • src/i18n/locales/zh.json
  • src/pages/Editor.tsx
  • src/utils/dataGrid.ts
  • src/utils/editor.ts
  • tests/utils/dataGrid.test.ts

Reviewed by step-3.7-flash · Input: 194.2K · Output: 30.3K · Cached: 2.4M

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat]: Paste cells from clipboard into the data grid

1 participant