ydb-embedded-ui 1.13.2 → 1.14.1

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 +40 -0
  2. package/dist/assets/icons/flask.svg +3 -0
  3. package/dist/components/InfoViewer/formatters/common.ts +15 -0
  4. package/dist/components/InfoViewer/formatters/index.ts +2 -0
  5. package/dist/components/InfoViewer/formatters/schema.ts +43 -0
  6. package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +44 -0
  7. package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +34 -0
  8. package/dist/components/{IndexInfoViewer/IndexInfoViewer.tsx → InfoViewer/schemaInfo/TableIndexInfo.tsx} +7 -18
  9. package/dist/components/InfoViewer/schemaInfo/index.ts +3 -0
  10. package/dist/components/InfoViewer/schemaOverview/CDCStreamOverview.tsx +44 -0
  11. package/dist/components/InfoViewer/schemaOverview/PersQueueGroupOverview.tsx +35 -0
  12. package/dist/components/InfoViewer/schemaOverview/index.ts +2 -0
  13. package/dist/components/QueryResultTable/Cell/Cell.tsx +33 -0
  14. package/dist/components/QueryResultTable/Cell/index.ts +1 -0
  15. package/dist/components/QueryResultTable/QueryResultTable.scss +11 -0
  16. package/dist/components/QueryResultTable/QueryResultTable.tsx +115 -0
  17. package/dist/components/QueryResultTable/i18n/en.json +3 -0
  18. package/dist/components/QueryResultTable/i18n/index.ts +11 -0
  19. package/dist/components/QueryResultTable/i18n/ru.json +3 -0
  20. package/dist/components/QueryResultTable/index.ts +1 -0
  21. package/dist/containers/App/App.scss +1 -0
  22. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +39 -14
  23. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +18 -7
  24. package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +4 -3
  25. package/dist/containers/Storage/Vdisk/__tests__/colors.tsx +7 -7
  26. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +6 -2
  27. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +1 -1
  28. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +8 -3
  29. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +1 -1
  30. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +1 -1
  31. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +36 -10
  32. package/dist/containers/Tenant/Preview/Preview.js +15 -57
  33. package/dist/containers/Tenant/Preview/Preview.scss +4 -8
  34. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +12 -41
  35. package/dist/containers/Tenant/QueryEditor/QueryEditor.scss +0 -4
  36. package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.scss +1 -2
  37. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +2 -2
  38. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +1 -1
  39. package/dist/containers/Tenant/utils/schema.ts +3 -0
  40. package/dist/containers/Tenant/utils/schemaActions.ts +1 -2
  41. package/dist/containers/Tenants/Tenants.js +12 -2
  42. package/dist/containers/UserSettings/UserSettings.tsx +26 -3
  43. package/dist/services/api.d.ts +19 -2
  44. package/dist/services/api.js +2 -2
  45. package/dist/setupTests.js +4 -0
  46. package/dist/store/reducers/executeQuery.js +4 -9
  47. package/dist/store/reducers/{preview.js → preview.ts} +22 -18
  48. package/dist/store/reducers/settings.js +3 -1
  49. package/dist/store/utils.ts +88 -0
  50. package/dist/types/api/query.ts +147 -0
  51. package/dist/types/api/schema.ts +235 -2
  52. package/dist/types/index.ts +33 -0
  53. package/dist/types/store/query.ts +9 -0
  54. package/dist/utils/{constants.js → constants.ts} +11 -6
  55. package/dist/utils/index.js +0 -24
  56. package/dist/utils/query.test.ts +189 -0
  57. package/dist/utils/query.ts +156 -0
  58. package/dist/utils/tests/providers.tsx +29 -0
  59. package/package.json +2 -2
  60. 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.13.2",
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.0.0",
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",
@@ -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
- }