ydb-embedded-ui 4.21.0 → 4.22.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.
- package/CHANGELOG.md +27 -0
- package/dist/components/NodeHostWrapper/NodeHostWrapper.scss +2 -1
- package/dist/components/QueryResultTable/QueryResultTable.tsx +7 -3
- package/dist/components/VirtualTable/TableChunk.tsx +2 -1
- package/dist/components/VirtualTable/VirtualTable.tsx +1 -1
- package/dist/containers/Node/Node.tsx +9 -17
- package/dist/containers/Node/NodeStructure/NodeStructure.tsx +8 -30
- package/dist/containers/Node/NodeStructure/Pdisk.tsx +32 -18
- package/dist/containers/Node/i18n/en.json +4 -0
- package/dist/containers/Node/i18n/index.ts +11 -0
- package/dist/containers/Node/i18n/ru.json +4 -0
- package/dist/containers/Nodes/Nodes.tsx +5 -10
- package/dist/containers/Nodes/getNodesColumns.tsx +57 -13
- package/dist/containers/Tablets/Tablets.tsx +3 -8
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +0 -1
- package/dist/containers/Tenant/Diagnostics/Network/Network.js +5 -10
- package/dist/containers/Tenant/Diagnostics/Network/utils.ts +6 -0
- package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.scss +13 -5
- package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.tsx +72 -18
- package/dist/containers/Tenant/Query/ExplainResult/ExplainResult.js +2 -1
- package/dist/containers/Tenant/Query/ExplainResult/utils.ts +6 -0
- package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +11 -24
- package/dist/containers/Tenant/Query/utils/getPreparedResult.ts +4 -5
- package/dist/containers/UserSettings/i18n/en.json +5 -2
- package/dist/containers/UserSettings/i18n/ru.json +5 -2
- package/dist/containers/UserSettings/settings.ts +12 -6
- package/dist/store/reducers/executeQuery.ts +4 -3
- package/dist/store/reducers/nodes/nodes.ts +2 -2
- package/dist/store/reducers/nodes/types.ts +12 -1
- package/dist/store/reducers/nodes/utils.ts +6 -0
- package/dist/store/reducers/settings/settings.ts +5 -3
- package/dist/types/api/netInfo.ts +1 -1
- package/dist/types/api/nodes.ts +24 -0
- package/dist/types/api/query.ts +23 -8
- package/dist/types/store/query.ts +6 -0
- package/dist/utils/constants.ts +3 -0
- package/dist/utils/developerUI/__test__/developerUI.test.ts +50 -0
- package/dist/utils/developerUI/developerUI.ts +42 -0
- package/dist/utils/diagnostics.ts +1 -0
- package/dist/utils/query.ts +68 -13
- package/package.json +1 -1
- package/dist/utils/index.js +0 -9
- /package/dist/{components/VirtualTable/utils.ts → utils/index.ts} +0 -0
package/dist/types/api/query.ts
CHANGED
@@ -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
|
-
|
239
|
-
|
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;
|
package/dist/utils/constants.ts
CHANGED
@@ -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
|
+
};
|
package/dist/utils/query.ts
CHANGED
@@ -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
|
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(
|
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
|
}
|
@@ -175,7 +223,14 @@ export const prepareQueryResponse = (data?: KeyValueRow[]) => {
|
|
175
223
|
for (const field in row) {
|
176
224
|
if (Object.prototype.hasOwnProperty.call(row, field)) {
|
177
225
|
const type = typeof row[field];
|
178
|
-
|
226
|
+
|
227
|
+
// Although typeof null == 'object'
|
228
|
+
// null result should be preserved
|
229
|
+
if (
|
230
|
+
(row[field] !== null && type === 'object') ||
|
231
|
+
type === 'boolean' ||
|
232
|
+
Array.isArray(row[field])
|
233
|
+
) {
|
179
234
|
formattedData[field] = JSON.stringify(row[field]);
|
180
235
|
} else {
|
181
236
|
formattedData[field] = row[field];
|
package/package.json
CHANGED
package/dist/utils/index.js
DELETED
@@ -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
|
-
};
|
File without changes
|