ydb-embedded-ui 4.31.2 → 4.33.0

Sign up to get free protection for your applications and to get access to all the features.
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