Skip to content

Commit 81e7e61

Browse files
committed
feat(QueryResultTable): add per-row clipboard copy button to query results
1 parent 7cb2202 commit 81e7e61

1 file changed

Lines changed: 34 additions & 5 deletions

File tree

src/components/QueryResultTable/QueryResultTable.tsx

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22

33
import DataTable from '@gravity-ui/react-data-table';
44
import type {Column, Settings} from '@gravity-ui/react-data-table';
5+
import {ClipboardButton} from '@gravity-ui/uikit';
56

67
import type {ColumnType, KeyValueRow} from '../../types/api/query';
78
import {cn} from '../../utils/cn';
@@ -28,32 +29,49 @@ export const b = cn('ydb-query-result-table');
2829

2930
const WIDTH_PREDICTION_ROWS_COUNT = 100;
3031

32+
//helper function to convert a row to TSV format for copying to clipboard
33+
const rowToTsv = (row: KeyValueRow) =>
34+
Object.values(row)
35+
.map((v) => (typeof v === 'object' ? JSON.stringify(v) : String(v)))
36+
.join('\t');
37+
3138
const prepareTypedColumns = (columns: ColumnType[], data: KeyValueRow[] | undefined) => {
3239
if (!columns.length) {
3340
return [];
3441
}
3542

3643
const dataSlice = data?.slice(0, WIDTH_PREDICTION_ROWS_COUNT);
3744

38-
return columns.map(({name, type}) => {
45+
const dataColumns = columns.map(({name, type}) => {
3946
const columnType = getColumnType(type);
4047

4148
const column: Column<KeyValueRow> = {
4249
name,
4350
width: getColumnWidth({data: dataSlice, name}),
4451
align: columnType === 'number' ? DataTable.RIGHT : DataTable.LEFT,
4552
render: ({row}) => {
46-
const data = row[name];
53+
const rowData = row[name];
4754
const normalizedData =
4855
columnType === 'binary-string' && typeof data === 'string'
49-
? JSON.stringify(data).slice(1, -1)
50-
: String(data);
56+
? JSON.stringify(rowData).slice(1, -1)
57+
: String(rowData);
5158
return <Cell value={normalizedData} />;
5259
},
5360
};
5461

5562
return column;
5663
});
64+
65+
const copyColumn: Column<KeyValueRow> = {
66+
name: 'copy',
67+
header: '',
68+
width: 40,
69+
render: ({row}) => (
70+
<ClipboardButton text={rowToTsv(row)} view="flat-secondary" size="s" title="Copy row" />
71+
),
72+
};
73+
74+
return [...dataColumns, copyColumn];
5775
};
5876

5977
const prepareGenericColumns = (data: KeyValueRow[] | undefined) => {
@@ -63,7 +81,7 @@ const prepareGenericColumns = (data: KeyValueRow[] | undefined) => {
6381

6482
const dataSlice = data?.slice(0, WIDTH_PREDICTION_ROWS_COUNT);
6583

66-
return Object.keys(data[0]).map((name) => {
84+
const dataColumns = Object.keys(data[0]).map((name) => {
6785
const column: Column<KeyValueRow> = {
6886
name,
6987
width: getColumnWidth({data: dataSlice, name}),
@@ -73,6 +91,17 @@ const prepareGenericColumns = (data: KeyValueRow[] | undefined) => {
7391

7492
return column;
7593
});
94+
95+
const copyColumn: Column<KeyValueRow> = {
96+
name: 'copy',
97+
header: '',
98+
width: 40,
99+
render: ({row}) => (
100+
<ClipboardButton text={rowToTsv(row)} view="flat-secondary" size="s" title="Copy row" />
101+
),
102+
};
103+
104+
return [...dataColumns, copyColumn];
76105
};
77106

78107
const getRowIndex = (_: unknown, index: number) => index;

0 commit comments

Comments
 (0)