ydb-embedded-ui 4.21.1 → 4.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/ProgressViewer/ProgressViewer.tsx +1 -1
  3. package/dist/components/VirtualTable/TableChunk.tsx +2 -1
  4. package/dist/components/VirtualTable/VirtualTable.tsx +1 -1
  5. package/dist/containers/Cluster/Cluster.tsx +2 -0
  6. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +14 -5
  7. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +104 -24
  8. package/dist/containers/Cluster/ClusterInfoSkeleton/ClusterInfoSkeleton.tsx +1 -1
  9. package/dist/containers/Cluster/i18n/en.json +16 -0
  10. package/dist/containers/Cluster/i18n/index.ts +11 -0
  11. package/dist/containers/Cluster/i18n/ru.json +16 -0
  12. package/dist/containers/Node/NodeStructure/Pdisk.tsx +4 -1
  13. package/dist/containers/Nodes/getNodesColumns.tsx +57 -13
  14. package/dist/containers/Tenant/Diagnostics/Network/Network.js +5 -10
  15. package/dist/containers/Tenant/Diagnostics/Network/utils.ts +6 -0
  16. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx +18 -3
  17. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx +18 -3
  18. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx +17 -1
  19. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx +20 -1
  20. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx +18 -3
  21. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx +2 -1
  22. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx +19 -2
  23. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx +8 -1
  24. package/dist/containers/Tenant/Diagnostics/TenantOverview/getSectionTitle.tsx +28 -0
  25. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +17 -1
  26. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +17 -1
  27. package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.scss +13 -5
  28. package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.tsx +72 -18
  29. package/dist/containers/Tenant/Query/ExplainResult/ExplainResult.js +2 -1
  30. package/dist/containers/Tenant/Query/ExplainResult/utils.ts +6 -0
  31. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +11 -24
  32. package/dist/containers/Tenant/Query/utils/getPreparedResult.ts +4 -5
  33. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.tsx +19 -11
  34. package/dist/containers/UserSettings/i18n/en.json +3 -0
  35. package/dist/containers/UserSettings/i18n/ru.json +3 -0
  36. package/dist/containers/UserSettings/settings.ts +7 -0
  37. package/dist/store/reducers/cluster/__test__/parseGroupsStatsQueryResponse.test.ts +121 -0
  38. package/dist/store/reducers/cluster/cluster.ts +46 -2
  39. package/dist/store/reducers/cluster/types.ts +29 -4
  40. package/dist/store/reducers/cluster/utils.ts +88 -0
  41. package/dist/store/reducers/executeQuery.ts +4 -3
  42. package/dist/store/reducers/nodes/types.ts +11 -1
  43. package/dist/store/reducers/nodes/utils.ts +6 -0
  44. package/dist/store/reducers/settings/settings.ts +2 -0
  45. package/dist/types/api/cluster.ts +3 -0
  46. package/dist/types/api/netInfo.ts +1 -1
  47. package/dist/types/api/nodes.ts +24 -0
  48. package/dist/types/api/query.ts +23 -8
  49. package/dist/types/store/query.ts +6 -0
  50. package/dist/utils/constants.ts +3 -0
  51. package/dist/utils/developerUI/__test__/developerUI.test.ts +50 -0
  52. package/dist/utils/developerUI/developerUI.ts +42 -0
  53. package/dist/utils/diagnostics.ts +1 -0
  54. package/dist/utils/hooks/index.ts +1 -0
  55. package/dist/utils/hooks/useSearchQuery.ts +9 -0
  56. package/dist/utils/query.ts +60 -12
  57. package/package.json +1 -1
  58. package/dist/utils/developerUI.ts +0 -32
  59. package/dist/utils/index.js +0 -9
  60. /package/dist/{components/VirtualTable/utils.ts → utils/index.ts} +0 -0
@@ -26,6 +26,9 @@ export interface TNodeInfo {
26
26
  Tablets?: TTabletStateInfo[];
27
27
  }
28
28
 
29
+ /**
30
+ * source: https://github.com/ydb-platform/ydb/blob/main/ydb/core/protos/node_whiteboard.proto
31
+ */
29
32
  export interface TSystemStateInfo {
30
33
  /** uint64 */
31
34
  StartTime?: string;
@@ -62,6 +65,20 @@ export interface TSystemStateInfo {
62
65
  /** double */
63
66
  MaxDiskUsage?: number;
64
67
  Location?: TNodeLocation;
68
+
69
+ /**
70
+ * int64
71
+ *
72
+ * a positive value means the peer is ahead in time; a negative value means it's behind
73
+ */
74
+ MaxClockSkewWithPeerUs?: string;
75
+ MaxClockSkewPeerId?: number;
76
+
77
+ /** uint64 */
78
+ DisconnectTime?: string;
79
+
80
+ SharedCacheStats?: TNodeSharedCache;
81
+ TotalSessions?: number;
65
82
  }
66
83
 
67
84
  export interface TPoolStats {
@@ -97,6 +114,13 @@ interface TNodeLocation {
97
114
  Unit?: string;
98
115
  }
99
116
 
117
+ interface TNodeSharedCache {
118
+ /** uint64 */
119
+ UsedBytes: string;
120
+ /** uint64 */
121
+ LimitBytes: string;
122
+ }
123
+
100
124
  enum EConfigState {
101
125
  'Consistent' = 'Consistent',
102
126
  'Outdated' = 'Outdated',
@@ -180,7 +180,7 @@ export interface ColumnType {
180
180
  }
181
181
 
182
182
  /** undefined = 'classic' */
183
- export type Schemas = 'classic' | 'modern' | 'ydb' | undefined;
183
+ export type Schemas = 'classic' | 'modern' | 'ydb' | 'multi' | undefined;
184
184
 
185
185
  /** undefined = 'execute' */
186
186
  export type ExecuteActions =
@@ -231,16 +231,29 @@ export type ExplainResponse<Action extends ExplainActions> = Action extends 'exp
231
231
  ? ExplainScriptResponse
232
232
  : ExplainQueryResponse;
233
233
 
234
+ // ==== Execute Results ====
235
+
236
+ interface ModernSchemaResult {
237
+ result?: ArrayRow[];
238
+ columns?: ColumnType[];
239
+ }
240
+ interface MultiSchemaResult {
241
+ result?: {
242
+ rows?: ArrayRow[] | null;
243
+ columns?: ColumnType[];
244
+ }[];
245
+ }
246
+ interface DefaultSchemaResult {
247
+ result?: KeyValueRow[];
248
+ }
249
+
234
250
  // ==== Execute Responses ====
235
251
 
236
252
  type ResultFields<Schema extends Schemas> = Schema extends 'modern'
237
- ? {
238
- result?: ArrayRow[];
239
- columns?: ColumnType[];
240
- }
241
- : {
242
- result?: KeyValueRow[];
243
- };
253
+ ? ModernSchemaResult
254
+ : Schema extends 'multi'
255
+ ? MultiSchemaResult
256
+ : DefaultSchemaResult;
244
257
 
245
258
  /**
246
259
  * meta.type = 'query'
@@ -287,6 +300,7 @@ export type AnyExplainResponse = ExplainQueryResponse | ExplainScriptResponse;
287
300
  export type ExecuteModernResponse =
288
301
  | ExecuteQueryResponse<'modern'>
289
302
  | ExecuteScriptResponse<'modern'>;
303
+ export type ExecuteMultiResponse = ExecuteQueryResponse<'multi'> | ExecuteScriptResponse<'multi'>;
290
304
  export type ExecuteClassicResponse =
291
305
  | ExecuteQueryResponse<'classic'>
292
306
  | ExecuteScriptResponse<'classic'>;
@@ -294,5 +308,6 @@ export type ExecuteYdbResponse = ExecuteQueryResponse<'ydb'> | ExecuteScriptResp
294
308
 
295
309
  export type AnyExecuteResponse =
296
310
  | ExecuteModernResponse
311
+ | ExecuteMultiResponse
297
312
  | ExecuteClassicResponse
298
313
  | ExecuteYdbResponse;
@@ -11,7 +11,13 @@ import type {
11
11
  } from '../api/query';
12
12
  import type {ValueOf} from '../common';
13
13
 
14
+ export interface ParsedResultSet {
15
+ columns?: ColumnType[];
16
+ result?: KeyValueRow[];
17
+ }
18
+
14
19
  export interface IQueryResult {
20
+ resultSets?: ParsedResultSet[];
15
21
  result?: KeyValueRow[];
16
22
  columns?: ColumnType[];
17
23
  stats?: TKqpStatsQuery;
@@ -133,3 +133,6 @@ export const TENANT_INITIAL_PAGE_KEY = 'saved_tenant_initial_tab';
133
133
 
134
134
  // Send filters and sort params to backend for Nodes and Storage tables
135
135
  export const USE_BACKEND_PARAMS_FOR_TABLES_KEY = 'useBackendParamsForTables';
136
+
137
+ // Enable schema that supports multiple resultsets
138
+ export const QUERY_USE_MULTI_SCHEMA_KEY = 'queryUseMultiSchema';
@@ -0,0 +1,50 @@
1
+ import {
2
+ createDeveloperUILinkWithNodeId,
3
+ createPDiskDeveloperUILink,
4
+ createVDiskDeveloperUILink,
5
+ } from '../developerUI';
6
+
7
+ describe('Developer UI links generators', () => {
8
+ describe('createDeveloperUILinkWithNodeId', () => {
9
+ it('should create relative link with no host', () => {
10
+ expect(createDeveloperUILinkWithNodeId(1)).toBe('/node/1/');
11
+ });
12
+ it('should create relative link with existing relative path with nodeId', () => {
13
+ expect(createDeveloperUILinkWithNodeId(1, '/node/3/')).toBe('/node/1/');
14
+ });
15
+ it('should create full link with host', () => {
16
+ expect(
17
+ createDeveloperUILinkWithNodeId(
18
+ 1,
19
+ 'http://ydb-vla-dev02-001.search.yandex.net:8765',
20
+ ),
21
+ ).toBe('http://ydb-vla-dev02-001.search.yandex.net:8765/node/1/');
22
+ });
23
+ it('should create full link with host with existing node path with nodeId', () => {
24
+ expect(
25
+ createDeveloperUILinkWithNodeId(
26
+ 1,
27
+ 'http://ydb-vla-dev02-001.search.yandex.net:8765/node/3',
28
+ ),
29
+ ).toBe('http://ydb-vla-dev02-001.search.yandex.net:8765/node/1/');
30
+ });
31
+ });
32
+ describe('createPDiskDeveloperUILink', () => {
33
+ it('should create link with pDiskId and nodeId', () => {
34
+ expect(createPDiskDeveloperUILink({nodeId: 1, pDiskId: 1})).toBe(
35
+ '/node/1/actors/pdisks/pdisk000000001',
36
+ );
37
+ });
38
+ });
39
+ describe('createVDiskDeveloperUILink', () => {
40
+ it('should create link with pDiskId, vDiskSlotId nodeId', () => {
41
+ expect(
42
+ createVDiskDeveloperUILink({
43
+ nodeId: 1,
44
+ pDiskId: 1,
45
+ vDiskSlotId: 1,
46
+ }),
47
+ ).toBe('/node/1/actors/vdisks/vdisk000000001_000000001');
48
+ });
49
+ });
50
+ });
@@ -0,0 +1,42 @@
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, host = backend) => {
6
+ const nodePathRegexp = /\/node\/\d+\/?$/g;
7
+
8
+ // In case current backend is already relative node path ({host}/node/{nodeId})
9
+ // We replace existing nodeId path with new nodeId path
10
+ if (nodePathRegexp.test(String(host))) {
11
+ return String(host).replace(nodePathRegexp, `/node/${nodeId}/`);
12
+ }
13
+
14
+ return `${host ?? ''}/node/${nodeId}/`;
15
+ };
16
+
17
+ interface PDiskDeveloperUILinkParams {
18
+ nodeId: number | string;
19
+ pDiskId: number | string;
20
+ host?: string;
21
+ }
22
+
23
+ export const createPDiskDeveloperUILink = ({nodeId, pDiskId, host}: PDiskDeveloperUILinkParams) => {
24
+ const pdiskPath = 'actors/pdisks/pdisk' + pad9(pDiskId);
25
+
26
+ return createDeveloperUILinkWithNodeId(nodeId, host) + pdiskPath;
27
+ };
28
+
29
+ interface VDiskDeveloperUILinkParams extends PDiskDeveloperUILinkParams {
30
+ vDiskSlotId: number | string;
31
+ }
32
+
33
+ export const createVDiskDeveloperUILink = ({
34
+ nodeId,
35
+ pDiskId,
36
+ vDiskSlotId,
37
+ host,
38
+ }: VDiskDeveloperUILinkParams) => {
39
+ const vdiskPath = 'actors/vdisks/vdisk' + pad9(pDiskId) + '_' + pad9(vDiskSlotId);
40
+
41
+ return createDeveloperUILinkWithNodeId(nodeId, host) + vdiskPath;
42
+ };
@@ -3,6 +3,7 @@ import {ValueOf} from '../types/common';
3
3
  const TOP_SHARDS_SORT_VALUES = {
4
4
  CPUCores: 'CPUCores',
5
5
  DataSize: 'DataSize',
6
+ InFlightTxCount: 'InFlightTxCount',
6
7
  } as const;
7
8
 
8
9
  const TOP_QUERIES_SORT_VALUES = {
@@ -3,6 +3,7 @@ export * from './useTypedSelector';
3
3
  export * from './useSetting';
4
4
  export * from './useQueryModes';
5
5
  export * from './useTableSort';
6
+ export * from './useSearchQuery';
6
7
 
7
8
  export * from './useNodesRequestParams';
8
9
  export * from './useStorageRequestParams';
@@ -0,0 +1,9 @@
1
+ import {useLocation} from 'react-router';
2
+
3
+ import {parseQuery} from '../../routes';
4
+
5
+ export const useSearchQuery = () => {
6
+ const location = useLocation();
7
+
8
+ return parseQuery(location);
9
+ };
@@ -2,7 +2,10 @@ import {YQLType} from '../types';
2
2
  import type {
3
3
  AnyExecuteResponse,
4
4
  AnyExplainResponse,
5
+ ArrayRow,
6
+ ColumnType,
5
7
  ExecuteModernResponse,
8
+ ExecuteMultiResponse,
6
9
  KeyValueRow,
7
10
  QueryPlan,
8
11
  ScriptPlan,
@@ -76,34 +79,74 @@ export const getColumnType = (type: string) => {
76
79
  }
77
80
  };
78
81
 
79
- /** parse response result field from ArrayRow to KeyValueRow */
82
+ /** parse response result from ArrayRow to KeyValueRow */
83
+ const parseModernResult = (rows: ArrayRow[], columns: ColumnType[]) => {
84
+ return rows.map((row) => {
85
+ return row.reduce<KeyValueRow>((newRow, cellData, columnIndex) => {
86
+ const {name} = columns[columnIndex];
87
+ newRow[name] = cellData;
88
+ return newRow;
89
+ }, {});
90
+ });
91
+ };
92
+
80
93
  const parseExecuteModernResponse = (data: ExecuteModernResponse): IQueryResult => {
81
94
  const {result, columns, ...restData} = data;
82
95
 
83
96
  return {
84
- result:
85
- result &&
86
- columns &&
87
- result.map((row) => {
88
- return row.reduce((newRow, cellData, columnIndex) => {
89
- const {name} = columns[columnIndex];
90
- newRow[name] = cellData;
91
- return newRow;
92
- }, {} as KeyValueRow);
93
- }),
97
+ result: result && columns && parseModernResult(result, columns),
94
98
  columns,
95
99
  ...restData,
96
100
  };
97
101
  };
98
102
 
103
+ const parseExecuteMultiResponse = (data: ExecuteMultiResponse): IQueryResult => {
104
+ const {result, ...restData} = data;
105
+
106
+ const parsedResult = result?.map((resultSet) => {
107
+ const {rows, columns} = resultSet;
108
+
109
+ let parsedRows: KeyValueRow[] | undefined;
110
+
111
+ if (columns) {
112
+ // Result shouldn't be null if there are columns
113
+ parsedRows = [];
114
+ }
115
+
116
+ if (rows && columns) {
117
+ parsedRows = parseModernResult(rows, columns);
118
+ }
119
+
120
+ return {
121
+ columns: columns,
122
+ result: parsedRows,
123
+ };
124
+ });
125
+
126
+ return {
127
+ resultSets: parsedResult, // use a separate field to make result compatible
128
+ ...restData,
129
+ };
130
+ };
131
+
99
132
  const isModern = (response: AnyExecuteResponse): response is ExecuteModernResponse =>
100
133
  Boolean(
101
134
  response &&
102
135
  !Array.isArray(response) &&
103
- Array.isArray((response as ExecuteModernResponse).result) &&
136
+ Array.isArray(response.result) &&
104
137
  Array.isArray((response as ExecuteModernResponse).columns),
105
138
  );
106
139
 
140
+ const isMulti = (response: AnyExecuteResponse): response is ExecuteMultiResponse =>
141
+ Boolean(
142
+ response &&
143
+ !Array.isArray(response) &&
144
+ Array.isArray(response.result) &&
145
+ typeof response.result[0] === 'object' &&
146
+ 'rows' in response.result[0] &&
147
+ 'columns' in response.result[0],
148
+ );
149
+
107
150
  type UnsupportedQueryResponseFormat =
108
151
  | Array<unknown>
109
152
  | string
@@ -122,12 +165,17 @@ const isUnsupportedType = (
122
165
  );
123
166
  };
124
167
 
168
+ // Although schema is set in request, if schema is not supported default schema for the version will be used
169
+ // So we should additionally parse response
125
170
  export const parseQueryAPIExecuteResponse = (
126
171
  data: AnyExecuteResponse | UnsupportedQueryResponseFormat,
127
172
  ): IQueryResult => {
128
173
  if (isUnsupportedType(data)) {
129
174
  return {};
130
175
  }
176
+ if (isMulti(data)) {
177
+ return parseExecuteMultiResponse(data);
178
+ }
131
179
  if (isModern(data)) {
132
180
  return parseExecuteModernResponse(data);
133
181
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "4.21.1",
3
+ "version": "4.23.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -1,32 +0,0 @@
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
- };
@@ -1,9 +0,0 @@
1
- // determine how many nodes have status Connected "true"
2
- export const getConnectedNodesCount = (nodeStateInfo) => {
3
- return nodeStateInfo?.reduce((acc, item) => (item.Connected ? acc + 1 : acc), 0);
4
- };
5
-
6
- export const renderExplainNode = (node) => {
7
- const parts = node.name.split('|');
8
- return parts.length > 1 ? parts[1] : node.name;
9
- };