ydb-embedded-ui 4.31.2 → 4.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/components/CellWithPopover/CellWithPopover.scss +7 -0
  2. package/dist/components/Loader/Loader.tsx +3 -2
  3. package/dist/components/MetricChart/MetricChart.tsx +45 -4
  4. package/dist/components/MetricChart/index.ts +1 -1
  5. package/dist/components/MetricChart/types.ts +3 -0
  6. package/dist/components/VirtualTable/TableHead.tsx +127 -26
  7. package/dist/components/VirtualTable/TableRow.tsx +15 -2
  8. package/dist/components/VirtualTable/VirtualTable.scss +62 -60
  9. package/dist/components/VirtualTable/VirtualTable.tsx +11 -1
  10. package/dist/components/VirtualTable/types.ts +1 -0
  11. package/dist/components/VirtualTable/useIntersectionObserver.ts +1 -0
  12. package/dist/containers/Node/Node.tsx +9 -7
  13. package/dist/containers/Nodes/NodesWrapper.tsx +1 -0
  14. package/dist/containers/Nodes/VirtualNodes.tsx +11 -5
  15. package/dist/containers/Nodes/getNodesColumns.tsx +1 -0
  16. package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +2 -1
  17. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +11 -6
  18. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +2 -2
  19. package/dist/containers/Tenant/Diagnostics/TenantOverview/DefaultOverviewContent/DefaultOverviewContent.tsx +6 -0
  20. package/dist/containers/Tenant/Diagnostics/TenantOverview/{DefaultDashboard.tsx → DefaultOverviewContent/defaultDashboardConfig.ts} +3 -7
  21. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.tsx +3 -2
  22. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/{CpuDashboard.tsx → cpuDashboardConfig.ts} +2 -6
  23. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantDashboard/TenantDashboard.tsx +27 -9
  24. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TenantMemory.tsx +3 -2
  25. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/{MemoryDashboard.tsx → memoryDashboardConfig.ts} +2 -6
  26. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +3 -5
  27. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx +1 -3
  28. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.tsx +6 -6
  29. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/{StorageDashboard.tsx → storageDashboardConfig.ts} +2 -6
  30. package/dist/containers/Tenant/Diagnostics/TenantOverview/utils.ts +3 -0
  31. package/dist/containers/UserSettings/i18n/en.json +2 -5
  32. package/dist/containers/UserSettings/i18n/ru.json +2 -5
  33. package/dist/containers/UserSettings/settings.ts +1 -12
  34. package/dist/services/settings.ts +0 -2
  35. package/dist/utils/constants.ts +0 -2
  36. package/dist/utils/hooks/useTableResize.ts +53 -0
  37. package/package.json +2 -1
@@ -1,13 +1,20 @@
1
1
  .ydb-cell-with-popover {
2
2
  display: flex;
3
3
 
4
+ max-width: 100%;
5
+
4
6
  &__popover {
5
7
  display: inline-block;
6
8
  overflow: hidden;
7
9
 
8
10
  max-width: 100%;
9
11
 
12
+ vertical-align: middle;
10
13
  white-space: nowrap;
11
14
  text-overflow: ellipsis;
15
+
16
+ .yc-popover__handler {
17
+ display: inline;
18
+ }
12
19
  }
13
20
  }
@@ -7,11 +7,12 @@ const b = cn('ydb-loader');
7
7
 
8
8
  interface LoaderProps {
9
9
  size?: LoaderSize;
10
+ className?: string;
10
11
  }
11
12
 
12
- export const Loader = ({size = 'm'}: LoaderProps) => {
13
+ export const Loader = ({size = 'm', className}: LoaderProps) => {
13
14
  return (
14
- <div className={b()}>
15
+ <div className={b(null, className)}>
15
16
  <KitLoader size={size} />
16
17
  </div>
17
18
  );
@@ -6,13 +6,19 @@ import ChartKit, {settings} from '@gravity-ui/chartkit';
6
6
  import type {IResponseError} from '../../types/api/error';
7
7
  import type {TimeFrame} from '../../utils/timeframes';
8
8
  import {useAutofetcher} from '../../utils/hooks';
9
+
9
10
  import {COLORS} from '../../utils/versions';
10
11
  import {cn} from '../../utils/cn';
11
12
 
12
13
  import {Loader} from '../Loader';
13
14
  import {ResponseError} from '../Errors/ResponseError';
14
15
 
15
- import type {ChartOptions, MetricDescription, PreparedMetricsData} from './types';
16
+ import type {
17
+ ChartOptions,
18
+ MetricDescription,
19
+ OnChartDataStatusChange,
20
+ PreparedMetricsData,
21
+ } from './types';
16
22
  import {convertResponse} from './convertReponse';
17
23
  import {getDefaultDataFormatter} from './getDefaultDataFormatter';
18
24
  import {getChartData} from './getChartData';
@@ -102,6 +108,15 @@ interface DiagnosticsChartProps {
102
108
  width?: number;
103
109
 
104
110
  chartOptions?: ChartOptions;
111
+
112
+ onChartDataStatusChange?: OnChartDataStatusChange;
113
+
114
+ /**
115
+ * YAGR charts don't render correctly inside not visible elements\
116
+ * So if chart is used inside component with 'display:none', it will be empty, when visibility change\
117
+ * Pass isChartVisible prop to ensure proper chart render
118
+ */
119
+ isChartVisible?: boolean;
105
120
  }
106
121
 
107
122
  export const MetricChart = ({
@@ -112,6 +127,8 @@ export const MetricChart = ({
112
127
  width = 400,
113
128
  height = width / 1.5,
114
129
  chartOptions,
130
+ onChartDataStatusChange,
131
+ isChartVisible,
115
132
  }: DiagnosticsChartProps) => {
116
133
  const mounted = useRef(false);
117
134
 
@@ -127,6 +144,20 @@ export const MetricChart = ({
127
144
  initialChartState,
128
145
  );
129
146
 
147
+ useEffect(() => {
148
+ if (error) {
149
+ return onChartDataStatusChange?.('error');
150
+ }
151
+ if (loading && !wasLoaded) {
152
+ return onChartDataStatusChange?.('loading');
153
+ }
154
+ if (!loading && wasLoaded) {
155
+ return onChartDataStatusChange?.('success');
156
+ }
157
+
158
+ return undefined;
159
+ }, [loading, wasLoaded, error, onChartDataStatusChange]);
160
+
130
161
  const fetchChartData = useCallback(
131
162
  async (isBackground: boolean) => {
132
163
  dispatch(setChartDataLoading());
@@ -146,7 +177,9 @@ export const MetricChart = ({
146
177
  });
147
178
 
148
179
  // Hack to prevent setting value to state, if component unmounted
149
- if (!mounted.current) return;
180
+ if (!mounted.current) {
181
+ return;
182
+ }
150
183
 
151
184
  // In some cases error could be in response with 200 status code
152
185
  // It happens when request is OK, but chart data cannot be returned due to some reason
@@ -155,10 +188,14 @@ export const MetricChart = ({
155
188
  const preparedData = convertResponse(response, metrics);
156
189
  dispatch(setChartData(preparedData));
157
190
  } else {
158
- dispatch(setChartError({statusText: response.error}));
191
+ const err = {statusText: response.error};
192
+
193
+ throw err;
159
194
  }
160
195
  } catch (err) {
161
- if (!mounted.current) return;
196
+ if (!mounted.current) {
197
+ return;
198
+ }
162
199
 
163
200
  dispatch(setChartError(err as IResponseError));
164
201
  }
@@ -175,6 +212,10 @@ export const MetricChart = ({
175
212
  return <Loader />;
176
213
  }
177
214
 
215
+ if (!isChartVisible) {
216
+ return null;
217
+ }
218
+
178
219
  return (
179
220
  <div className={b('chart')}>
180
221
  <ChartKit type="yagr" data={convertedData} />
@@ -1,2 +1,2 @@
1
- export type {MetricDescription, Metric, ChartOptions} from './types';
1
+ export * from './types';
2
2
  export {MetricChart} from './MetricChart';
@@ -30,3 +30,6 @@ export type ChartDataType = 'ms' | 'size';
30
30
  export interface ChartOptions {
31
31
  dataType?: ChartDataType;
32
32
  }
33
+
34
+ export type ChartDataStatus = 'loading' | 'success' | 'error';
35
+ export type OnChartDataStatusChange = (newStatus: ChartDataStatus) => void;
@@ -1,14 +1,21 @@
1
- import {useState} from 'react';
1
+ import {useCallback, useEffect, useMemo, useRef, useState} from 'react';
2
+
3
+ import type {
4
+ HandleTableColumnsResize,
5
+ TableColumnsWidthSetup,
6
+ } from '../../utils/hooks/useTableResize';
2
7
 
3
8
  import type {Column, OnSort, SortOrderType, SortParams} from './types';
4
9
  import {ASCENDING, DEFAULT_SORT_ORDER, DEFAULT_TABLE_ROW_HEIGHT, DESCENDING} from './constants';
5
10
  import {b} from './shared';
6
11
 
12
+ const COLUMN_NAME_HTML_ATTRIBUTE = 'data-columnname';
13
+
7
14
  // Icon similar to original DataTable icons to keep the same tables across diferent pages and tabs
8
15
  const SortIcon = ({order}: {order?: SortOrderType}) => {
9
16
  return (
10
17
  <svg
11
- className={b('icon', {desc: order === DESCENDING})}
18
+ className={b('sort-icon', {desc: order === DESCENDING})}
12
19
  viewBox="0 0 10 6"
13
20
  width="10"
14
21
  height="6"
@@ -27,7 +34,7 @@ interface ColumnSortIconProps {
27
34
  const ColumnSortIcon = ({sortOrder, sortable, defaultSortOrder}: ColumnSortIconProps) => {
28
35
  if (sortable) {
29
36
  return (
30
- <span className={b('sort-icon', {shadow: !sortOrder})}>
37
+ <span className={b('sort-icon-container', {shadow: !sortOrder})}>
31
38
  <SortIcon order={sortOrder || defaultSortOrder} />
32
39
  </span>
33
40
  );
@@ -36,9 +43,84 @@ const ColumnSortIcon = ({sortOrder, sortable, defaultSortOrder}: ColumnSortIconP
36
43
  }
37
44
  };
38
45
 
46
+ interface TableHeadCellProps<T> {
47
+ column: Column<T>;
48
+ sortOrder?: SortOrderType;
49
+ defaultSortOrder: SortOrderType;
50
+ onSort?: (columnName: string) => void;
51
+ rowHeight: number;
52
+ onCellMount?: (element: Element) => void;
53
+ onCellUnMount?: (element: Element) => void;
54
+ }
55
+
56
+ export const TableHeadCell = <T,>({
57
+ column,
58
+ sortOrder,
59
+ defaultSortOrder,
60
+ onSort,
61
+ rowHeight,
62
+ onCellMount,
63
+ onCellUnMount,
64
+ }: TableHeadCellProps<T>) => {
65
+ const cellWrapperRef = useRef<HTMLDivElement>(null);
66
+
67
+ useEffect(() => {
68
+ const cellWrapper = cellWrapperRef.current;
69
+ if (cellWrapper) {
70
+ onCellMount?.(cellWrapper);
71
+ }
72
+ return () => {
73
+ if (cellWrapper) {
74
+ onCellUnMount?.(cellWrapper);
75
+ }
76
+ };
77
+ }, [onCellMount, onCellUnMount]);
78
+
79
+ const content = column.header ?? column.name;
80
+
81
+ return (
82
+ <th>
83
+ <div
84
+ ref={cellWrapperRef}
85
+ className={b('head-cell-wrapper', {
86
+ resizeable: column.resizeable,
87
+ })}
88
+ style={{
89
+ height: `${rowHeight}px`,
90
+ width: `${column.width}px`,
91
+ }}
92
+ {...{
93
+ [COLUMN_NAME_HTML_ATTRIBUTE]: column.name,
94
+ }}
95
+ >
96
+ <div
97
+ className={b(
98
+ 'head-cell',
99
+ {align: column.align, sortable: column.sortable},
100
+ column.className,
101
+ )}
102
+ onClick={() => {
103
+ if (column.sortable) {
104
+ onSort?.(column.name);
105
+ }
106
+ }}
107
+ >
108
+ <div className={b('head-cell-content')}>{content}</div>
109
+ <ColumnSortIcon
110
+ sortOrder={sortOrder}
111
+ sortable={column.sortable}
112
+ defaultSortOrder={defaultSortOrder}
113
+ />
114
+ </div>
115
+ </div>
116
+ </th>
117
+ );
118
+ };
119
+
39
120
  interface TableHeadProps<T> {
40
121
  columns: Column<T>[];
41
122
  onSort?: OnSort;
123
+ onColumnsResize?: HandleTableColumnsResize;
42
124
  defaultSortOrder?: SortOrderType;
43
125
  rowHeight?: number;
44
126
  }
@@ -46,11 +128,44 @@ interface TableHeadProps<T> {
46
128
  export const TableHead = <T,>({
47
129
  columns,
48
130
  onSort,
131
+ onColumnsResize,
49
132
  defaultSortOrder = DEFAULT_SORT_ORDER,
50
133
  rowHeight = DEFAULT_TABLE_ROW_HEIGHT,
51
134
  }: TableHeadProps<T>) => {
52
135
  const [sortParams, setSortParams] = useState<SortParams>({});
53
136
 
137
+ const isTableResizeable = Boolean(onColumnsResize);
138
+
139
+ const resizeObserver: ResizeObserver | undefined = useMemo(() => {
140
+ if (!isTableResizeable) {
141
+ return undefined;
142
+ }
143
+
144
+ return new ResizeObserver((entries) => {
145
+ const columnsWidth: TableColumnsWidthSetup = {};
146
+ entries.forEach((entry) => {
147
+ // @ts-ignore ignore custrom property usage
148
+ const id = entry.target.attributes[COLUMN_NAME_HTML_ATTRIBUTE]?.value;
149
+ columnsWidth[id] = entry.contentRect.width;
150
+ });
151
+
152
+ onColumnsResize?.(columnsWidth);
153
+ });
154
+ }, [onColumnsResize, isTableResizeable]);
155
+
156
+ const handleCellMount = useCallback(
157
+ (element: Element) => {
158
+ resizeObserver?.observe(element);
159
+ },
160
+ [resizeObserver],
161
+ );
162
+ const handleCellUnMount = useCallback(
163
+ (element: Element) => {
164
+ resizeObserver?.unobserve(element);
165
+ },
166
+ [resizeObserver],
167
+ );
168
+
54
169
  const handleSort = (columnId: string) => {
55
170
  let newSortParams: SortParams = {};
56
171
 
@@ -95,34 +210,20 @@ export const TableHead = <T,>({
95
210
  <thead className={b('head')}>
96
211
  <tr>
97
212
  {columns.map((column) => {
98
- const content = column.header ?? column.name;
99
213
  const sortOrder =
100
214
  sortParams.columnId === column.name ? sortParams.sortOrder : undefined;
101
215
 
102
216
  return (
103
- <th
217
+ <TableHeadCell
104
218
  key={column.name}
105
- className={b(
106
- 'th',
107
- {align: column.align, sortable: column.sortable},
108
- column.className,
109
- )}
110
- style={{
111
- height: `${rowHeight}px`,
112
- }}
113
- onClick={() => {
114
- handleSort(column.name);
115
- }}
116
- >
117
- <div className={b('head-cell')}>
118
- {content}
119
- <ColumnSortIcon
120
- sortOrder={sortOrder}
121
- sortable={column.sortable}
122
- defaultSortOrder={defaultSortOrder}
123
- />
124
- </div>
125
- </th>
219
+ column={column}
220
+ sortOrder={sortOrder}
221
+ defaultSortOrder={defaultSortOrder}
222
+ onSort={handleSort}
223
+ rowHeight={rowHeight}
224
+ onCellMount={handleCellMount}
225
+ onCellUnMount={handleCellUnMount}
226
+ />
126
227
  );
127
228
  })}
128
229
  </tr>
@@ -8,14 +8,25 @@ import {b} from './shared';
8
8
 
9
9
  interface TableCellProps {
10
10
  height: number;
11
+ width: number;
11
12
  align?: AlignType;
12
13
  children: ReactNode;
13
14
  className?: string;
14
15
  }
15
16
 
16
- const TableRowCell = ({children, className, height, align = DEFAULT_ALIGN}: TableCellProps) => {
17
+ const TableRowCell = ({
18
+ children,
19
+ className,
20
+ height,
21
+ width,
22
+ align = DEFAULT_ALIGN,
23
+ }: TableCellProps) => {
24
+ // Additional maxWidth to ensure overflow hidden for <td>
17
25
  return (
18
- <td className={b('td', {align: align}, className)} style={{height: `${height}px`}}>
26
+ <td
27
+ className={b('row-cell', {align: align}, className)}
28
+ style={{height: `${height}px`, width: `${width}px`, maxWidth: `${width}px`}}
29
+ >
19
30
  {children}
20
31
  </td>
21
32
  );
@@ -35,6 +46,7 @@ export const LoadingTableRow = <T,>({index, columns, height}: LoadingTableRowPro
35
46
  <TableRowCell
36
47
  key={`${column.name}${index}`}
37
48
  height={height}
49
+ width={column.width}
38
50
  align={column.align}
39
51
  className={column.className}
40
52
  >
@@ -64,6 +76,7 @@ export const TableRow = <T,>({row, index, columns, getRowClassName, height}: Tab
64
76
  <TableRowCell
65
77
  key={`${column.name}${index}`}
66
78
  height={height}
79
+ width={column.width}
67
80
  align={column.align}
68
81
  className={column.className}
69
82
  >
@@ -6,8 +6,6 @@
6
6
  --virtual-table-cell-vertical-padding: 5px;
7
7
  --virtual-table-cell-horizontal-padding: 10px;
8
8
 
9
- --virtual-table-sort-icon-space: 18px;
10
-
11
9
  --virtual-table-border-color: var(--g-color-base-generic-hover);
12
10
  --virtual-table-hover-color: var(--g-color-base-float-hover);
13
11
 
@@ -21,6 +19,10 @@
21
19
  table-layout: fixed;
22
20
  border-spacing: 0;
23
21
  border-collapse: separate;
22
+
23
+ th {
24
+ padding: 0;
25
+ }
24
26
  }
25
27
 
26
28
  &__row {
@@ -40,96 +42,96 @@
40
42
  @include sticky-top();
41
43
  }
42
44
 
43
- &__th {
44
- position: relative;
45
-
46
- padding: var(--virtual-table-cell-vertical-padding)
47
- var(--virtual-table-cell-horizontal-padding);
48
-
49
- font-weight: bold;
50
- cursor: default;
51
- text-align: left;
45
+ &__sort-icon-container {
46
+ display: flex;
47
+ justify-content: center;
52
48
 
53
- border-bottom: $cell-border;
49
+ color: inherit;
54
50
 
55
- &_sortable {
56
- cursor: pointer;
51
+ &_shadow {
52
+ opacity: 0.15;
53
+ }
54
+ }
57
55
 
58
- #{$block}__head-cell {
59
- padding-right: var(--virtual-table-sort-icon-space);
60
- }
56
+ &__sort-icon {
57
+ &_desc {
58
+ transform: rotate(180deg);
59
+ }
60
+ }
61
61
 
62
- &#{$block}__th_align_right {
63
- #{$block}__head-cell {
64
- padding-right: 0;
65
- padding-left: var(--virtual-table-sort-icon-space);
66
- }
62
+ &__head-cell-wrapper {
63
+ display: flex;
64
+ overflow-x: hidden;
67
65
 
68
- #{$block}__sort-icon {
69
- right: auto;
70
- left: 0;
66
+ border-bottom: $cell-border;
71
67
 
72
- transform: translate(0, -50%) scaleX(-1);
73
- }
74
- }
68
+ &_resizeable {
69
+ resize: horizontal;
75
70
  }
76
71
  }
77
72
 
78
73
  &__head-cell {
79
- position: relative;
80
-
81
- display: inline-block;
82
- overflow: hidden;
74
+ display: flex;
75
+ flex-direction: row;
76
+ align-items: center;
83
77
 
84
- box-sizing: border-box;
78
+ width: 100%;
85
79
  max-width: 100%;
80
+ padding: var(--virtual-table-cell-vertical-padding)
81
+ var(--virtual-table-cell-horizontal-padding);
86
82
 
87
- vertical-align: top;
88
- white-space: nowrap;
89
- text-overflow: ellipsis;
83
+ &_align {
84
+ &_left {
85
+ justify-content: left;
86
+ }
87
+ &_center {
88
+ justify-content: center;
89
+ }
90
+ &_right {
91
+ justify-content: right;
92
+ }
93
+ }
90
94
  }
91
95
 
92
- &__sort-icon {
93
- position: absolute;
94
- top: 50%;
95
- right: 0;
96
-
97
- display: inline-flex;
96
+ &__head-cell {
97
+ gap: 8px;
98
98
 
99
- color: inherit;
99
+ font-weight: bold;
100
+ cursor: default;
100
101
 
101
- transform: translate(0, -50%);
102
+ &_sortable {
103
+ cursor: pointer;
102
104
 
103
- &_shadow {
104
- opacity: 0.15;
105
+ &#{$block}__head-cell_align_right {
106
+ flex-direction: row-reverse;
107
+ }
105
108
  }
106
109
  }
107
110
 
108
- &__icon {
109
- vertical-align: top;
111
+ // Separate head cell content class for correct text ellipsis overflow
112
+ &__head-cell-content {
113
+ overflow: hidden;
110
114
 
111
- &_desc {
112
- transform: rotate(180deg);
113
- }
115
+ width: min-content;
116
+
117
+ white-space: nowrap;
118
+ text-overflow: ellipsis;
114
119
  }
115
120
 
116
- &__td {
117
- overflow: hidden;
121
+ &__row-cell {
122
+ display: table-cell;
123
+ overflow-x: hidden;
118
124
 
125
+ width: 100%;
126
+ max-width: 100%;
119
127
  padding: var(--virtual-table-cell-vertical-padding)
120
128
  var(--virtual-table-cell-horizontal-padding);
121
129
 
130
+ vertical-align: middle;
122
131
  white-space: nowrap;
123
132
  text-overflow: ellipsis;
124
133
 
125
134
  border-bottom: $cell-border;
126
- }
127
-
128
- &__td,
129
- &__th {
130
- height: 40px;
131
-
132
- vertical-align: middle;
133
135
 
134
136
  &_align {
135
137
  &_left {
@@ -1,5 +1,7 @@
1
1
  import {useState, useReducer, useRef, useCallback, useEffect} from 'react';
2
2
 
3
+ import type {HandleTableColumnsResize} from '../../utils/hooks/useTableResize';
4
+
3
5
  import type {IResponseError} from '../../types/api/error';
4
6
  import {getArray} from '../../utils';
5
7
 
@@ -45,9 +47,12 @@ interface VirtualTableProps<T> {
45
47
  rowHeight?: number;
46
48
  parentContainer?: Element | null;
47
49
  initialSortParams?: SortParams;
50
+ onColumnsResize?: HandleTableColumnsResize;
51
+
48
52
  renderControls?: RenderControls;
49
53
  renderEmptyDataMessage?: RenderEmptyDataMessage;
50
54
  renderErrorMessage?: RenderErrorMessage;
55
+
51
56
  dependencyArray?: unknown[]; // Fully reload table on params change
52
57
  }
53
58
 
@@ -59,6 +64,7 @@ export const VirtualTable = <T,>({
59
64
  rowHeight = DEFAULT_TABLE_ROW_HEIGHT,
60
65
  parentContainer,
61
66
  initialSortParams,
67
+ onColumnsResize,
62
68
  renderControls,
63
69
  renderEmptyDataMessage,
64
70
  renderErrorMessage,
@@ -258,7 +264,11 @@ export const VirtualTable = <T,>({
258
264
  const renderTable = () => {
259
265
  return (
260
266
  <table className={b('table')}>
261
- <TableHead columns={columns} onSort={handleSort} />
267
+ <TableHead
268
+ columns={columns}
269
+ onSort={handleSort}
270
+ onColumnsResize={onColumnsResize}
271
+ />
262
272
  {renderData()}
263
273
  </table>
264
274
  );
@@ -28,6 +28,7 @@ export interface Column<T> {
28
28
  header?: ReactNode;
29
29
  className?: string;
30
30
  sortable?: boolean;
31
+ resizeable?: boolean;
31
32
  render: (props: {row: T; index: number}) => ReactNode;
32
33
  width: number;
33
34
  align: AlignType;
@@ -6,6 +6,7 @@ import {DEFAULT_INTERSECTION_OBSERVER_MARGIN} from './constants';
6
6
  interface UseIntersectionObserverProps {
7
7
  onEntry: OnEntry;
8
8
  onLeave: OnLeave;
9
+ /** Intersection observer calculate margins based on container element properties */
9
10
  parentContainer?: Element | null;
10
11
  }
11
12