ydb-embedded-ui 3.1.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +2 -0
  3. package/dist/components/DateRange/DateRange.scss +11 -0
  4. package/dist/{containers/Tenant/Diagnostics/TopShards → components}/DateRange/DateRange.tsx +7 -7
  5. package/dist/{containers/Tenant/Diagnostics/TopShards → components}/DateRange/index.ts +0 -0
  6. package/dist/components/EntitiesCount/EntitiesCount.tsx +34 -0
  7. package/dist/components/EntitiesCount/i18n/en.json +3 -0
  8. package/dist/components/{AsideNavigation/Settings → EntitiesCount}/i18n/index.ts +2 -2
  9. package/dist/components/EntitiesCount/i18n/ru.json +3 -0
  10. package/dist/components/EntitiesCount/index.ts +1 -0
  11. package/dist/components/Fullscreen/Fullscreen.scss +7 -5
  12. package/dist/components/Illustration/Illustration.tsx +4 -11
  13. package/dist/components/InfoViewer/InfoViewer.scss +2 -0
  14. package/dist/components/TabletsOverall/TabletsOverall.tsx +4 -4
  15. package/dist/components/TabletsStatistic/TabletsStatistic.tsx +56 -0
  16. package/dist/components/TabletsStatistic/index.ts +1 -0
  17. package/dist/containers/App/App.scss +4 -12
  18. package/dist/containers/AsideNavigation/AsideNavigation.scss +0 -18
  19. package/dist/containers/AsideNavigation/AsideNavigation.tsx +95 -33
  20. package/dist/containers/Heatmap/Heatmap.scss +0 -7
  21. package/dist/containers/Heatmap/Heatmap.tsx +203 -0
  22. package/dist/containers/Heatmap/HeatmapCanvas/HeatmapCanvas.js +2 -1
  23. package/dist/containers/Heatmap/index.ts +1 -0
  24. package/dist/containers/Node/Node.tsx +1 -1
  25. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +1 -1
  26. package/dist/containers/Storage/Storage.js +12 -19
  27. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +16 -0
  28. package/dist/containers/Tablets/Tablets.scss +0 -5
  29. package/dist/containers/Tablets/Tablets.tsx +172 -0
  30. package/dist/containers/Tablets/i18n/en.json +6 -0
  31. package/dist/{components/AsideNavigation → containers/Tablets}/i18n/index.ts +1 -1
  32. package/dist/containers/Tablets/i18n/ru.json +6 -0
  33. package/dist/containers/Tablets/index.ts +1 -0
  34. package/dist/containers/TabletsFilters/TabletsFilters.js +4 -8
  35. package/dist/containers/TabletsFilters/TabletsFilters.scss +6 -2
  36. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +8 -13
  37. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +7 -7
  38. package/dist/containers/Tenant/Diagnostics/{TopShards/TopShards.scss → OverloadedShards/OverloadedShards.scss} +1 -1
  39. package/dist/containers/Tenant/Diagnostics/{TopShards/TopShards.tsx → OverloadedShards/OverloadedShards.tsx} +10 -11
  40. package/dist/containers/Tenant/Diagnostics/{TopShards → OverloadedShards}/i18n/en.json +0 -0
  41. package/dist/containers/Tenant/Diagnostics/OverloadedShards/i18n/index.ts +11 -0
  42. package/dist/containers/Tenant/Diagnostics/{TopShards → OverloadedShards}/i18n/ru.json +0 -0
  43. package/dist/containers/Tenant/Diagnostics/OverloadedShards/index.ts +1 -0
  44. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +7 -7
  45. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +16 -19
  46. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +202 -0
  47. package/dist/containers/Tenant/Diagnostics/TopQueries/i18n/en.json +4 -0
  48. package/dist/containers/Tenant/Diagnostics/{TopShards → TopQueries}/i18n/index.ts +1 -1
  49. package/dist/containers/Tenant/Diagnostics/TopQueries/i18n/ru.json +4 -0
  50. package/dist/containers/Tenant/Diagnostics/TopQueries/index.ts +1 -0
  51. package/dist/containers/Tenants/Tenants.js +1 -1
  52. package/dist/containers/UserSettings/UserSettings.tsx +5 -4
  53. package/dist/routes.ts +1 -1
  54. package/dist/services/api.d.ts +7 -0
  55. package/dist/store/reducers/describe.ts +4 -1
  56. package/dist/store/reducers/executeTopQueries.ts +170 -0
  57. package/dist/store/reducers/{heatmap.js → heatmap.ts} +33 -18
  58. package/dist/store/reducers/settings.js +13 -3
  59. package/dist/store/reducers/shardsWorkload.ts +9 -9
  60. package/dist/store/reducers/storage.js +2 -0
  61. package/dist/store/reducers/{tablets.js → tablets.ts} +30 -17
  62. package/dist/store/state-url-mapping.js +10 -2
  63. package/dist/types/api/compute.ts +52 -0
  64. package/dist/types/api/consumer.ts +257 -0
  65. package/dist/types/api/enums.ts +2 -2
  66. package/dist/types/api/nodes.ts +5 -2
  67. package/dist/types/api/pdisk.ts +3 -0
  68. package/dist/types/api/schema.ts +17 -3
  69. package/dist/types/api/storage.ts +31 -28
  70. package/dist/types/api/tablet.ts +18 -2
  71. package/dist/types/api/tenant.ts +4 -1
  72. package/dist/types/api/topic.ts +157 -0
  73. package/dist/types/api/vdisk.ts +3 -0
  74. package/dist/types/store/executeTopQueries.ts +29 -0
  75. package/dist/types/store/heatmap.ts +51 -0
  76. package/dist/types/store/schema.ts +3 -3
  77. package/dist/types/store/shardsWorkload.ts +3 -3
  78. package/dist/types/store/tablets.ts +42 -0
  79. package/dist/utils/constants.ts +1 -37
  80. package/dist/utils/getNodesColumns.js +14 -2
  81. package/dist/utils/tablet.ts +53 -0
  82. package/package.json +4 -3
  83. package/dist/components/AsideNavigation/AsideHeader.scss +0 -147
  84. package/dist/components/AsideNavigation/AsideHeader.tsx +0 -389
  85. package/dist/components/AsideNavigation/AsideHeaderFooterItem/AsideHeaderFooterItem.scss +0 -82
  86. package/dist/components/AsideNavigation/AsideHeaderFooterItem/AsideHeaderFooterItem.tsx +0 -138
  87. package/dist/components/AsideNavigation/AsideHeaderFooterSlot/AsideHeaderFooterSlot.tsx +0 -33
  88. package/dist/components/AsideNavigation/AsideHeaderFooterSlot/SlotsContext.tsx +0 -49
  89. package/dist/components/AsideNavigation/AsideHeaderTooltip/AsideHeaderTooltip.scss +0 -16
  90. package/dist/components/AsideNavigation/AsideHeaderTooltip/AsideHeaderTooltip.tsx +0 -37
  91. package/dist/components/AsideNavigation/CompositeBar/CompositeBar.scss +0 -108
  92. package/dist/components/AsideNavigation/CompositeBar/CompositeBar.tsx +0 -282
  93. package/dist/components/AsideNavigation/Content/Content.tsx +0 -35
  94. package/dist/components/AsideNavigation/Drawer/Drawer.scss +0 -76
  95. package/dist/components/AsideNavigation/Drawer/Drawer.tsx +0 -134
  96. package/dist/components/AsideNavigation/Drawer/index.ts +0 -1
  97. package/dist/components/AsideNavigation/Logo/Logo.scss +0 -43
  98. package/dist/components/AsideNavigation/Logo/Logo.tsx +0 -82
  99. package/dist/components/AsideNavigation/Settings/README.md +0 -92
  100. package/dist/components/AsideNavigation/Settings/Settings.scss +0 -128
  101. package/dist/components/AsideNavigation/Settings/Settings.tsx +0 -270
  102. package/dist/components/AsideNavigation/Settings/SettingsMenu/SettingsMenu.scss +0 -78
  103. package/dist/components/AsideNavigation/Settings/SettingsMenu/SettingsMenu.tsx +0 -141
  104. package/dist/components/AsideNavigation/Settings/SettingsSearch/SettingsSearch.tsx +0 -57
  105. package/dist/components/AsideNavigation/Settings/collect-settings.ts +0 -156
  106. package/dist/components/AsideNavigation/Settings/filter-settings.ts +0 -38
  107. package/dist/components/AsideNavigation/Settings/helpers.ts +0 -39
  108. package/dist/components/AsideNavigation/Settings/i18n/en.json +0 -5
  109. package/dist/components/AsideNavigation/Settings/i18n/ru.json +0 -5
  110. package/dist/components/AsideNavigation/Settings/index.ts +0 -1
  111. package/dist/components/AsideNavigation/constants.ts +0 -28
  112. package/dist/components/AsideNavigation/helpers.ts +0 -34
  113. package/dist/components/AsideNavigation/i18n/en.json +0 -4
  114. package/dist/components/AsideNavigation/i18n/ru.json +0 -4
  115. package/dist/components/AsideNavigation/icons.ts +0 -32
  116. package/dist/components/AsideNavigation/types.ts +0 -23
  117. package/dist/components/TabletsStatistic/TabletsStatistic.js +0 -58
  118. package/dist/containers/Heatmap/Heatmap.js +0 -244
  119. package/dist/containers/Tablets/Tablets.js +0 -228
  120. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +0 -188
  121. package/dist/containers/Tenant/Diagnostics/TopShards/DateRange/DateRange.scss +0 -13
  122. package/dist/containers/Tenant/Diagnostics/TopShards/index.ts +0 -1
  123. package/dist/store/reducers/executeTopQueries.js +0 -66
  124. package/dist/types/api/consumers.ts +0 -3
@@ -0,0 +1,203 @@
1
+ import React, {useCallback, useEffect, useState} from 'react';
2
+ import {useDispatch} from 'react-redux';
3
+ import cn from 'bem-cn-lite';
4
+
5
+ import {Checkbox, Select} from '@gravity-ui/uikit';
6
+
7
+ import {getTabletsInfo, setHeatmapOptions} from '../../store/reducers/heatmap';
8
+ import {showTooltip, hideTooltip} from '../../store/reducers/tooltip';
9
+ import {formatNumber} from '../../utils';
10
+ import {prepareQueryError} from '../../utils/query';
11
+ import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
12
+ import {Loader} from '../../components/Loader';
13
+ import type {IHeatmapMetricValue} from '../../types/store/heatmap';
14
+
15
+ import {COLORS_RANGE_SIZE, getColorRange, getColorIndex, getCurrentMetricLimits} from './util';
16
+ import {HeatmapCanvas} from './HeatmapCanvas/HeatmapCanvas';
17
+ import {Histogram} from './Histogram/Histogram';
18
+
19
+ import './Heatmap.scss';
20
+
21
+ const b = cn('heatmap');
22
+ const COLORS_RANGE = getColorRange(COLORS_RANGE_SIZE);
23
+
24
+ interface HeatmapProps {
25
+ path: string;
26
+ }
27
+
28
+ export const Heatmap = ({path}: HeatmapProps) => {
29
+ const dispatch = useDispatch();
30
+
31
+ const itemsContainer = React.createRef<HTMLDivElement>();
32
+
33
+ const {autorefresh} = useTypedSelector((state) => state.schema);
34
+ const {
35
+ loading,
36
+ wasLoaded,
37
+ error,
38
+ sort,
39
+ heatmap,
40
+ metrics,
41
+ currentMetric,
42
+ data: tablets = [],
43
+ } = useTypedSelector((state) => state.heatmap);
44
+
45
+ const [selectedMetric, setSelectedMetric] = useState(['']);
46
+
47
+ useEffect(() => {
48
+ if (!currentMetric && metrics && metrics.length) {
49
+ dispatch(
50
+ setHeatmapOptions({
51
+ currentMetric: metrics[0].value,
52
+ }),
53
+ );
54
+ }
55
+ if (currentMetric) {
56
+ setSelectedMetric([currentMetric]);
57
+ }
58
+ }, [currentMetric, metrics, dispatch]);
59
+
60
+ const fetchData = useCallback(
61
+ (isBackground: boolean) => {
62
+ if (!isBackground) {
63
+ dispatch(setHeatmapOptions({wasLoaded: false}));
64
+ }
65
+ dispatch(getTabletsInfo({path}));
66
+ },
67
+ [path, dispatch],
68
+ );
69
+
70
+ useAutofetcher(fetchData, [fetchData], autorefresh);
71
+
72
+ const onShowTooltip = (...args: Parameters<typeof showTooltip>) => {
73
+ dispatch(showTooltip(...args));
74
+ };
75
+
76
+ const onHideTooltip = () => {
77
+ dispatch(hideTooltip);
78
+ };
79
+
80
+ const handleMetricChange = (value: string[]) => {
81
+ dispatch(
82
+ setHeatmapOptions({
83
+ currentMetric: value[0] as IHeatmapMetricValue,
84
+ }),
85
+ );
86
+ };
87
+ const handleCheckboxChange = () => {
88
+ dispatch(
89
+ setHeatmapOptions({
90
+ sort: !sort,
91
+ }),
92
+ );
93
+ };
94
+
95
+ const handleHeatmapChange = () => {
96
+ dispatch(
97
+ setHeatmapOptions({
98
+ heatmap: !heatmap,
99
+ }),
100
+ );
101
+ };
102
+
103
+ const renderHistogram = () => {
104
+ return (
105
+ <Histogram
106
+ tablets={tablets}
107
+ currentMetric={currentMetric}
108
+ showTooltip={onShowTooltip}
109
+ hideTooltip={onHideTooltip}
110
+ />
111
+ );
112
+ };
113
+
114
+ const renderHeatmapCanvas = () => {
115
+ const {min, max} = getCurrentMetricLimits(currentMetric, tablets);
116
+
117
+ const preparedTablets = tablets.map((tablet) => {
118
+ const value = currentMetric && Number(tablet.metrics?.[currentMetric]);
119
+ const colorIndex = getColorIndex(value, min, max);
120
+ const color = COLORS_RANGE[colorIndex];
121
+
122
+ return {
123
+ ...tablet,
124
+ color,
125
+ value,
126
+ formattedValue: formatNumber(value),
127
+ currentMetric,
128
+ };
129
+ });
130
+ const sortedTablets = sort
131
+ ? preparedTablets.sort((x, y) => Number(y.value) - Number(x.value))
132
+ : preparedTablets;
133
+
134
+ return (
135
+ <div ref={itemsContainer} className={b('items')}>
136
+ <HeatmapCanvas
137
+ tablets={sortedTablets}
138
+ parentRef={itemsContainer}
139
+ showTooltip={onShowTooltip}
140
+ hideTooltip={onHideTooltip}
141
+ currentMetric={currentMetric}
142
+ />
143
+ </div>
144
+ );
145
+ };
146
+
147
+ const renderContent = () => {
148
+ const {min, max} = getCurrentMetricLimits(currentMetric, tablets);
149
+
150
+ return (
151
+ <div className={b()}>
152
+ <div className={b('filters')}>
153
+ <Select
154
+ className={b('heatmap-select')}
155
+ value={selectedMetric}
156
+ options={metrics}
157
+ onUpdate={handleMetricChange}
158
+ width={200}
159
+ />
160
+ <div className={b('sort-checkbox')}>
161
+ <Checkbox onUpdate={handleCheckboxChange} checked={sort}>
162
+ Sort
163
+ </Checkbox>
164
+ </div>
165
+ <div className={b('histogram-checkbox')}>
166
+ <Checkbox onUpdate={handleHeatmapChange} checked={heatmap}>
167
+ Heatmap
168
+ </Checkbox>
169
+ </div>
170
+ <div className={b('limits')}>
171
+ <div className={b('limits-block')}>
172
+ <div className={b('limits-title')}>min:</div>
173
+ <div className={b('limits-value')}>
174
+ {Number.isInteger(min) ? formatNumber(min) : '—'}
175
+ </div>
176
+ </div>
177
+ <div className={b('limits-block')}>
178
+ <div className={b('limits-title')}>max:</div>
179
+ <div className={b('limits-value')}>
180
+ {Number.isInteger(max) ? formatNumber(max) : '—'}
181
+ </div>
182
+ </div>
183
+ <div className={b('limits-block')}>
184
+ <div className={b('limits-title')}>count:</div>
185
+ <div className={b('limits-value')}>{formatNumber(tablets.length)}</div>
186
+ </div>
187
+ </div>
188
+ </div>
189
+ {heatmap ? renderHeatmapCanvas() : renderHistogram()}
190
+ </div>
191
+ );
192
+ };
193
+
194
+ if (loading && !wasLoaded) {
195
+ return <Loader />;
196
+ }
197
+
198
+ if (error) {
199
+ return <div>{prepareQueryError(error)}</div>;
200
+ }
201
+
202
+ return renderContent();
203
+ };
@@ -161,7 +161,8 @@ export const HeatmapCanvas = (props) => {
161
161
 
162
162
  HeatmapCanvas.propTypes = {
163
163
  tablets: PropTypes.array,
164
- parentRef: PropTypes.node,
164
+ parentRef: PropTypes.object,
165
165
  showTooltip: PropTypes.func,
166
166
  hideTooltip: PropTypes.func,
167
+ currentMetric: PropTypes.string,
167
168
  };
@@ -0,0 +1 @@
1
+ export * from './Heatmap';
@@ -8,7 +8,7 @@ import {Tabs} from '@gravity-ui/uikit';
8
8
  import {Link} from 'react-router-dom';
9
9
 
10
10
  import {TABLETS, STORAGE, NODE_PAGES, OVERVIEW, STRUCTURE} from './NodePages';
11
- import Tablets from '../Tablets/Tablets';
11
+ import {Tablets} from '../Tablets';
12
12
  import Storage from '../Storage/Storage';
13
13
  import NodeOverview from './NodeOverview/NodeOverview';
14
14
  import NodeStructure from './NodeStructure/NodeStructure';
@@ -27,7 +27,7 @@ function DiskStateProgressBar({
27
27
  diskAllocatedPercent = -1,
28
28
  severity,
29
29
  }: DiskStateProgressBarProps) {
30
- const inverted = useSelector((state) => getSettingValue(state, INVERTED_DISKS_KEY));
30
+ const inverted = useSelector((state) => JSON.parse(getSettingValue(state, INVERTED_DISKS_KEY)));
31
31
 
32
32
  const renderAllocatedPercent = () => {
33
33
  return (
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import {connect} from 'react-redux';
4
4
  import cn from 'bem-cn-lite';
5
5
  import DataTable from '@yandex-cloud/react-data-table';
6
- import {RadioButton, Label} from '@gravity-ui/uikit';
6
+ import {RadioButton} from '@gravity-ui/uikit';
7
7
 
8
8
  import {Search} from '../../components/Search';
9
9
  import {UsageFilter} from './UsageFilter';
@@ -12,6 +12,7 @@ import {NodesUptimeFilterValues} from '../../utils/nodes';
12
12
  import {TableSkeleton} from '../../components/TableSkeleton/TableSkeleton';
13
13
  import {UptimeFilter} from '../../components/UptimeFIlter';
14
14
  import {AccessDenied} from '../../components/Errors/403';
15
+ import {EntitiesCount} from '../../components/EntitiesCount';
15
16
 
16
17
  import {
17
18
  getStorageInfo,
@@ -230,22 +231,17 @@ class Storage extends React.Component {
230
231
  const {storageType, groupsCount, nodesCount, flatListStorageEntities, loading, wasLoaded} =
231
232
  this.props;
232
233
 
233
- let label = `${storageType === StorageTypes.groups ? 'Groups' : 'Nodes'}: `;
234
+ const entityName = storageType === StorageTypes.groups ? 'Groups' : 'Nodes';
234
235
  const count = storageType === StorageTypes.groups ? groupsCount : nodesCount;
235
236
 
236
- if (loading && !wasLoaded) {
237
- label += '...';
238
- return label;
239
- }
240
-
241
- // count.total can be missing in old versions
242
- if (flatListStorageEntities.length === Number(count.total) || !count.total) {
243
- label += flatListStorageEntities.length;
244
- } else {
245
- label += `${flatListStorageEntities.length} of ${count.total}`;
246
- }
247
-
248
- return label;
237
+ return (
238
+ <EntitiesCount
239
+ label={entityName}
240
+ loading={loading && !wasLoaded}
241
+ total={count.total}
242
+ current={flatListStorageEntities.length}
243
+ />
244
+ );
249
245
  }
250
246
 
251
247
  renderControls() {
@@ -307,10 +303,7 @@ class Storage extends React.Component {
307
303
  disabled={usageFilterOptions.length === 0}
308
304
  />
309
305
  )}
310
-
311
- <Label theme="info" size="m">
312
- {this.renderEntitiesCount()}
313
- </Label>
306
+ {this.renderEntitiesCount()}
314
307
  </div>
315
308
  );
316
309
  }
@@ -16,6 +16,8 @@ import './StorageNodes.scss';
16
16
  enum TableColumnsIds {
17
17
  NodeId = 'NodeId',
18
18
  FQDN = 'FQDN',
19
+ DataCenter = 'DataCenter',
20
+ Rack = 'Rack',
19
21
  uptime = 'uptime',
20
22
  PDisks = 'PDisks',
21
23
  Missing = 'Missing',
@@ -36,6 +38,8 @@ interface StorageNodesProps {
36
38
  const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
37
39
  NodeId: 'Node ID',
38
40
  FQDN: 'FQDN',
41
+ DataCenter: 'DC',
42
+ Rack: 'Rack',
39
43
  uptime: 'Uptime',
40
44
  PDisks: 'PDisks',
41
45
  Missing: 'Missing',
@@ -96,6 +100,18 @@ function StorageNodes({
96
100
  },
97
101
  align: DataTable.LEFT,
98
102
  },
103
+ {
104
+ name: TableColumnsIds.DataCenter,
105
+ header: tableColumnsNames[TableColumnsIds.DataCenter],
106
+ render: ({row}) => row.DataCenter || '—',
107
+ align: DataTable.LEFT,
108
+ },
109
+ {
110
+ name: TableColumnsIds.Rack,
111
+ header: tableColumnsNames[TableColumnsIds.Rack],
112
+ render: ({row}) => row.Rack || '—',
113
+ align: DataTable.LEFT,
114
+ },
99
115
  {
100
116
  name: TableColumnsIds.uptime,
101
117
  header: tableColumnsNames[TableColumnsIds.uptime],
@@ -37,9 +37,4 @@
37
37
  line-height: 18px;
38
38
  text-align: center;
39
39
  }
40
-
41
- &__loader-wrapper {
42
- display: flex;
43
- justify-content: center;
44
- }
45
40
  }
@@ -0,0 +1,172 @@
1
+ import {useCallback, useEffect, useState} from 'react';
2
+ import {useDispatch} from 'react-redux';
3
+ import cn from 'bem-cn-lite';
4
+ import ReactList from 'react-list';
5
+
6
+ import {Select} from '@gravity-ui/uikit';
7
+
8
+ import Tablet from '../../components/Tablet/Tablet';
9
+ import TabletsOverall from '../../components/TabletsOverall/TabletsOverall';
10
+ import {Loader} from '../../components/Loader';
11
+
12
+ import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
13
+ import {ETabletState, EType, TTabletStateInfo} from '../../types/api/tablet';
14
+
15
+ import {showTooltip, hideTooltip} from '../../store/reducers/tooltip';
16
+ import {
17
+ getTabletsInfo,
18
+ clearWasLoadingFlag,
19
+ setStateFilter,
20
+ setTypeFilter,
21
+ } from '../../store/reducers/tablets';
22
+
23
+ import './Tablets.scss';
24
+
25
+ import i18n from './i18n';
26
+
27
+ const b = cn('tablets');
28
+
29
+ interface TabletsProps {
30
+ path?: string;
31
+ nodeId?: string | number;
32
+ className?: string;
33
+ }
34
+
35
+ export const Tablets = ({path, nodeId, className}: TabletsProps) => {
36
+ const dispatch = useDispatch();
37
+
38
+ const {
39
+ data = {},
40
+ wasLoaded,
41
+ loading,
42
+ error,
43
+ stateFilter,
44
+ typeFilter,
45
+ } = useTypedSelector((state) => state.tablets);
46
+ const {autorefresh} = useTypedSelector((state) => state.schema);
47
+
48
+ const {TabletStateInfo: tablets = []} = data;
49
+
50
+ const fetchData = useCallback(
51
+ (isBackground) => {
52
+ if (!isBackground) {
53
+ dispatch(clearWasLoadingFlag());
54
+ }
55
+ if (nodeId) {
56
+ dispatch(getTabletsInfo({nodes: [String(nodeId)]}));
57
+ } else if (path) {
58
+ dispatch(getTabletsInfo({path}));
59
+ }
60
+ },
61
+ [path, nodeId, dispatch],
62
+ );
63
+
64
+ useAutofetcher(fetchData, [fetchData], autorefresh);
65
+
66
+ const [tabletsToRender, setTabletsToRender] = useState<TTabletStateInfo[]>([]);
67
+
68
+ useEffect(() => {
69
+ let filteredTablets = tablets;
70
+
71
+ if (typeFilter.length > 0) {
72
+ filteredTablets = filteredTablets.filter((tablet) =>
73
+ typeFilter.some((filter) => tablet.Type === filter),
74
+ );
75
+ }
76
+ if (stateFilter.length > 0) {
77
+ filteredTablets = filteredTablets.filter((tablet) =>
78
+ stateFilter.some((filter) => tablet.State === filter),
79
+ );
80
+ }
81
+ setTabletsToRender(filteredTablets);
82
+ }, [tablets, stateFilter, typeFilter]);
83
+
84
+ const handleStateFilterChange = (value: string[]) => {
85
+ dispatch(setStateFilter(value as ETabletState[]));
86
+ };
87
+
88
+ const handleTypeFilterChange = (value: string[]) => {
89
+ dispatch(setTypeFilter(value as EType[]));
90
+ };
91
+
92
+ const onShowTooltip = (...args: Parameters<typeof showTooltip>) => {
93
+ dispatch(showTooltip(...args));
94
+ };
95
+
96
+ const onHideTooltip = () => {
97
+ dispatch(hideTooltip());
98
+ };
99
+
100
+ const renderTablet = (tabletIndex: number) => {
101
+ return (
102
+ <Tablet
103
+ onMouseLeave={onHideTooltip}
104
+ onMouseEnter={onShowTooltip}
105
+ tablet={tabletsToRender[tabletIndex]}
106
+ key={tabletIndex}
107
+ className={b('tablet')}
108
+ />
109
+ );
110
+ };
111
+
112
+ const renderContent = () => {
113
+ const states = Array.from(new Set(tablets.map((tablet) => tablet.State)))
114
+ .filter((state): state is ETabletState => state !== undefined)
115
+ .map((item) => ({
116
+ value: item,
117
+ content: item,
118
+ }));
119
+ const types = Array.from(new Set(tablets.map((tablet) => tablet.Type)))
120
+ .filter((type): type is EType => type !== undefined)
121
+ .map((item) => ({
122
+ value: item,
123
+ content: item,
124
+ }));
125
+
126
+ return (
127
+ <div className={b(null, className)}>
128
+ <div className={b('header')}>
129
+ <Select
130
+ className={b('filter-control')}
131
+ multiple
132
+ placeholder={i18n('controls.allItems')}
133
+ label={`${i18n('controls.state')}:`}
134
+ options={states}
135
+ value={stateFilter}
136
+ onUpdate={handleStateFilterChange}
137
+ />
138
+ <Select
139
+ className={b('filter-control')}
140
+ multiple
141
+ placeholder={i18n('controls.allItems')}
142
+ label={`${i18n('controls.type')}:`}
143
+ options={types}
144
+ value={typeFilter}
145
+ onUpdate={handleTypeFilterChange}
146
+ />
147
+ <TabletsOverall tablets={tablets} />
148
+ </div>
149
+
150
+ <div className={b('items')}>
151
+ <ReactList
152
+ itemRenderer={renderTablet}
153
+ length={tabletsToRender.length}
154
+ type="uniform"
155
+ />
156
+ </div>
157
+ </div>
158
+ );
159
+ };
160
+
161
+ if (loading && !wasLoaded) {
162
+ return <Loader />;
163
+ } else if (error) {
164
+ return <div className="error">{error.statusText}</div>;
165
+ } else {
166
+ return tablets.length > 0 ? (
167
+ renderContent()
168
+ ) : (
169
+ <div className="error">{i18n('noTabletsData')}</div>
170
+ );
171
+ }
172
+ };
@@ -0,0 +1,6 @@
1
+ {
2
+ "controls.type": "Type",
3
+ "controls.state": "State",
4
+ "controls.allItems": "All items",
5
+ "noTabletsData": "No tablets data"
6
+ }
@@ -3,7 +3,7 @@ import {i18n, Lang} from '../../../utils/i18n';
3
3
  import en from './en.json';
4
4
  import ru from './ru.json';
5
5
 
6
- const COMPONENT = 'ydb-embedded-ui';
6
+ const COMPONENT = 'ydb-tablets';
7
7
 
8
8
  i18n.registerKeyset(Lang.En, COMPONENT, en);
9
9
  i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
@@ -0,0 +1,6 @@
1
+ {
2
+ "controls.type": "Тип",
3
+ "controls.state": "Состояние",
4
+ "controls.allItems": "Все",
5
+ "noTabletsData": "Нет информации о таблетках"
6
+ }
@@ -0,0 +1 @@
1
+ export * from './Tablets';
@@ -11,7 +11,7 @@ import ReactList from 'react-list';
11
11
  import Tablet from '../../components/Tablet/Tablet';
12
12
  import {AccessDenied} from '../../components/Errors/403';
13
13
 
14
- import {TABLET_COLOR_TO_STATES, TABLETS_STATES} from '../../utils/constants';
14
+ import {tabletColorToTabletState, tabletStates} from '../../utils/tablet';
15
15
  import {showTooltip, hideTooltip} from '../../store/reducers/tooltip';
16
16
  import {
17
17
  getTabletsInfo,
@@ -61,7 +61,7 @@ class TabletsFilters extends React.Component {
61
61
  };
62
62
 
63
63
  static getStateFiltersFromColor = (color) => {
64
- return TABLET_COLOR_TO_STATES[color] || [color];
64
+ return tabletColorToTabletState[color] || [color];
65
65
  };
66
66
 
67
67
  static CONTROL_WIDTH = 220;
@@ -159,7 +159,7 @@ class TabletsFilters extends React.Component {
159
159
  const {nodeFilter, tenantPath} = this.state;
160
160
  const {tablets, filteredTablets, nodes, stateFilter, typeFilter, error} = this.props;
161
161
 
162
- const states = TABLETS_STATES.map((item) => ({value: item, content: item}));
162
+ const states = tabletStates.map((item) => ({value: item, content: item}));
163
163
  const types = Array.from(new Set(...[_.map(tablets, (tblt) => tblt.Type)])).map((item) => ({
164
164
  value: item,
165
165
  content: item,
@@ -243,8 +243,6 @@ const Filters = ({
243
243
  <Select
244
244
  multiple
245
245
  label="Node ID"
246
- showApply
247
- showItemMeta
248
246
  width={TabletsFilters.CONTROL_WIDTH}
249
247
  popupWidth={TabletsFilters.POPUP_WIDTH}
250
248
  placeholder="All"
@@ -255,7 +253,7 @@ const Filters = ({
255
253
  return (
256
254
  <div className={b('node')}>
257
255
  <div>{option.content}</div>
258
- <div className={b('node-meta')}>{option.meta}</div>
256
+ <div className={b('node-meta')} title={option.meta}>{option.meta}</div>
259
257
  </div>
260
258
  );
261
259
  }}
@@ -267,7 +265,6 @@ const Filters = ({
267
265
  <Select
268
266
  multiple
269
267
  label="multiple"
270
- showApply
271
268
  width={TabletsFilters.CONTROL_WIDTH}
272
269
  placeholder="All"
273
270
  options={states}
@@ -280,7 +277,6 @@ const Filters = ({
280
277
  <Select
281
278
  multiple
282
279
  label="Types"
283
- showApply
284
280
  width={TabletsFilters.CONTROL_WIDTH}
285
281
  placeholder="All"
286
282
  options={types}
@@ -6,14 +6,18 @@
6
6
  @include flex-container();
7
7
 
8
8
  &__node {
9
- display: flex;
10
- flex-direction: column;
9
+ overflow: hidden;
11
10
 
12
11
  font-size: var(--yc-text-body-1-font-size);
13
12
  line-height: var(--yc-text-body-1-line-height);
14
13
  }
15
14
 
16
15
  &__node-meta {
16
+ overflow: hidden;
17
+
18
+ white-space: nowrap;
19
+ text-overflow: ellipsis;
20
+
17
21
  color: var(--yc-color-text-secondary);
18
22
  }
19
23