Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/

import { createContext } from 'react';
import type { IGridReactiveValue } from './IGridReactiveValue.js';
import type { DataGridCellKeyboardEvent } from './DataGrid.js';

export interface IDataGridHeaderCellContext {
headerElement?: IGridReactiveValue<React.ReactNode, [colIdx: number]>;
Expand All @@ -23,7 +24,7 @@ export interface IDataGridHeaderCellContext {
columnSortable?: IGridReactiveValue<boolean, [colIdx: number]>;
columnSortingMultiple?: boolean;
onColumnSort?: (colIdx: number, order: 'asc' | 'desc' | null, isMultiple: boolean) => void;
onHeaderKeyDown?: (event: React.KeyboardEvent) => void;
onHeaderKeyDown?: (event: DataGridCellKeyboardEvent) => void;
}

export const DataGridCellHeaderContext = createContext<IDataGridHeaderCellContext | null>(null);
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import { useGridReactiveValue } from '../useGridReactiveValue.js';
import { HeaderDnDContext } from '../useHeaderDnD.js';
import { OrderButton } from './OrderButton.js';
import type { DataGridCellKeyboardEvent } from '../DataGrid.js';

interface Props {
colIdx: number;
Expand Down Expand Up @@ -67,11 +68,11 @@
return;
}

const nextSortState = sortingState === 'asc' ? 'desc' : sortingState === 'desc' ? null : 'asc';

Check warning on line 71 in webapp/common-react/@dbeaver/react-data-grid/src/renderers/HeaderCellContentRenderer.tsx

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Do not nest ternary expressions
onColumnSort(colIdx, nextSortState, e.ctrlKey || e.metaKey);
}

function onKeyDown(event: React.KeyboardEvent<HTMLElement>) {
function onKeyDown(event: DataGridCellKeyboardEvent) {
onHeaderKeyDown?.(event);

if ((event.key === 'Enter' || event.key === ' ') && isColumnSortable && onColumnSort) {
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/plugin-data-grid/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export {
type IGridReactiveValue,
type DataGridRef,
type ICellPosition,
type DataGridCellKeyboardEvent,
type ICellChange,
type IDataGridRowRenderer,
type IDataGridCellRenderer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,7 @@ export class DataGridContextMenuCellEditingService {
actions.edit(key);
break;
case ACTION_DATA_GRID_EDITING_SET_TO_NULL:
for (const element of selectedElements) {
// TODO wait for search merge to implement setMany here in order to have batched changes for undo/redo
editor.set(element, null);
}
editor.setMany(selectedElements.map(key => ({ key, value: null })));
break;
case ACTION_DATA_GRID_EDITING_ADD_ROW:
editor.add(...selectedElements);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
type IDataGridCellRenderer,
type DataGridProps,
type ICellChange,
type DataGridCellKeyboardEvent,
} from '@cloudbeaver/plugin-data-grid';
import {
DATA_CONTEXT_DV_PRESENTATION,
Expand All @@ -33,6 +34,7 @@ import {
isBooleanValuePresentationAvailable,
GridDataKeysUtils,
ResultSetDataSource,
ResultSetSelectAction,
getNextOrder,
isResultSetDataModel,
isResultSetDataSource,
Expand Down Expand Up @@ -62,6 +64,7 @@ import { TableDataContext } from './TableDataContext.js';
import { useGridDragging } from './useGridDragging.js';
import { useFormatting } from './useFormatting.js';
import { useGridSelectedCellsCopy } from './useGridSelectedCellsCopy.js';
import { useGridSelectedCellsPaste } from './useGridSelectedCellsPaste.js';
import { useSearchResultsCache } from './useSearchResultsCache.js';
import { useTableData } from './useTableData.js';
import { TableColumnHeader } from './TableColumnHeader/TableColumnHeader.js';
Expand Down Expand Up @@ -185,6 +188,7 @@ export const DataGridTable = observer<IDataPresentationProps>(function DataGridT
}));

const gridSelectedCellCopy = useGridSelectedCellsCopy(tableData, selectionAction as unknown as DatabaseSelectAction, gridSelectionContext);
const gridSelectedCellPaste = useGridSelectedCellsPaste(tableData, selectionAction as unknown as ResultSetSelectAction);
const { onMouseDownHandler, onMouseMoveHandler } = useGridDragging({
onDragStart: startPosition => {
handlers.selectCell(startPosition);
Expand Down Expand Up @@ -559,7 +563,8 @@ export const DataGridTable = observer<IDataPresentationProps>(function DataGridT
}

const handleCellKeyDown: DataGridProps['onCellKeyDown'] = (_, event) => {
gridSelectedCellCopy.onKeydownHandler(event);
handleCopyPaste(event);

const cell = selectionAction.getFocusedElement();

if (EventContext.has(event, EventStopPropagationFlag) || model.isReadonly(resultIndex) || !cell) {
Expand All @@ -574,6 +579,15 @@ export const DataGridTable = observer<IDataPresentationProps>(function DataGridT
}
};

function handleCopyPaste(event: DataGridCellKeyboardEvent) {
const readonly = model.isReadonly(resultIndex);
gridSelectedCellCopy.onKeydownHandler(event);

if (!readonly) {
gridSelectedCellPaste.onKeydownHandler(event);
}
}

return (
<ColumnDnDContext.Provider value={columnDnDState}>
<DataGridContext.Provider value={gridContext}>
Expand Down Expand Up @@ -621,7 +635,7 @@ export const DataGridTable = observer<IDataPresentationProps>(function DataGridT
onCellChange={handleCellChange}
onCellChangeBatch={handleCellChangeBatch}
onCellKeyDown={handleCellKeyDown}
onHeaderKeyDown={gridSelectedCellCopy.onKeydownHandler}
onHeaderKeyDown={handleCopyPaste}
/>
</div>
</FormattingContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -66,7 +66,7 @@
return rowsValues.join('\r\n');
}

export function useGridSelectedCellsCopy(

Check warning on line 69 in webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useGridSelectedCellsCopy.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Missing return type on function
tableData: ITableData,
selectAction: DatabaseSelectAction | undefined,
selectionContext: IDataGridSelectionContext,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { useCallback } from 'react';
import { useService } from '@cloudbeaver/core-di';
import { EventContext, EventStopPropagationFlag } from '@cloudbeaver/core-events';
import type { DataGridCellKeyboardEvent } from '@cloudbeaver/plugin-data-grid';
import { ResultSetSelectAction } from '@cloudbeaver/plugin-data-viewer';

import type { ITableData } from './TableDataContext.js';
import { ClipboardService } from '@cloudbeaver/core-ui';

const EVENT_KEY_CODE = {
V: 'KeyV',
};

export function useGridSelectedCellsPaste(
tableData: ITableData,
selectAction: ResultSetSelectAction | undefined,
): { onKeydownHandler: (event: DataGridCellKeyboardEvent) => void } {
const clipboardService = useService(ClipboardService);

const onKeydownHandler = useCallback(
async (event: DataGridCellKeyboardEvent) => {
const isPasteShortcut = (event.ctrlKey || event.metaKey) && event.nativeEvent.code === EVENT_KEY_CODE.V;
const selectedCells = selectAction?.getActiveElements();

if (!isPasteShortcut) {
return;
}

EventContext.set(event, EventStopPropagationFlag);
event.preventDefault();
event?.preventGridDefault?.();

if (!selectedCells?.length || !tableData.editor) {
return;
}

const clipboardText = await clipboardService.read();
const updates = selectedCells.filter(key => !tableData.isCellReadonly(key)).map(key => ({ key, value: clipboardText }));

if (updates.length > 0) {
tableData.editor.setMany(updates);
}
},
[tableData, selectAction, clipboardService],
);

return { onKeydownHandler };
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 DBeaver Corp and others
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
Expand Down
Loading