diff --git a/packages/frontend-core/src/components/grid/lib/utils.js b/packages/frontend-core/src/components/grid/lib/utils.js index b921c39951..1988b66cc2 100644 --- a/packages/frontend-core/src/components/grid/lib/utils.js +++ b/packages/frontend-core/src/components/grid/lib/utils.js @@ -1,17 +1,17 @@ import { helpers } from "@budibase/shared-core" import { TypeIconMap } from "../../../constants" -// we can't use "-" for joining the ID/field, as this can be present in the ID or column name -// using something very unusual to avoid this problem +// We can't use "-" as a separator as this can be present in the ID +// or column name, so we use something very unusual to avoid this problem const JOINING_CHARACTER = "‽‽" export const parseCellID = cellId => { if (!cellId) { - return { id: undefined, field: undefined } + return { rowId: undefined, field: undefined } } const parts = cellId.split(JOINING_CHARACTER) const field = parts.pop() - return { id: parts.join(JOINING_CHARACTER), field } + return { rowId: parts.join(JOINING_CHARACTER), field } } export const getCellID = (rowId, fieldName) => { diff --git a/packages/frontend-core/src/components/grid/overlays/KeyboardManager.svelte b/packages/frontend-core/src/components/grid/overlays/KeyboardManager.svelte index 0662fdf6a1..98b4d6df25 100644 --- a/packages/frontend-core/src/components/grid/overlays/KeyboardManager.svelte +++ b/packages/frontend-core/src/components/grid/overlays/KeyboardManager.svelte @@ -158,7 +158,7 @@ return } const cols = $visibleColumns - const { id, field: columnName } = parseCellID($focusedCellId) + const { rowId, field: columnName } = parseCellID($focusedCellId) let newColumnName if (columnName === $stickyColumn?.name) { const index = delta - 1 @@ -172,7 +172,7 @@ } } if (newColumnName) { - $focusedCellId = getCellID(id, newColumnName) + $focusedCellId = getCellID(rowId, newColumnName) } } @@ -227,14 +227,6 @@ } } - const toggleSelectRow = () => { - const id = $focusedRow?._id - if (!id || id === NewRowID) { - return - } - selectedRows.actions.toggleRow(id) - } - onMount(() => { document.addEventListener("keydown", handleKeyDown) return () => { diff --git a/packages/frontend-core/src/components/grid/stores/clipboard.js b/packages/frontend-core/src/components/grid/stores/clipboard.js index 2c779c855d..793abc9ad8 100644 --- a/packages/frontend-core/src/components/grid/stores/clipboard.js +++ b/packages/frontend-core/src/components/grid/stores/clipboard.js @@ -88,11 +88,11 @@ export const createActions = context => { for (let row of $selectedCells) { const rowValues = [] for (let cellId of row) { - const { id, field } = parseCellID(cellId) - const rowIndex = $rowLookupMap[id] + const { rowId, field } = parseCellID(cellId) + const rowIndex = $rowLookupMap[rowId] const row = { ...$rows[rowIndex], - ...$rowChangeCache[id], + ...$rowChangeCache[rowId], } rowValues.push(row[field]) } @@ -134,15 +134,32 @@ export const createActions = context => { if (multiCellCopy) { if (multiCellPaste) { // Multi to multi - try pasting into all selected cells - await pasteIntoSelectedCells(value) + let newValue = value + + // If we are pasting into more rows than we copied, but the number of + // columns match, then repeat the copied values as required + const $selectedCells = get(selectedCells) + const selectedRows = $selectedCells.length + const selectedColumns = $selectedCells[0].length + const copiedRows = value.length + const copiedColumns = value[0].length + if (selectedRows > copiedRows && selectedColumns === copiedColumns) { + newValue = [] + for (let i = 0; i < selectedRows; i++) { + newValue.push(value[i % copiedRows]) + } + } + + // Paste the new value + await pasteIntoSelectedCells(newValue) } else { // Multi to single - expand to paste all values // Get indices of focused cell const $focusedCellId = get(focusedCellId) - const { id, field } = parseCellID($focusedCellId) + const { rowId, field } = parseCellID($focusedCellId) const $rowLookupMap = get(rowLookupMap) const $columnLookupMap = get(columnLookupMap) - const rowIdx = $rowLookupMap[id] + const rowIdx = $rowLookupMap[rowId] const colIdx = $columnLookupMap[field] // Get limits of how many rows and columns we're able to paste into @@ -195,11 +212,11 @@ export const createActions = context => { for (let rowIdx = 0; rowIdx < rowExtent; rowIdx++) { for (let colIdx = 0; colIdx < colExtent; colIdx++) { const cellId = $selectedCells[rowIdx][colIdx] - const { id, field } = parseCellID(cellId) - if (!changeMap[id]) { - changeMap[id] = {} + const { rowId, field } = parseCellID(cellId) + if (!changeMap[rowId]) { + changeMap[rowId] = {} } - changeMap[id][field] = value[rowIdx][colIdx] + changeMap[rowId][field] = value[rowIdx][colIdx] } } await rows.actions.bulkUpdate(changeMap) diff --git a/packages/frontend-core/src/components/grid/stores/menu.js b/packages/frontend-core/src/components/grid/stores/menu.js index d9e45b19a1..22bf26fff5 100644 --- a/packages/frontend-core/src/components/grid/stores/menu.js +++ b/packages/frontend-core/src/components/grid/stores/menu.js @@ -43,7 +43,7 @@ export const createActions = context => { // Check if there are multiple rows selected, and if this is one of them let multiRowMode = false if (get(selectedRowCount) > 1) { - const rowId = parseCellID(cellId).id + const { rowId } = parseCellID(cellId) if (get(selectedRows)[rowId]) { multiRowMode = true } diff --git a/packages/frontend-core/src/components/grid/stores/rows.js b/packages/frontend-core/src/components/grid/stores/rows.js index f78a57fe1c..ad8024b403 100644 --- a/packages/frontend-core/src/components/grid/stores/rows.js +++ b/packages/frontend-core/src/components/grid/stores/rows.js @@ -711,7 +711,7 @@ export const initialise = context => { if (!id) { return } - const { id: rowId, field } = parseCellID(id) + const { rowId, field } = parseCellID(id) const hasChanges = field in (get(rowChangeCache)[rowId] || {}) const hasErrors = validation.actions.rowHasErrors(rowId) const isSavingChanges = get(inProgressChanges)[rowId] diff --git a/packages/frontend-core/src/components/grid/stores/ui.js b/packages/frontend-core/src/components/grid/stores/ui.js index 10a17a372a..be56fd8538 100644 --- a/packages/frontend-core/src/components/grid/stores/ui.js +++ b/packages/frontend-core/src/components/grid/stores/ui.js @@ -60,7 +60,7 @@ export const deriveStores = context => { // Derive the current focused row ID const focusedRowId = derived(focusedCellId, $focusedCellId => { - return parseCellID($focusedCellId)?.id + return parseCellID($focusedCellId).rowId }) // Derive the row that contains the selected cell @@ -119,8 +119,8 @@ export const deriveStores = context => { const targetInfo = parseCellID(targetCellId) // Row indices - const sourceRowIndex = $rowLookupMap[sourceInfo.id] - const targetRowIndex = $rowLookupMap[targetInfo.id] + const sourceRowIndex = $rowLookupMap[sourceInfo.rowId] + const targetRowIndex = $rowLookupMap[targetInfo.rowId] const lowerRowIndex = Math.min(sourceRowIndex, targetRowIndex) const upperRowIndex = Math.max(sourceRowIndex, targetRowIndex) @@ -331,7 +331,7 @@ export const initialise = context => { const hasRow = rows.actions.hasRow // Check selected cell - const selectedRowId = parseCellID($focusedCellId)?.id + const selectedRowId = parseCellID($focusedCellId).rowId if (selectedRowId && !hasRow(selectedRowId)) { focusedCellId.set(null) } diff --git a/packages/frontend-core/src/components/grid/stores/validation.js b/packages/frontend-core/src/components/grid/stores/validation.js index 6dd98ffff9..93e67e1d31 100644 --- a/packages/frontend-core/src/components/grid/stores/validation.js +++ b/packages/frontend-core/src/components/grid/stores/validation.js @@ -21,7 +21,7 @@ export const deriveStores = context => { Object.entries($validation).forEach(([key, error]) => { // Extract row ID from all errored cell IDs if (error) { - const rowId = parseCellID(key).id + const { rowId } = parseCellID(key) if (!map[rowId]) { map[rowId] = [] }