Skip to content

Commit f30a38f

Browse files
authored
fix: fix columns width on long rowset (#1384)
1 parent e63d22b commit f30a38f

File tree

4 files changed

+72
-22
lines changed

4 files changed

+72
-22
lines changed

src/components/QueryResultTable/QueryResultTable.tsx

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {ResizeableDataTable} from '../ResizeableDataTable/ResizeableDataTable';
1313

1414
import {Cell} from './Cell';
1515
import i18n from './i18n';
16+
import {getColumnWidth} from './utils/getColumnWidth';
1617

1718
import './QueryResultTable.scss';
1819

@@ -21,30 +22,27 @@ const TABLE_SETTINGS: Settings = {
2122
stripedRows: true,
2223
dynamicRenderType: 'variable',
2324
dynamicItemSizeGetter: () => 40,
25+
sortable: false,
2426
};
2527

2628
export const b = cn('ydb-query-result-table');
2729

28-
const prepareTypedColumns = (columns: ColumnType[]) => {
30+
const WIDTH_PREDICTION_ROWS_COUNT = 100;
31+
32+
const prepareTypedColumns = (columns: ColumnType[], data?: KeyValueRow[]) => {
2933
if (!columns.length) {
3034
return [];
3135
}
3236

37+
const dataSlice = data?.slice(0, WIDTH_PREDICTION_ROWS_COUNT);
38+
3339
return columns.map(({name, type}) => {
3440
const columnType = getColumnType(type);
3541

3642
const column: Column<KeyValueRow> = {
3743
name,
44+
width: getColumnWidth({data: dataSlice, name}),
3845
align: columnType === 'number' ? DataTable.RIGHT : DataTable.LEFT,
39-
sortAccessor: (row) => {
40-
const value = row[name];
41-
42-
if (value === undefined || value === null) {
43-
return null;
44-
}
45-
46-
return columnType === 'number' ? BigInt(value) : value;
47-
},
4846
render: ({row}) => <Cell value={String(row[name])} />,
4947
};
5048

@@ -57,11 +55,13 @@ const prepareGenericColumns = (data: KeyValueRow[]) => {
5755
return [];
5856
}
5957

58+
const dataSlice = data?.slice(0, WIDTH_PREDICTION_ROWS_COUNT);
59+
6060
return Object.keys(data[0]).map((name) => {
6161
const column: Column<KeyValueRow> = {
6262
name,
63+
width: getColumnWidth({data: dataSlice, name}),
6364
align: isNumeric(data[0][name]) ? DataTable.RIGHT : DataTable.LEFT,
64-
sortAccessor: (row) => (isNumeric(row[name]) ? Number(row[name]) : row[name]),
6565
render: ({row}) => <Cell value={String(row[name])} />,
6666
};
6767

@@ -78,19 +78,12 @@ interface QueryResultTableProps
7878
}
7979

8080
export const QueryResultTable = (props: QueryResultTableProps) => {
81-
const {columns: rawColumns, data: rawData, settings: settingsMix, ...restProps} = props;
81+
const {columns: rawColumns, data: rawData, ...restProps} = props;
8282

8383
const data = React.useMemo(() => prepareQueryResponse(rawData), [rawData]);
8484
const columns = React.useMemo(() => {
85-
return rawColumns ? prepareTypedColumns(rawColumns) : prepareGenericColumns(data);
85+
return rawColumns ? prepareTypedColumns(rawColumns, data) : prepareGenericColumns(data);
8686
}, [data, rawColumns]);
87-
const settings = React.useMemo(
88-
() => ({
89-
...TABLE_SETTINGS,
90-
...settingsMix,
91-
}),
92-
[settingsMix],
93-
);
9487

9588
// empty data is expected to be be an empty array
9689
// undefined data is not rendered at all
@@ -106,7 +99,7 @@ export const QueryResultTable = (props: QueryResultTableProps) => {
10699
<ResizeableDataTable
107100
data={data}
108101
columns={columns}
109-
settings={settings}
102+
settings={TABLE_SETTINGS}
110103
// prevent accessing row.id in case it is present but is not the PK (i.e. may repeat)
111104
rowKey={getRowIndex}
112105
{...restProps}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import {HEADER_PADDING, MAX_COLUMN_WIDTH, getColumnWidth} from './getColumnWidth';
2+
3+
describe('getColumnWidth', () => {
4+
it('returns minimum width for empty data', () => {
5+
const result = getColumnWidth({data: [], name: 'test'});
6+
expect(result).toBe(HEADER_PADDING + 'test'.length * 10);
7+
});
8+
9+
it('calculates correct width for string columns', () => {
10+
const data = [{test: 'short'}, {test: 'medium length'}, {test: 'this is a longer string'}];
11+
const result = getColumnWidth({data, name: 'test'});
12+
expect(result).toBe(HEADER_PADDING + 'this is a longer string'.length * 10);
13+
});
14+
15+
it('returns MAX_COLUMN_WIDTH when calculated width exceeds it', () => {
16+
const data = [{test: 'a'.repeat(100)}];
17+
const result = getColumnWidth({data, name: 'test'});
18+
expect(result).toBe(MAX_COLUMN_WIDTH);
19+
});
20+
21+
it('handles undefined data correctly', () => {
22+
const result = getColumnWidth({name: 'test'});
23+
expect(result).toBe(HEADER_PADDING + 'test'.length * 10);
24+
});
25+
26+
it('handles missing values in data correctly', () => {
27+
const data = [{test: 'short'}, {}, {test: 'longer string'}];
28+
const result = getColumnWidth({data, name: 'test'});
29+
expect(result).toBe(HEADER_PADDING + 'longer string'.length * 10);
30+
});
31+
32+
it('uses column name length when all values are shorter', () => {
33+
const data = [{longColumnName: 'a'}, {longColumnName: 'bb'}];
34+
const result = getColumnWidth({data, name: 'longColumnName'});
35+
expect(result).toBe(HEADER_PADDING + 'longColumnName'.length * 10);
36+
});
37+
});
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type {KeyValueRow} from '../../../types/api/query';
2+
3+
export const MAX_COLUMN_WIDTH = 600;
4+
export const HEADER_PADDING = 20;
5+
6+
export const getColumnWidth = ({data, name}: {data?: KeyValueRow[]; name: string}) => {
7+
let maxColumnContentLength = name.length;
8+
9+
if (data) {
10+
for (const row of data) {
11+
const cellLength = row[name] ? String(row[name]).length : 0;
12+
maxColumnContentLength = Math.max(maxColumnContentLength, cellLength);
13+
14+
if (maxColumnContentLength * 10 + HEADER_PADDING >= MAX_COLUMN_WIDTH) {
15+
return MAX_COLUMN_WIDTH;
16+
}
17+
}
18+
}
19+
20+
return maxColumnContentLength * 10 + HEADER_PADDING;
21+
};

src/containers/Tenant/Query/ExecuteResult/ExecuteResult.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ export function ExecuteResult({
136136
<QueryResultTable
137137
data={currentResult?.result}
138138
columns={currentResult?.columns}
139-
settings={{sortable: false}}
140139
/>
141140
</div>
142141
</div>

0 commit comments

Comments
 (0)