-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathQueryResultTable.tsx
118 lines (93 loc) · 3.52 KB
/
QueryResultTable.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import React from 'react';
import DataTable from '@gravity-ui/react-data-table';
import type {Column, Settings} from '@gravity-ui/react-data-table';
import type {ColumnType, KeyValueRow} from '../../types/api/query';
import {cn} from '../../utils/cn';
import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
import {getColumnWidth} from '../../utils/getColumnWidth';
import {getColumnType} from '../../utils/query';
import {isNumeric} from '../../utils/utils';
import type {ResizeableDataTableProps} from '../ResizeableDataTable/ResizeableDataTable';
import {ResizeableDataTable} from '../ResizeableDataTable/ResizeableDataTable';
import {Cell} from './Cell';
import i18n from './i18n';
import './QueryResultTable.scss';
const TABLE_SETTINGS: Settings = {
...DEFAULT_TABLE_SETTINGS,
stripedRows: true,
sortable: false,
displayIndices: true,
};
export const b = cn('ydb-query-result-table');
const WIDTH_PREDICTION_ROWS_COUNT = 100;
const prepareTypedColumns = (columns: ColumnType[], data?: KeyValueRow[]) => {
if (!columns.length) {
return [];
}
const dataSlice = data?.slice(0, WIDTH_PREDICTION_ROWS_COUNT);
return columns.map(({name, type}) => {
const columnType = getColumnType(type);
const column: Column<KeyValueRow> = {
name,
width: getColumnWidth({data: dataSlice, name}),
align: columnType === 'number' ? DataTable.RIGHT : DataTable.LEFT,
render: ({row}) => <Cell value={String(row[name])} />,
};
return column;
});
};
const prepareGenericColumns = (data?: KeyValueRow[]) => {
if (!data?.length) {
return [];
}
const dataSlice = data?.slice(0, WIDTH_PREDICTION_ROWS_COUNT);
return Object.keys(data[0]).map((name) => {
const column: Column<KeyValueRow> = {
name,
width: getColumnWidth({data: dataSlice, name}),
align: isNumeric(data[0][name]) ? DataTable.RIGHT : DataTable.LEFT,
render: ({row}) => <Cell value={String(row[name])} />,
};
return column;
});
};
const getRowIndex = (_: unknown, index: number) => index;
// Display row number in format 1-10 instead of 0-9
const getVisibleRowIndex = (_: unknown, index: number) => index + 1;
interface QueryResultTableProps
extends Omit<ResizeableDataTableProps<KeyValueRow>, 'data' | 'columns'> {
data?: KeyValueRow[];
columns?: ColumnType[];
settings?: Partial<Settings>;
}
export const QueryResultTable = (props: QueryResultTableProps) => {
const {columns, data, settings: propsSettings} = props;
const preparedColumns = React.useMemo(() => {
return columns ? prepareTypedColumns(columns, data) : prepareGenericColumns(data);
}, [data, columns]);
const settings = React.useMemo(() => {
return {
...TABLE_SETTINGS,
...propsSettings,
};
}, [propsSettings]);
// empty data is expected to be be an empty array
// undefined data is not rendered at all
if (!Array.isArray(data)) {
return null;
}
if (!preparedColumns.length) {
return <div className={b('message')}>{i18n('empty')}</div>;
}
return (
<ResizeableDataTable
data={data}
columns={preparedColumns}
settings={settings}
// prevent accessing row.id in case it is present but is not the PK (i.e. may repeat)
rowKey={getRowIndex}
visibleRowIndex={getVisibleRowIndex}
wrapperClassName={b('table-wrapper')}
/>
);
};