ydb-embedded-ui 4.20.4 → 4.21.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/components/EmptyState/EmptyState.scss +0 -1
  3. package/dist/components/NodeHostWrapper/NodeHostWrapper.scss +2 -1
  4. package/dist/components/ProgressViewer/ProgressViewer.scss +1 -0
  5. package/dist/components/QueryResultTable/QueryResultTable.tsx +7 -3
  6. package/dist/components/TableWithControlsLayout/TableWithControlsLayout.scss +4 -0
  7. package/dist/components/VirtualTable/TableChunk.tsx +84 -0
  8. package/dist/components/VirtualTable/TableHead.tsx +139 -0
  9. package/dist/components/VirtualTable/TableRow.tsx +91 -0
  10. package/dist/components/VirtualTable/VirtualTable.scss +146 -0
  11. package/dist/components/VirtualTable/VirtualTable.tsx +277 -0
  12. package/dist/components/VirtualTable/constants.ts +17 -0
  13. package/dist/components/VirtualTable/i18n/en.json +3 -0
  14. package/dist/components/VirtualTable/i18n/index.ts +11 -0
  15. package/dist/components/VirtualTable/i18n/ru.json +3 -0
  16. package/dist/components/VirtualTable/index.ts +3 -0
  17. package/dist/components/VirtualTable/reducer.ts +143 -0
  18. package/dist/components/VirtualTable/shared.ts +3 -0
  19. package/dist/components/VirtualTable/types.ts +60 -0
  20. package/dist/components/VirtualTable/useIntersectionObserver.ts +42 -0
  21. package/dist/components/VirtualTable/utils.ts +3 -0
  22. package/dist/containers/App/App.scss +2 -1
  23. package/dist/containers/Cluster/Cluster.tsx +17 -4
  24. package/dist/containers/Node/Node.tsx +9 -17
  25. package/dist/containers/Node/NodeStructure/NodeStructure.tsx +8 -30
  26. package/dist/containers/Node/NodeStructure/Pdisk.tsx +29 -18
  27. package/dist/containers/Node/i18n/en.json +4 -0
  28. package/dist/containers/Node/i18n/index.ts +11 -0
  29. package/dist/containers/Node/i18n/ru.json +4 -0
  30. package/dist/containers/Nodes/Nodes.tsx +7 -28
  31. package/dist/containers/Nodes/VirtualNodes.tsx +146 -0
  32. package/dist/containers/Nodes/getNodes.ts +26 -0
  33. package/dist/containers/Nodes/getNodesColumns.tsx +49 -39
  34. package/dist/containers/Tablets/Tablets.tsx +3 -8
  35. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +0 -1
  36. package/dist/containers/UserSettings/i18n/en.json +4 -4
  37. package/dist/containers/UserSettings/i18n/ru.json +4 -4
  38. package/dist/containers/UserSettings/settings.ts +5 -6
  39. package/dist/store/reducers/nodes/nodes.ts +2 -2
  40. package/dist/store/reducers/nodes/types.ts +1 -0
  41. package/dist/store/reducers/settings/settings.ts +3 -3
  42. package/dist/utils/developerUI.ts +32 -0
  43. package/dist/utils/hooks/useNodesRequestParams.ts +4 -8
  44. package/dist/utils/nodes.ts +12 -0
  45. package/dist/utils/query.ts +8 -1
  46. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
- import DataTable, {type Column} from '@gravity-ui/react-data-table';
1
+ import DataTable, {type Column as DataTableColumn} from '@gravity-ui/react-data-table';
2
2
 
3
+ import type {Column as VirtualTableColumn} from '../../components/VirtualTable';
3
4
  import {PoolsGraph} from '../../components/PoolsGraph/PoolsGraph';
4
5
  import {ProgressViewer} from '../../components/ProgressViewer/ProgressViewer';
5
6
  import {TabletsStatistic} from '../../components/TabletsStatistic';
@@ -34,46 +35,52 @@ interface GetNodesColumnsProps {
34
35
  getNodeRef?: GetNodeRefFunc;
35
36
  }
36
37
 
37
- const nodeIdColumn: Column<NodesPreparedEntity> = {
38
+ type NodesColumn = VirtualTableColumn<NodesPreparedEntity> & DataTableColumn<NodesPreparedEntity>;
39
+
40
+ const nodeIdColumn: NodesColumn = {
38
41
  name: NODES_COLUMNS_IDS.NodeId,
39
42
  header: '#',
40
- width: '80px',
43
+ width: 80,
44
+ render: ({row}) => row.NodeId,
41
45
  align: DataTable.RIGHT,
42
46
  sortable: false,
43
47
  };
44
48
 
45
- const getHostColumn = (
46
- getNodeRef?: GetNodeRefFunc,
47
- fixedWidth = false,
48
- ): Column<NodesPreparedEntity> => ({
49
+ const getHostColumn = (getNodeRef?: GetNodeRefFunc): NodesColumn => ({
49
50
  name: NODES_COLUMNS_IDS.Host,
50
51
  render: ({row}) => {
51
52
  return <NodeHostWrapper node={row} getNodeRef={getNodeRef} />;
52
53
  },
53
- width: fixedWidth ? '350px' : undefined,
54
+ width: 350,
54
55
  align: DataTable.LEFT,
55
56
  sortable: false,
56
57
  });
57
58
 
58
- const dataCenterColumn: Column<NodesPreparedEntity> = {
59
+ const getHostColumnWithUndefinedWidth = (
60
+ getNodeRef?: GetNodeRefFunc,
61
+ ): DataTableColumn<NodesPreparedEntity> => {
62
+ return {...getHostColumn(getNodeRef), width: undefined};
63
+ };
64
+
65
+ const dataCenterColumn: NodesColumn = {
59
66
  name: NODES_COLUMNS_IDS.DC,
60
67
  header: 'DC',
61
68
  align: DataTable.LEFT,
62
69
  render: ({row}) => (row.DataCenter ? row.DataCenter : '—'),
63
- width: '60px',
70
+ width: 60,
64
71
  };
65
72
 
66
- const rackColumn: Column<NodesPreparedEntity> = {
73
+ const rackColumn: NodesColumn = {
67
74
  name: NODES_COLUMNS_IDS.Rack,
68
75
  header: 'Rack',
69
76
  align: DataTable.LEFT,
70
77
  render: ({row}) => (row.Rack ? row.Rack : '—'),
71
- width: '80px',
78
+ width: 80,
72
79
  };
73
80
 
74
- const versionColumn: Column<NodesPreparedEntity> = {
81
+ const versionColumn: NodesColumn = {
75
82
  name: NODES_COLUMNS_IDS.Version,
76
- width: '200px',
83
+ width: 200,
77
84
  align: DataTable.LEFT,
78
85
  render: ({row}) => {
79
86
  return <CellWithPopover content={row.Version}>{row.Version}</CellWithPopover>;
@@ -81,16 +88,17 @@ const versionColumn: Column<NodesPreparedEntity> = {
81
88
  sortable: false,
82
89
  };
83
90
 
84
- const uptimeColumn: Column<NodesPreparedEntity> = {
91
+ const uptimeColumn: NodesColumn = {
85
92
  name: NODES_COLUMNS_IDS.Uptime,
86
93
  header: 'Uptime',
87
94
  sortAccessor: ({StartTime}) => StartTime && -StartTime,
95
+ render: ({row}) => row.Uptime,
88
96
  align: DataTable.RIGHT,
89
- width: '110px',
97
+ width: 110,
90
98
  sortable: false,
91
99
  };
92
100
 
93
- const memoryColumn: Column<NodesPreparedEntity> = {
101
+ const memoryColumn: NodesColumn = {
94
102
  name: NODES_COLUMNS_IDS.Memory,
95
103
  header: 'Memory',
96
104
  sortAccessor: ({MemoryUsed = 0}) => Number(MemoryUsed),
@@ -103,21 +111,21 @@ const memoryColumn: Column<NodesPreparedEntity> = {
103
111
  }
104
112
  },
105
113
  align: DataTable.RIGHT,
106
- width: '120px',
114
+ width: 120,
107
115
  };
108
116
 
109
- const cpuColumn: Column<NodesPreparedEntity> = {
117
+ const cpuColumn: NodesColumn = {
110
118
  name: NODES_COLUMNS_IDS.CPU,
111
119
  header: 'CPU',
112
120
  sortAccessor: ({PoolStats = []}) => Math.max(...PoolStats.map(({Usage}) => Number(Usage))),
113
121
  defaultOrder: DataTable.DESCENDING,
114
122
  render: ({row}) => (row.PoolStats ? <PoolsGraph pools={row.PoolStats} /> : '—'),
115
123
  align: DataTable.LEFT,
116
- width: '80px',
124
+ width: 80,
117
125
  sortable: false,
118
126
  };
119
127
 
120
- const loadAverageColumn: Column<NodesPreparedEntity> = {
128
+ const loadAverageColumn: NodesColumn = {
121
129
  name: NODES_COLUMNS_IDS.LoadAverage,
122
130
  header: 'Load average',
123
131
  sortAccessor: ({LoadAverage = []}) =>
@@ -135,13 +143,13 @@ const loadAverageColumn: Column<NodesPreparedEntity> = {
135
143
  '—'
136
144
  ),
137
145
  align: DataTable.LEFT,
138
- width: '140px',
146
+ width: 140,
139
147
  sortable: false,
140
148
  };
141
149
 
142
- const getTabletsColumn = (tabletsPath?: string): Column<NodesPreparedEntity> => ({
150
+ const getTabletsColumn = (tabletsPath?: string): NodesColumn => ({
143
151
  name: NODES_COLUMNS_IDS.Tablets,
144
- width: '430px',
152
+ width: 430,
145
153
  render: ({row}) => {
146
154
  return row.Tablets ? (
147
155
  <TabletsStatistic
@@ -157,7 +165,7 @@ const getTabletsColumn = (tabletsPath?: string): Column<NodesPreparedEntity> =>
157
165
  sortable: false,
158
166
  });
159
167
 
160
- const topNodesLoadAverageColumn: Column<NodesPreparedEntity> = {
168
+ const topNodesLoadAverageColumn: NodesColumn = {
161
169
  name: NODES_COLUMNS_IDS.TopNodesLoadAverage,
162
170
  header: 'Load',
163
171
  render: ({row}) =>
@@ -170,11 +178,11 @@ const topNodesLoadAverageColumn: Column<NodesPreparedEntity> = {
170
178
  '—'
171
179
  ),
172
180
  align: DataTable.LEFT,
173
- width: '80px',
181
+ width: 80,
174
182
  sortable: false,
175
183
  };
176
184
 
177
- const topNodesMemoryColumn: Column<NodesPreparedEntity> = {
185
+ const topNodesMemoryColumn: NodesColumn = {
178
186
  name: NODES_COLUMNS_IDS.TopNodesMemory,
179
187
  header: 'Memory',
180
188
  render: ({row}) =>
@@ -189,17 +197,14 @@ const topNodesMemoryColumn: Column<NodesPreparedEntity> = {
189
197
  '—'
190
198
  ),
191
199
  align: DataTable.LEFT,
192
- width: '140px',
200
+ width: 140,
193
201
  sortable: false,
194
202
  };
195
203
 
196
- export function getNodesColumns({
197
- tabletsPath,
198
- getNodeRef,
199
- }: GetNodesColumnsProps): Column<NodesPreparedEntity>[] {
204
+ export function getNodesColumns({tabletsPath, getNodeRef}: GetNodesColumnsProps): NodesColumn[] {
200
205
  return [
201
206
  nodeIdColumn,
202
- getHostColumn(getNodeRef, true),
207
+ getHostColumn(getNodeRef),
203
208
  dataCenterColumn,
204
209
  rackColumn,
205
210
  versionColumn,
@@ -213,23 +218,28 @@ export function getNodesColumns({
213
218
 
214
219
  export function getTopNodesByLoadColumns(
215
220
  getNodeRef?: GetNodeRefFunc,
216
- ): Column<NodesPreparedEntity>[] {
217
- return [topNodesLoadAverageColumn, nodeIdColumn, getHostColumn(getNodeRef), versionColumn];
221
+ ): DataTableColumn<NodesPreparedEntity>[] {
222
+ return [
223
+ topNodesLoadAverageColumn,
224
+ nodeIdColumn,
225
+ getHostColumnWithUndefinedWidth(getNodeRef),
226
+ versionColumn,
227
+ ];
218
228
  }
219
229
 
220
230
  export function getTopNodesByCpuColumns(
221
231
  getNodeRef?: GetNodeRefFunc,
222
- ): Column<NodesPreparedEntity>[] {
223
- return [cpuColumn, nodeIdColumn, getHostColumn(getNodeRef)];
232
+ ): DataTableColumn<NodesPreparedEntity>[] {
233
+ return [cpuColumn, nodeIdColumn, getHostColumnWithUndefinedWidth(getNodeRef)];
224
234
  }
225
235
 
226
236
  export function getTopNodesByMemoryColumns({
227
237
  tabletsPath,
228
238
  getNodeRef,
229
- }: GetNodesColumnsProps): Column<NodesPreparedEntity>[] {
239
+ }: GetNodesColumnsProps): NodesColumn[] {
230
240
  return [
231
241
  nodeIdColumn,
232
- getHostColumn(getNodeRef, true),
242
+ getHostColumn(getNodeRef),
233
243
  uptimeColumn,
234
244
  topNodesMemoryColumn,
235
245
  topNodesLoadAverageColumn,
@@ -34,14 +34,9 @@ interface TabletsProps {
34
34
  export const Tablets = ({path, nodeId, className}: TabletsProps) => {
35
35
  const dispatch = useDispatch();
36
36
 
37
- const {
38
- data = {},
39
- wasLoaded,
40
- loading,
41
- error,
42
- stateFilter,
43
- typeFilter,
44
- } = useTypedSelector((state) => state.tablets);
37
+ const {data, wasLoaded, loading, error, stateFilter, typeFilter} = useTypedSelector(
38
+ (state) => state.tablets,
39
+ );
45
40
  const {autorefresh} = useTypedSelector((state) => state.schema);
46
41
 
47
42
  const tablets = useMemo(() => data?.TabletStateInfo || [], [data]);
@@ -123,7 +123,6 @@ function Diagnostics(props: DiagnosticsProps) {
123
123
  return (
124
124
  <Nodes
125
125
  path={currentSchemaPath}
126
- type={type}
127
126
  additionalNodesProps={props.additionalNodesProps}
128
127
  />
129
128
  );
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "page.general": "General",
3
- "section.general": "General",
3
+ "section.appearance": "Appearance",
4
4
 
5
5
  "page.experiments": "Experiments",
6
6
  "section.experiments": "Experiments",
@@ -17,10 +17,10 @@
17
17
  "settings.invertedDisks.title": "Inverted disks space indicators",
18
18
 
19
19
  "settings.useNodesEndpoint.title": "Break the Nodes tab in Diagnostics",
20
- "settings.useNodesEndpoint.popover": "Use /viewer/json/nodes endpoint for Nodes Tab in diagnostics. It returns incorrect data on versions before 23-1",
20
+ "settings.useNodesEndpoint.popover": "Use /viewer/json/nodes endpoint for Nodes Tab in diagnostics. It could return incorrect data on some versions",
21
21
 
22
- "settings.useBackendParamsForTables.title": "Offload tables filters and sorting to backend",
23
- "settings.useBackendParamsForTables.popover": "Filter and sort Nodes and Storage tables with request params. May increase performance, but could causes additional fetches and longer loading time on older versions",
22
+ "settings.useBackendParamsForTables.title": "Use virtual table for cluster Nodes tab",
23
+ "settings.useBackendParamsForTables.popover": "Use table with data load on scroll. It will increase performance, but could work unstable",
24
24
 
25
25
  "settings.enableAdditionalQueryModes.title": "Enable additional query modes",
26
26
  "settings.enableAdditionalQueryModes.popover": "Adds 'Data', 'YQL - QueryService' and 'PostgreSQL' modes. May not work on some versions",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "page.general": "Общие",
3
- "section.general": "Общие",
3
+ "section.appearance": "Внешний вид",
4
4
 
5
5
  "page.experiments": "Эксперименты",
6
6
  "section.experiments": "Эксперименты",
@@ -17,10 +17,10 @@
17
17
  "settings.invertedDisks.title": "Инвертированные индикаторы места на дисках",
18
18
 
19
19
  "settings.useNodesEndpoint.title": "Сломать вкладку Nodes в диагностике",
20
- "settings.useNodesEndpoint.popover": "Использовать эндпоинт /viewer/json/nodes для вкладки Nodes в диагностике. Может возвращать некорректные данные на версиях до 23-1",
20
+ "settings.useNodesEndpoint.popover": "Использовать эндпоинт /viewer/json/nodes для вкладки Nodes в диагностике. Может возвращать некорректные данные на некоторых версиях",
21
21
 
22
- "settings.useBackendParamsForTables.title": "Перенести фильтры и сортировку таблиц на бэкенд",
23
- "settings.useBackendParamsForTables.popover": "Добавляет фильтрацию и сортировку таблиц Nodes и Storage с использованием параметров запроса. Может улушить производительность, но на старых версиях может привести к дополнительным запросам и большему времени ожидания загрузки",
22
+ "settings.useBackendParamsForTables.title": "Использовать виртуализированную таблицу для вкладки Nodes кластера",
23
+ "settings.useBackendParamsForTables.popover": "Использовать таблицу с загрузкой данных по скроллу. Это улучшит производительность, но может работать нестабильно",
24
24
 
25
25
  "settings.enableAdditionalQueryModes.title": "Включить дополнительные режимы выполнения запросов",
26
26
  "settings.enableAdditionalQueryModes.popover": "Добавляет режимы 'Data', 'YQL - QueryService' и 'PostgreSQL'. Может работать некорректно на некоторых версиях",
@@ -101,16 +101,15 @@ export const enableNewTenantDiagnosticsDesign: SettingProps = {
101
101
  helpPopoverContent: i18n('settings.tenantDiagnostics.popover'),
102
102
  };
103
103
 
104
- export const generalSection: SettingsSection = {
105
- id: 'generalSection',
106
- title: i18n('section.general'),
107
- settings: [themeSetting],
104
+ export const appearanceSection: SettingsSection = {
105
+ id: 'appearanceSection',
106
+ title: i18n('section.appearance'),
107
+ settings: [themeSetting, invertedDisksSetting],
108
108
  };
109
109
  export const experimentsSection: SettingsSection = {
110
110
  id: 'experimentsSection',
111
111
  title: i18n('section.experiments'),
112
112
  settings: [
113
- invertedDisksSetting,
114
113
  useNodesEndpointSetting,
115
114
  useBackendParamsForTables,
116
115
  enableQueryModesForExplainSetting,
@@ -122,7 +121,7 @@ export const generalPage: SettingsPage = {
122
121
  id: 'generalPage',
123
122
  title: i18n('page.general'),
124
123
  icon: {data: favoriteFilledIcon, height: 14, width: 14},
125
- sections: [generalSection],
124
+ sections: [appearanceSection],
126
125
  };
127
126
  export const experimentsPage: SettingsPage = {
128
127
  id: 'experimentsPage',
@@ -99,9 +99,9 @@ const nodes: Reducer<NodesState, NodesAction> = (state = initialState, action) =
99
99
  };
100
100
  const concurrentId = 'getNodes';
101
101
 
102
- export function getNodes({type = 'any', ...params}: NodesApiRequestParams) {
102
+ export function getNodes({type = 'any', storage = false, ...params}: NodesApiRequestParams) {
103
103
  return createApiRequest({
104
- request: window.api.getNodes({type, ...params}, {concurrentId}),
104
+ request: window.api.getNodes({type, storage, ...params}, {concurrentId}),
105
105
  actions: FETCH_NODES,
106
106
  dataHandler: prepareNodesData,
107
107
  });
@@ -70,6 +70,7 @@ export interface NodesGeneralRequestParams extends NodesSortParams {
70
70
  }
71
71
 
72
72
  export interface NodesApiRequestParams extends NodesGeneralRequestParams {
73
+ path?: string;
73
74
  tenant?: string;
74
75
  type?: NodeType;
75
76
  visibleEntities?: VisibleEntities; // "with" param
@@ -50,15 +50,15 @@ export const initialState = {
50
50
  [INVERTED_DISKS_KEY]: readSavedSettingsValue(INVERTED_DISKS_KEY, 'false'),
51
51
  [USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY]: readSavedSettingsValue(
52
52
  USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
53
- 'true',
53
+ 'false',
54
54
  ),
55
55
  [ENABLE_ADDITIONAL_QUERY_MODES]: readSavedSettingsValue(
56
56
  ENABLE_ADDITIONAL_QUERY_MODES,
57
- 'false',
57
+ 'true',
58
58
  ),
59
59
  [DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS]: readSavedSettingsValue(
60
60
  DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS,
61
- 'false',
61
+ 'true',
62
62
  ),
63
63
  [SAVED_QUERIES_KEY]: readSavedSettingsValue(SAVED_QUERIES_KEY, '[]'),
64
64
  [TENANT_INITIAL_PAGE_KEY]: readSavedSettingsValue(
@@ -0,0 +1,32 @@
1
+ import {backend} from '../store';
2
+ import {pad9} from './utils';
3
+
4
+ // Current node connects with target node by itself using nodeId
5
+ export const createDeveloperUILinkWithNodeId = (nodeId: number | string) => {
6
+ return `${backend}/node/${nodeId}/`;
7
+ };
8
+
9
+ interface PDiskDeveloperUILinkParams {
10
+ nodeId: number | string;
11
+ pDiskId: number | string;
12
+ }
13
+
14
+ export const createPDiskDeveloperUILink = ({nodeId, pDiskId}: PDiskDeveloperUILinkParams) => {
15
+ const pdiskPath = 'actors/pdisks/pdisk' + pad9(pDiskId);
16
+
17
+ return createDeveloperUILinkWithNodeId(nodeId) + pdiskPath;
18
+ };
19
+
20
+ interface VDiskDeveloperUILinkParams extends PDiskDeveloperUILinkParams {
21
+ vDiskSlotId: number | string;
22
+ }
23
+
24
+ export const createVDiskDeveloperUILink = ({
25
+ nodeId,
26
+ pDiskId,
27
+ vDiskSlotId,
28
+ }: VDiskDeveloperUILinkParams) => {
29
+ const vdiskPath = 'actors/vdisks/vdisk' + pad9(pDiskId) + '_' + pad9(vDiskSlotId);
30
+
31
+ return createDeveloperUILinkWithNodeId(nodeId) + vdiskPath;
32
+ };
@@ -2,10 +2,9 @@ import {useMemo} from 'react';
2
2
 
3
3
  import type {NodesGeneralRequestParams} from '../../store/reducers/nodes/types';
4
4
  import type {ProblemFilterValue} from '../../store/reducers/settings/types';
5
- import {ProblemFilterValues} from '../../store/reducers/settings/settings';
6
5
 
7
- import {HOUR_IN_SECONDS, USE_BACKEND_PARAMS_FOR_TABLES_KEY} from '../constants';
8
- import {NodesUptimeFilterValues} from '../nodes';
6
+ import {USE_BACKEND_PARAMS_FOR_TABLES_KEY} from '../constants';
7
+ import {NodesUptimeFilterValues, getProblemParamValue, getUptimeParamValue} from '../nodes';
9
8
  import {useSetting} from './useSetting';
10
9
 
11
10
  interface NodesRawRequestParams
@@ -27,11 +26,8 @@ export const useNodesRequestParams = ({
27
26
  // Otherwise no params will be updated, no hooks that depend on requestParams will be triggered
28
27
  return useMemo(() => {
29
28
  if (useBackendParamsForTables) {
30
- const problemsOnly = problemFilter === ProblemFilterValues.PROBLEMS;
31
- const uptime =
32
- nodesUptimeFilter === NodesUptimeFilterValues.SmallUptime
33
- ? HOUR_IN_SECONDS
34
- : undefined;
29
+ const problemsOnly = getProblemParamValue(problemFilter);
30
+ const uptime = getUptimeParamValue(nodesUptimeFilter);
35
31
 
36
32
  return {
37
33
  filter,
@@ -3,8 +3,12 @@ import type {TNodeInfo} from '../types/api/nodesList';
3
3
  import type {NodesPreparedEntity} from '../store/reducers/nodes/types';
4
4
  import type {NodesMap} from '../types/store/nodesList';
5
5
  import type {ValueOf} from '../types/common';
6
+ import type {ProblemFilterValue} from '../store/reducers/settings/types';
7
+ import {ProblemFilterValues} from '../store/reducers/settings/settings';
6
8
  import {EFlag} from '../types/api/enums';
7
9
 
10
+ import {HOUR_IN_SECONDS} from './constants';
11
+
8
12
  export enum NodesUptimeFilterValues {
9
13
  'All' = 'All',
10
14
  'SmallUptime' = 'SmallUptime',
@@ -27,6 +31,14 @@ export const prepareNodesMap = (nodesList?: TNodeInfo[]) => {
27
31
  }, new Map());
28
32
  };
29
33
 
34
+ export const getProblemParamValue = (problemFilter: ProblemFilterValue | undefined) => {
35
+ return problemFilter === ProblemFilterValues.PROBLEMS;
36
+ };
37
+
38
+ export const getUptimeParamValue = (nodesUptimeFilter: NodesUptimeFilterValues | undefined) => {
39
+ return nodesUptimeFilter === NodesUptimeFilterValues.SmallUptime ? HOUR_IN_SECONDS : undefined;
40
+ };
41
+
30
42
  /**
31
43
  * Values to sort /compute v2 and /nodes responses
32
44
  *
@@ -175,7 +175,14 @@ export const prepareQueryResponse = (data?: KeyValueRow[]) => {
175
175
  for (const field in row) {
176
176
  if (Object.prototype.hasOwnProperty.call(row, field)) {
177
177
  const type = typeof row[field];
178
- if (type === 'object' || type === 'boolean' || Array.isArray(row[field])) {
178
+
179
+ // Although typeof null == 'object'
180
+ // null result should be preserved
181
+ if (
182
+ (row[field] !== null && type === 'object') ||
183
+ type === 'boolean' ||
184
+ Array.isArray(row[field])
185
+ ) {
179
186
  formattedData[field] = JSON.stringify(row[field]);
180
187
  } else {
181
188
  formattedData[field] = row[field];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "4.20.4",
3
+ "version": "4.21.1",
4
4
  "files": [
5
5
  "dist"
6
6
  ],