Skip to content

Commit 275e787

Browse files
dbeaver/pro#7554 adds tooltip for multi sorting in data grid
1 parent 24b7b60 commit 275e787

12 files changed

Lines changed: 51 additions & 25 deletions

File tree

webapp/common-react/@dbeaver/react-data-grid/src/DataGrid.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
7272
getHeaderPinned,
7373
columnSortingState,
7474
getHeaderDnD,
75+
orderButtonTitle,
7576
cell,
7677
cellText,
7778
cellElement,
@@ -187,7 +188,16 @@ export const DataGrid = forwardRef<DataGridRef, DataGridProps>(function DataGrid
187188
<DataGridRowContext value={{ rowElement, rowCount, onScrollToBottom }}>
188189
<DataGridCellContext value={{ cell, cellText, cellElement, cellTooltip, onCellChange }}>
189190
<DataGridCellHeaderContext
190-
value={{ headerElement, headerText, getHeaderDnD, columnSortable, onColumnSort, columnSortingState, onHeaderKeyDown }}
191+
value={{
192+
headerElement,
193+
headerText,
194+
getHeaderDnD,
195+
columnSortable,
196+
onColumnSort,
197+
columnSortingState,
198+
onHeaderKeyDown,
199+
orderButtonTitle,
200+
}}
191201
>
192202
<DataGridBase
193203
ref={innerGridRef}

webapp/common-react/@dbeaver/react-data-grid/src/DataGridHeaderCellContext.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
/*
2+
* CloudBeaver - Cloud Database Manager
3+
* Copyright (C) 2020-2025 DBeaver Corp and others
4+
*
5+
* Licensed under the Apache License, Version 2.0.
6+
* you may not use this file except in compliance with the License.
7+
*/
8+
19
import { createContext } from 'react';
210
import type { IGridReactiveValue } from './IGridReactiveValue.js';
311

@@ -15,6 +23,7 @@ export interface IDataGridHeaderCellContext {
1523
columnSortable?: IGridReactiveValue<boolean, [colIdx: number]>;
1624
onColumnSort?: (colIdx: number, order: 'asc' | 'desc' | null, isMultiple: boolean) => void;
1725
onHeaderKeyDown?: (event: React.KeyboardEvent) => void;
26+
orderButtonTitle?: string;
1827
}
1928

2029
export const DataGridCellHeaderContext = createContext<IDataGridHeaderCellContext | null>(null);

webapp/common-react/@dbeaver/react-data-grid/src/renderers/HeaderCellContentRenderer.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const HeaderCellContentRenderer = memo(function HeaderCellContentRenderer
2727
const onColumnSort = cellHeaderContext?.onColumnSort;
2828
const onHeaderKeyDown = cellHeaderContext?.onHeaderKeyDown;
2929
const sortingState = useGridReactiveValue(cellHeaderContext?.columnSortingState, colIdx);
30+
const orderButtonTitle = cellHeaderContext?.orderButtonTitle;
3031

3132
const draggable = dndHeaderContext?.getCanDrag?.(colIdx) ?? false;
3233
const drag = useDrag({
@@ -63,7 +64,9 @@ export const HeaderCellContentRenderer = memo(function HeaderCellContentRenderer
6364
});
6465

6566
function handleSort(e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>) {
66-
if (!onColumnSort) return;
67+
if (!onColumnSort) {
68+
return;
69+
}
6770

6871
const nextSortState = sortingState === 'asc' ? 'desc' : sortingState === 'desc' ? null : 'asc';
6972
onColumnSort(colIdx, nextSortState, e.ctrlKey || e.metaKey);
@@ -87,7 +90,7 @@ export const HeaderCellContentRenderer = memo(function HeaderCellContentRenderer
8790
onKeyDown={onKeyDown}
8891
>
8992
<span className="tw:overflow-hidden tw:text-ellipsis">{headerElement ?? getHeaderText ?? ''}</span>
90-
{isColumnSortable && onColumnSort && <OrderButton sortState={sortingState} onClick={handleSort} />}
93+
{isColumnSortable && onColumnSort && <OrderButton sortState={sortingState} title={orderButtonTitle} onClick={handleSort} />}
9194
</div>
9295
);
9396
});

webapp/common-react/@dbeaver/react-data-grid/src/renderers/OrderButton.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,40 @@
1+
/*
2+
* CloudBeaver - Cloud Database Manager
3+
* Copyright (C) 2020-2025 DBeaver Corp and others
4+
*
5+
* Licensed under the Apache License, Version 2.0.
6+
* you may not use this file except in compliance with the License.
7+
*/
8+
19
import { clsx, IconButton, Icon } from '@dbeaver/ui-kit';
210

311
interface OrderButtonProps {
412
sortState?: 'asc' | 'desc' | null;
513
onClick: (e: React.MouseEvent<HTMLElement>) => void;
614
tabIndex?: number;
15+
title?: string;
716
}
817

9-
export function OrderButton({ sortState, onClick, tabIndex }: OrderButtonProps) {
18+
export function OrderButton({ sortState, onClick, tabIndex, title }: OrderButtonProps) {
1019
const svgSortAsc = 'sort-asc';
1120
const svgSortDesc = 'sort-desc';
1221
const svgSortUnknown = 'sort-unknown';
22+
const tooltip = title || 'Sort by column';
1323

1424
const iconSrc = sortState === 'asc' ? svgSortAsc : sortState === 'desc' ? svgSortDesc : svgSortUnknown;
1525

1626
return (
1727
<IconButton
1828
variant="secondary"
1929
size="small"
20-
onClick={onClick}
2130
tabIndex={tabIndex}
22-
title="Sort by column"
23-
aria-label="Sort by column"
31+
title={tooltip}
32+
aria-label={tooltip}
2433
className={clsx(
2534
'tw:opacity-0 tw:group-focus:opacity-100 tw:focus:opacity-100 tw:group-hover:opacity-100 tw:hover:opacity-100 tw:outline-offset-0',
2635
sortState && 'tw:opacity-100',
2736
)}
37+
onClick={onClick}
2838
>
2939
<Icon name={iconSrc} />
3040
</IconButton>

webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridTable.tsx

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ import { useCallback, useLayoutEffect, useMemo, useRef, type HTMLAttributes } fr
1010
import { reaction } from 'mobx';
1111

1212
import { getComputed, s, TextPlaceholder, useObjectRef, useS, useTranslate } from '@cloudbeaver/core-blocks';
13-
// import { useService } from '@cloudbeaver/core-di';
1413
import { EventContext, EventStopPropagationFlag } from '@cloudbeaver/core-events';
15-
// import { ClipboardService } from '@cloudbeaver/core-ui';
1614
import { useCaptureViewContext } from '@cloudbeaver/core-view';
1715
import {
1816
DataGrid,
@@ -58,20 +56,13 @@ import { useTableData } from './useTableData.js';
5856
import { TableColumnHeader } from './TableColumnHeader/TableColumnHeader.js';
5957
import { TableIndexColumnHeader } from './TableColumnHeader/TableIndexColumnHeader.js';
6058
import { clsx } from '@dbeaver/ui-kit';
59+
import { getOS, OperatingSystem } from '@cloudbeaver/core-utils';
6160

6261
const ROW_HEIGHT = 24;
6362
export const HEADER_HEIGHT = 32;
6463
export const HEADER_WITH_DESC_HEIGHT = 42;
6564

66-
export const DataGridTable = observer<IDataPresentationProps>(function DataGridTable({
67-
model,
68-
actions,
69-
resultIndex,
70-
simple,
71-
className,
72-
dataFormat,
73-
...rest
74-
}) {
65+
export const DataGridTable = observer<IDataPresentationProps>(function DataGridTable({ model, actions, resultIndex, simple, className, ...rest }) {
7566
const translate = useTranslate();
7667
const styles = useS(classes);
7768
const gridContainerRef = useRef<HTMLDivElement | null>(null);
@@ -85,6 +76,8 @@ export const DataGridTable = observer<IDataPresentationProps>(function DataGridT
8576

8677
const tableData = useTableData(model as unknown as IDatabaseDataModel<ResultSetDataSource>, resultIndex, dataGridDivRef);
8778
const gridSelectionContext = useGridSelectionContext(tableData, selectionAction);
79+
const multiSortModifier = getOS() === OperatingSystem.macOS ? '⌘CMD' : 'CTRL';
80+
const orderButtonTitle = translate('data_grid_table_tooltip_column_header_order', undefined, { modifier: multiSortModifier });
8881

8982
const restoreFocus = useCallback(
9083
function restoreFocus() {
@@ -512,6 +505,7 @@ export const DataGridTable = observer<IDataPresentationProps>(function DataGridT
512505
rowCount={rowsCount}
513506
columnSortable={columnSortable}
514507
columnSortingState={columnSortingState}
508+
orderButtonTitle={orderButtonTitle}
515509
getRowId={rowIdx => (tableData.rows[rowIdx] ? GridDataKeysUtils.serialize(tableData.rows[rowIdx]) : '')}
516510
onFocus={handleFocusChange}
517511
onScrollToBottom={handleScrollToBottom}

webapp/packages/plugin-data-spreadsheet-new/src/locales/de.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default [
1212
['data_grid_table_disable_order', 'Deaktiviert'],
1313
['data_grid_table_disable_all_orders', 'Alle deaktivieren'],
1414
['data_grid_table_delete_filters_and_orders', 'Filter / Sortierung zurücksetzen'],
15-
['data_grid_table_tooltip_column_header_order', 'Sortieren nach Spalte'],
15+
['data_grid_table_tooltip_column_header_order', 'Zum Sortieren klicken. Halten Sie {arg:modifier} für Mehrfachsortierung'],
1616
['data_grid_table_context_menu_filter_dialog_title', 'Wert bearbeiten'],
1717
['data_grid_table_index_column_tooltip', 'Wählen ganze Tabelle aus'],
1818
['data_grid_table_readonly_tooltip', 'Schreibgeschützt'],

webapp/packages/plugin-data-spreadsheet-new/src/locales/en.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default [
1616
['data_grid_table_disable_order', 'Disabled'],
1717
['data_grid_table_disable_all_orders', 'Disable all'],
1818
['data_grid_table_delete_filters_and_orders', 'Reset filters / sorting'],
19-
['data_grid_table_tooltip_column_header_order', 'Sort by column'],
19+
['data_grid_table_tooltip_column_header_order', 'Click to sort. Hold {arg:modifier} for multi-sort'],
2020
['data_grid_table_context_menu_filter_dialog_title', 'Edit value'],
2121
['data_grid_table_context_menu_filter_clipboard_permission', 'Give access to clipboard'],
2222
['data_grid_table_context_menu_save_value_error', 'Failed to save value'],

webapp/packages/plugin-data-spreadsheet-new/src/locales/fr.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default [
1616
['data_grid_table_disable_order', 'Désactivé'],
1717
['data_grid_table_disable_all_orders', 'Désactiver tout'],
1818
['data_grid_table_delete_filters_and_orders', 'Réinitialiser les filtres / le tri'],
19-
['data_grid_table_tooltip_column_header_order', 'Trier par colonne'],
19+
['data_grid_table_tooltip_column_header_order', 'Cliquez pour trier. Maintenez {arg:modifier} pour un tri multiple'],
2020
['data_grid_table_context_menu_filter_dialog_title', 'Modifier la valeur'],
2121
['data_grid_table_context_menu_filter_clipboard_permission', 'Donner accès au presse-papiers'],
2222
['data_grid_table_context_menu_save_value_error', 'Échec de la sauvegarde de la valeur'],

webapp/packages/plugin-data-spreadsheet-new/src/locales/it.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default [
1111
['data_grid_table_disable_order', 'Disabilitato'],
1212
['data_grid_table_disable_all_orders', 'Disabilita tutto'],
1313
['data_grid_table_delete_filters_and_orders', "Reimposta i filtri / l'ordinamento"],
14-
['data_grid_table_tooltip_column_header_order', 'Ordina per colonna'],
14+
['data_grid_table_tooltip_column_header_order', 'Fai clic per ordinare. Tieni premuto {arg:modifier} per l\'ordinamento multiplo'],
1515
['data_grid_table_context_menu_filter_dialog_title', 'Modifica valore'],
1616
['data_grid_table_context_menu_filter_clipboard_permission', 'Dai accesso agli appunti'],
1717
['data_grid_table_context_menu_save_value_error', 'Failed to save value'],

webapp/packages/plugin-data-spreadsheet-new/src/locales/ru.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default [
1616
['data_grid_table_disable_order', 'Отключена'],
1717
['data_grid_table_disable_all_orders', 'Отменить сортировку всех колонок'],
1818
['data_grid_table_delete_filters_and_orders', 'Отменить фильтры / сортировки'],
19-
['data_grid_table_tooltip_column_header_order', 'Сортировка по колонке'],
19+
['data_grid_table_tooltip_column_header_order', 'Нажмите для сортировки. Удерживайте {arg:modifier} для множественной сортировки'],
2020
['data_grid_table_context_menu_filter_dialog_title', 'Редактировать значение'],
2121
['data_grid_table_context_menu_filter_clipboard_permission', 'Дать доступ к буферу обмена'],
2222
['data_grid_table_context_menu_save_value_error', 'Не удалось сохранить значение'],

0 commit comments

Comments
 (0)