ydb-embedded-ui 1.13.2 → 1.14.1
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 +40 -0
- package/dist/assets/icons/flask.svg +3 -0
- package/dist/components/InfoViewer/formatters/common.ts +15 -0
- package/dist/components/InfoViewer/formatters/index.ts +2 -0
- package/dist/components/InfoViewer/formatters/schema.ts +43 -0
- package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +44 -0
- package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +34 -0
- package/dist/components/{IndexInfoViewer/IndexInfoViewer.tsx → InfoViewer/schemaInfo/TableIndexInfo.tsx} +7 -18
- package/dist/components/InfoViewer/schemaInfo/index.ts +3 -0
- package/dist/components/InfoViewer/schemaOverview/CDCStreamOverview.tsx +44 -0
- package/dist/components/InfoViewer/schemaOverview/PersQueueGroupOverview.tsx +35 -0
- package/dist/components/InfoViewer/schemaOverview/index.ts +2 -0
- package/dist/components/QueryResultTable/Cell/Cell.tsx +33 -0
- package/dist/components/QueryResultTable/Cell/index.ts +1 -0
- package/dist/components/QueryResultTable/QueryResultTable.scss +11 -0
- package/dist/components/QueryResultTable/QueryResultTable.tsx +115 -0
- package/dist/components/QueryResultTable/i18n/en.json +3 -0
- package/dist/components/QueryResultTable/i18n/index.ts +11 -0
- package/dist/components/QueryResultTable/i18n/ru.json +3 -0
- package/dist/components/QueryResultTable/index.ts +1 -0
- package/dist/containers/App/App.scss +1 -0
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +39 -14
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +18 -7
- package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +4 -3
- package/dist/containers/Storage/Vdisk/__tests__/colors.tsx +7 -7
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +6 -2
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +1 -1
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +8 -3
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +1 -1
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +1 -1
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +36 -10
- package/dist/containers/Tenant/Preview/Preview.js +15 -57
- package/dist/containers/Tenant/Preview/Preview.scss +4 -8
- package/dist/containers/Tenant/QueryEditor/QueryEditor.js +12 -41
- package/dist/containers/Tenant/QueryEditor/QueryEditor.scss +0 -4
- package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.scss +1 -2
- package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +2 -2
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +1 -1
- package/dist/containers/Tenant/utils/schema.ts +3 -0
- package/dist/containers/Tenant/utils/schemaActions.ts +1 -2
- package/dist/containers/Tenants/Tenants.js +12 -2
- package/dist/containers/UserSettings/UserSettings.tsx +26 -3
- package/dist/services/api.d.ts +19 -2
- package/dist/services/api.js +2 -2
- package/dist/setupTests.js +4 -0
- package/dist/store/reducers/executeQuery.js +4 -9
- package/dist/store/reducers/{preview.js → preview.ts} +22 -18
- package/dist/store/reducers/settings.js +3 -1
- package/dist/store/utils.ts +88 -0
- package/dist/types/api/query.ts +147 -0
- package/dist/types/api/schema.ts +235 -2
- package/dist/types/index.ts +33 -0
- package/dist/types/store/query.ts +9 -0
- package/dist/utils/{constants.js → constants.ts} +11 -6
- package/dist/utils/index.js +0 -24
- package/dist/utils/query.test.ts +189 -0
- package/dist/utils/query.ts +156 -0
- package/dist/utils/tests/providers.tsx +29 -0
- package/package.json +2 -2
- package/dist/store/utils.js +0 -51
@@ -0,0 +1,156 @@
|
|
1
|
+
import {YQLType} from '../types';
|
2
|
+
import type {
|
3
|
+
AnyExecuteResponse,
|
4
|
+
CommonFields,
|
5
|
+
DeepExecuteResponse,
|
6
|
+
DeprecatedExecuteResponsePlain,
|
7
|
+
ExecuteClassicResponsePlain,
|
8
|
+
ExecuteModernResponse,
|
9
|
+
KeyValueRow,
|
10
|
+
QueryAPIExecuteResponse,
|
11
|
+
Schemas,
|
12
|
+
} from '../types/api/query';
|
13
|
+
import type {IQueryResult} from '../types/store/query';
|
14
|
+
|
15
|
+
// eslint-disable-next-line complexity
|
16
|
+
export const getColumnType = (type: string) => {
|
17
|
+
switch (type.replace(/\?$/, '')) {
|
18
|
+
case YQLType.Bool:
|
19
|
+
return 'boolean';
|
20
|
+
case YQLType.Int8:
|
21
|
+
case YQLType.Int16:
|
22
|
+
case YQLType.Int32:
|
23
|
+
case YQLType.Int64:
|
24
|
+
case YQLType.Uint8:
|
25
|
+
case YQLType.Uint16:
|
26
|
+
case YQLType.Uint32:
|
27
|
+
case YQLType.Uint64:
|
28
|
+
case YQLType.Float:
|
29
|
+
case YQLType.Double:
|
30
|
+
case YQLType.Decimal:
|
31
|
+
return 'number';
|
32
|
+
case YQLType.String:
|
33
|
+
case YQLType.Utf8:
|
34
|
+
case YQLType.Json:
|
35
|
+
case YQLType.JsonDocument:
|
36
|
+
case YQLType.Yson:
|
37
|
+
case YQLType.Uuid:
|
38
|
+
return 'string';
|
39
|
+
case YQLType.Date:
|
40
|
+
case YQLType.Datetime:
|
41
|
+
case YQLType.Timestamp:
|
42
|
+
case YQLType.Interval:
|
43
|
+
case YQLType.TzDate:
|
44
|
+
case YQLType.TzDateTime:
|
45
|
+
case YQLType.TzTimestamp:
|
46
|
+
return 'date';
|
47
|
+
default:
|
48
|
+
return undefined;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
const parseExecuteModernResponse = (data: ExecuteModernResponse): IQueryResult => {
|
53
|
+
const {result, columns, ...restData} = data;
|
54
|
+
|
55
|
+
return {
|
56
|
+
result: result && columns && result.map((row) => {
|
57
|
+
return row.reduce((newRow: KeyValueRow, cellData, columnIndex) => {
|
58
|
+
const {name} = columns[columnIndex];
|
59
|
+
newRow[name] = cellData;
|
60
|
+
return newRow;
|
61
|
+
}, {});
|
62
|
+
}),
|
63
|
+
columns,
|
64
|
+
...restData,
|
65
|
+
};
|
66
|
+
};
|
67
|
+
|
68
|
+
const parseDeprecatedExecuteResponseValue = (data?: DeprecatedExecuteResponsePlain | ExecuteClassicResponsePlain): KeyValueRow[] | undefined => {
|
69
|
+
if (!data) {
|
70
|
+
return undefined;
|
71
|
+
}
|
72
|
+
|
73
|
+
if (typeof data === 'string') {
|
74
|
+
try {
|
75
|
+
return JSON.parse(data);
|
76
|
+
} catch (e) {
|
77
|
+
return undefined;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
if (Array.isArray(data)) {
|
82
|
+
return data;
|
83
|
+
}
|
84
|
+
|
85
|
+
// Plan is not a valid response in this case
|
86
|
+
return undefined;
|
87
|
+
};
|
88
|
+
|
89
|
+
const hasResult = (data: AnyExecuteResponse): data is DeepExecuteResponse => Boolean(
|
90
|
+
data && typeof data === 'object' && 'result' in data
|
91
|
+
);
|
92
|
+
|
93
|
+
const isModern = (response: AnyExecuteResponse): response is ExecuteModernResponse => Boolean(
|
94
|
+
response &&
|
95
|
+
!Array.isArray(response) &&
|
96
|
+
Array.isArray((response as ExecuteModernResponse).result) &&
|
97
|
+
Array.isArray((response as ExecuteModernResponse).columns)
|
98
|
+
);
|
99
|
+
|
100
|
+
const hasCommonFields = (data: AnyExecuteResponse): data is CommonFields => Boolean(
|
101
|
+
data && typeof data === 'object' && ('ast' in data || 'plan' in data || 'stats' in data)
|
102
|
+
);
|
103
|
+
|
104
|
+
// complex logic because of the variety of possible responses
|
105
|
+
// after all backends are updated to the latest version, it can be simplified
|
106
|
+
export const parseQueryAPIExecuteResponse = <T extends Schemas>(data: QueryAPIExecuteResponse<T>): IQueryResult => {
|
107
|
+
if (!data) {
|
108
|
+
return {};
|
109
|
+
}
|
110
|
+
|
111
|
+
if (hasResult(data)) {
|
112
|
+
if (isModern(data)) {
|
113
|
+
return parseExecuteModernResponse(data);
|
114
|
+
}
|
115
|
+
|
116
|
+
return {
|
117
|
+
...data,
|
118
|
+
result: parseDeprecatedExecuteResponseValue(data.result),
|
119
|
+
};
|
120
|
+
}
|
121
|
+
|
122
|
+
if (hasCommonFields(data)) {
|
123
|
+
return data;
|
124
|
+
}
|
125
|
+
|
126
|
+
return {
|
127
|
+
result: parseDeprecatedExecuteResponseValue(data),
|
128
|
+
};
|
129
|
+
};
|
130
|
+
|
131
|
+
export const prepareQueryResponse = (data?: KeyValueRow[]) => {
|
132
|
+
if (!Array.isArray(data)) {
|
133
|
+
return [];
|
134
|
+
}
|
135
|
+
|
136
|
+
return data.map((row) => {
|
137
|
+
const formattedData: KeyValueRow = {};
|
138
|
+
|
139
|
+
for (const field in row) {
|
140
|
+
if (Object.prototype.hasOwnProperty.call(row, field)) {
|
141
|
+
const type = typeof row[field];
|
142
|
+
if (type === 'object' || type === 'boolean' || Array.isArray(row[field])) {
|
143
|
+
formattedData[field] = JSON.stringify(row[field]);
|
144
|
+
} else {
|
145
|
+
formattedData[field] = row[field];
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
150
|
+
return formattedData;
|
151
|
+
});
|
152
|
+
};
|
153
|
+
|
154
|
+
export function prepareQueryError(error: any) {
|
155
|
+
return error.data?.error?.message || error.data || error.statusText || JSON.stringify(error);
|
156
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import React, {PropsWithChildren} from 'react';
|
2
|
+
import {Provider} from 'react-redux'
|
3
|
+
import {render} from '@testing-library/react'
|
4
|
+
import type {RenderOptions} from '@testing-library/react'
|
5
|
+
|
6
|
+
import configureStore from '../../store';
|
7
|
+
|
8
|
+
interface ExtendedRenderOptions extends Omit<RenderOptions, 'queries'> {
|
9
|
+
storeConfiguration?: {
|
10
|
+
store?: any;
|
11
|
+
history?: any;
|
12
|
+
};
|
13
|
+
}
|
14
|
+
|
15
|
+
export const renderWithStore = (
|
16
|
+
ui: React.ReactElement,
|
17
|
+
{
|
18
|
+
storeConfiguration = configureStore(),
|
19
|
+
...renderOptions
|
20
|
+
}: ExtendedRenderOptions = {}
|
21
|
+
) => {
|
22
|
+
const {store} = storeConfiguration;
|
23
|
+
|
24
|
+
function Wrapper({children}: PropsWithChildren<{}>) {
|
25
|
+
return <Provider store={store}>{children}</Provider>
|
26
|
+
}
|
27
|
+
|
28
|
+
return {store, ...render(ui, {wrapper: Wrapper, ...renderOptions})}
|
29
|
+
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "ydb-embedded-ui",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.14.1",
|
4
4
|
"files": [
|
5
5
|
"dist"
|
6
6
|
],
|
@@ -10,7 +10,7 @@
|
|
10
10
|
},
|
11
11
|
"dependencies": {
|
12
12
|
"@yandex-cloud/i18n": "0.6.0",
|
13
|
-
"@yandex-cloud/paranoid": "1.
|
13
|
+
"@yandex-cloud/paranoid": "^1.2.1",
|
14
14
|
"@yandex-cloud/react-data-table": "0.2.1",
|
15
15
|
"axios": "0.19.2",
|
16
16
|
"bem-cn-lite": "4.0.0",
|
package/dist/store/utils.js
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
import createToast from '../utils/createToast';
|
2
|
-
import {SET_UNAUTHENTICATED} from './reducers/authentication';
|
3
|
-
|
4
|
-
export const nop = (result) => result;
|
5
|
-
|
6
|
-
export function createRequestActionTypes(prefix, type) {
|
7
|
-
return {
|
8
|
-
REQUEST: `${prefix}/${type}_REQUEST`,
|
9
|
-
SUCCESS: `${prefix}/${type}_SUCCESS`,
|
10
|
-
FAILURE: `${prefix}/${type}_FAILURE`,
|
11
|
-
};
|
12
|
-
}
|
13
|
-
|
14
|
-
export function createApiRequest({actions, request, dataHandler = nop}) {
|
15
|
-
const doRequest = async function (dispatch, getState) {
|
16
|
-
dispatch({
|
17
|
-
type: actions.REQUEST,
|
18
|
-
});
|
19
|
-
|
20
|
-
try {
|
21
|
-
const result = await request;
|
22
|
-
const data = dataHandler(result, getState);
|
23
|
-
|
24
|
-
dispatch({
|
25
|
-
type: actions.SUCCESS,
|
26
|
-
data,
|
27
|
-
});
|
28
|
-
|
29
|
-
return data;
|
30
|
-
} catch (error) {
|
31
|
-
if (error && error.status === 401) {
|
32
|
-
dispatch({
|
33
|
-
type: SET_UNAUTHENTICATED.SUCCESS,
|
34
|
-
});
|
35
|
-
} else if (error && Number(error.status) >= 500 && error.statusText) {
|
36
|
-
createToast({
|
37
|
-
name: 'Request failure',
|
38
|
-
title: 'Request failure',
|
39
|
-
type: 'error',
|
40
|
-
content: `${error.status} ${error.statusText}`,
|
41
|
-
});
|
42
|
-
}
|
43
|
-
dispatch({
|
44
|
-
type: actions.FAILURE,
|
45
|
-
error,
|
46
|
-
});
|
47
|
-
}
|
48
|
-
};
|
49
|
-
|
50
|
-
return doRequest;
|
51
|
-
}
|