ydb-embedded-ui 3.4.5 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/components/InfoViewer/formatters/table.ts +6 -0
  3. package/dist/components/TruncatedQuery/TruncatedQuery.js +1 -1
  4. package/dist/components/TruncatedQuery/TruncatedQuery.scss +7 -3
  5. package/dist/containers/Node/{NodePages.js → NodePages.ts} +1 -1
  6. package/dist/containers/Tablet/TabletControls/TabletControls.tsx +2 -2
  7. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +11 -43
  8. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/TableInfo.tsx +19 -17
  9. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +192 -37
  10. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +20 -14
  11. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +49 -12
  12. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +37 -18
  13. package/dist/containers/Tenant/QueryEditor/QueriesHistory/QueriesHistory.tsx +3 -3
  14. package/dist/containers/Tenant/QueryEditor/QueryDuration/QueryDuration.scss +8 -0
  15. package/dist/containers/Tenant/QueryEditor/QueryDuration/QueryDuration.tsx +21 -0
  16. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +58 -82
  17. package/dist/containers/Tenant/QueryEditor/QueryEditor.scss +0 -33
  18. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/OldQueryEditorControls.tsx +83 -0
  19. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.scss +57 -0
  20. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.tsx +84 -0
  21. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/shared.ts +23 -0
  22. package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.js +12 -23
  23. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.js +4 -6
  24. package/dist/containers/Tenant/QueryEditor/i18n/en.json +3 -0
  25. package/dist/containers/Tenant/QueryEditor/i18n/index.ts +11 -0
  26. package/dist/containers/Tenant/QueryEditor/i18n/ru.json +3 -0
  27. package/dist/containers/UserSettings/UserSettings.tsx +30 -1
  28. package/dist/routes.ts +1 -1
  29. package/dist/services/api.d.ts +4 -3
  30. package/dist/services/api.js +5 -5
  31. package/dist/store/reducers/{executeQuery.js → executeQuery.ts} +48 -43
  32. package/dist/store/reducers/executeTopQueries.ts +5 -1
  33. package/dist/store/reducers/{explainQuery.js → explainQuery.ts} +44 -59
  34. package/dist/store/reducers/{olapStats.js → olapStats.ts} +8 -18
  35. package/dist/store/reducers/settings.js +19 -4
  36. package/dist/store/reducers/storage.js +5 -7
  37. package/dist/types/api/error.ts +14 -0
  38. package/dist/types/api/query.ts +227 -115
  39. package/dist/types/api/schema.ts +523 -3
  40. package/dist/types/common.ts +1 -0
  41. package/dist/types/store/executeQuery.ts +38 -0
  42. package/dist/types/store/explainQuery.ts +38 -0
  43. package/dist/types/store/olapStats.ts +14 -0
  44. package/dist/types/store/query.ts +23 -3
  45. package/dist/utils/constants.ts +2 -1
  46. package/dist/utils/error.ts +25 -0
  47. package/dist/utils/index.js +0 -49
  48. package/dist/utils/prepareQueryExplain.ts +7 -24
  49. package/dist/utils/query.test.ts +148 -213
  50. package/dist/utils/query.ts +68 -90
  51. package/dist/utils/timeParsers/formatDuration.ts +30 -12
  52. package/dist/utils/timeParsers/i18n/en.json +9 -5
  53. package/dist/utils/timeParsers/i18n/ru.json +9 -5
  54. package/dist/utils/timeParsers/parsers.ts +9 -0
  55. package/dist/utils/utils.js +1 -2
  56. package/package.json +1 -1
@@ -2,13 +2,10 @@ import {YQLType} from '../types';
2
2
  import type {
3
3
  AnyExecuteResponse,
4
4
  AnyExplainResponse,
5
- AnyResponse,
6
- CommonFields,
7
- DeepExecuteResponse,
8
- DeprecatedExecuteResponsePlain,
9
- ExecuteClassicResponsePlain,
10
5
  ExecuteModernResponse,
11
6
  KeyValueRow,
7
+ ScanPlan,
8
+ ScriptPlan,
12
9
  } from '../types/api/query';
13
10
  import type {IQueryResult} from '../types/store/query';
14
11
 
@@ -47,119 +44,94 @@ export const getColumnType = (type: string) => {
47
44
  default:
48
45
  return undefined;
49
46
  }
50
- }
47
+ };
51
48
 
49
+ /** parse response result field from ArrayRow to KeyValueRow */
52
50
  const parseExecuteModernResponse = (data: ExecuteModernResponse): IQueryResult => {
53
51
  const {result, columns, ...restData} = data;
54
52
 
55
53
  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
- }),
54
+ result:
55
+ result &&
56
+ columns &&
57
+ result.map((row) => {
58
+ return row.reduce((newRow, cellData, columnIndex) => {
59
+ const {name} = columns[columnIndex];
60
+ newRow[name] = cellData;
61
+ return newRow;
62
+ }, {} as KeyValueRow);
63
+ }),
63
64
  columns,
64
65
  ...restData,
65
66
  };
66
67
  };
67
68
 
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;
69
+ const isModern = (response: AnyExecuteResponse): response is ExecuteModernResponse =>
70
+ Boolean(
71
+ response &&
72
+ !Array.isArray(response) &&
73
+ Array.isArray((response as ExecuteModernResponse).result) &&
74
+ Array.isArray((response as ExecuteModernResponse).columns),
75
+ );
76
+
77
+ type UnsupportedQueryResponseFormat =
78
+ | Array<unknown>
79
+ | string
80
+ | null
81
+ | undefined
82
+ | {result: string | Record<string, unknown>};
83
+
84
+ const isUnsupportedType = (
85
+ data: AnyExecuteResponse | AnyExplainResponse | UnsupportedQueryResponseFormat,
86
+ ): data is UnsupportedQueryResponseFormat => {
87
+ return Boolean(
88
+ !data ||
89
+ typeof data !== 'object' ||
90
+ Array.isArray(data) ||
91
+ ('result' in data && !Array.isArray(data.result)),
92
+ );
87
93
  };
88
94
 
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: AnyResponse): 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 = (data: AnyExecuteResponse): IQueryResult => {
107
- if (!data) {
95
+ export const parseQueryAPIExecuteResponse = (
96
+ data: AnyExecuteResponse | UnsupportedQueryResponseFormat,
97
+ ): IQueryResult => {
98
+ if (isUnsupportedType(data)) {
108
99
  return {};
109
100
  }
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
- };
101
+ if (isModern(data)) {
102
+ return parseExecuteModernResponse(data);
120
103
  }
121
104
 
122
- if (hasCommonFields(data)) {
123
- return data;
124
- }
125
-
126
- return {
127
- result: parseDeprecatedExecuteResponseValue(data),
128
- };
105
+ return data;
129
106
  };
130
107
 
131
- // complex logic because of the variety of possible responses
132
- // after all backends are updated to the latest version, it can be simplified
133
- export const parseQueryAPIExplainResponse = (data: AnyExplainResponse): IQueryResult => {
134
- if (!data) {
108
+ export const parseQueryAPIExplainResponse = (
109
+ data: AnyExplainResponse | UnsupportedQueryResponseFormat,
110
+ ): IQueryResult => {
111
+ if (isUnsupportedType(data)) {
135
112
  return {};
136
113
  }
137
114
 
138
- if ('ast' in data) {
139
- return data;
140
- }
115
+ return data;
116
+ };
141
117
 
142
- if ('result' in data) {
143
- const {result, ...restData} = data;
118
+ const isExplainScriptPlan = (plan: ScriptPlan | ScanPlan): plan is ScriptPlan =>
119
+ Boolean(plan && 'queries' in plan);
144
120
 
145
- if ('ast' in data.result) {
146
- return {
147
- ast: result.ast,
148
- ...restData,
149
- };
121
+ export const parseQueryExplainPlan = (plan: ScriptPlan | ScanPlan): ScanPlan => {
122
+ if (isExplainScriptPlan(plan)) {
123
+ if (!plan.queries || !plan.queries.length) {
124
+ return {meta: plan.meta};
150
125
  }
151
126
 
152
127
  return {
153
- plan: data.result,
154
- ...restData,
128
+ Plan: plan.queries[0].Plan,
129
+ tables: plan.queries[0].tables,
130
+ meta: plan.meta,
155
131
  };
156
132
  }
157
133
 
158
- if (hasCommonFields(data)) {
159
- return data;
160
- }
161
-
162
- return {plan: data};
134
+ return plan;
163
135
  };
164
136
 
165
137
  export const prepareQueryResponse = (data?: KeyValueRow[]) => {
@@ -186,5 +158,11 @@ export const prepareQueryResponse = (data?: KeyValueRow[]) => {
186
158
  };
187
159
 
188
160
  export function prepareQueryError(error: any) {
189
- return error.data?.error?.message || error.message || error.data || error.statusText || JSON.stringify(error);
161
+ return (
162
+ error.data?.error?.message ||
163
+ error.message ||
164
+ error.data ||
165
+ error.statusText ||
166
+ JSON.stringify(error)
167
+ );
190
168
  }
@@ -4,9 +4,10 @@ import i18n from './i18n';
4
4
 
5
5
  /**
6
6
  * Process time difference in ms and returns formated time.
7
- * Only two major values are returned (days & hours, hours & minutes, minutes & seconds, etc.)
7
+ * By default only two major values are returned (days & hours, hours & minutes, minutes & seconds, etc.).
8
+ * It can be altered with valuesCount arg
8
9
  */
9
- export const formatDurationToShortTimeFormat = (value: number) => {
10
+ export const formatDurationToShortTimeFormat = (value: number, valuesCount: 1 | 2 = 2) => {
10
11
  const ms = value % 1000;
11
12
  let remain = Math.floor(value / 1000);
12
13
 
@@ -29,17 +30,34 @@ export const formatDurationToShortTimeFormat = (value: number) => {
29
30
  ms,
30
31
  };
31
32
 
32
- if (days > 0) {
33
- return i18n('daysHours', duration);
33
+ if (valuesCount === 2) {
34
+ if (days > 0) {
35
+ return i18n('daysHours', duration);
36
+ }
37
+ if (hours > 0) {
38
+ return i18n('hoursMin', duration);
39
+ }
40
+ if (minutes > 0) {
41
+ return i18n('minSec', duration);
42
+ }
43
+ if (seconds > 0) {
44
+ return i18n('secMs', duration);
45
+ }
34
46
  }
35
- if (hours > 0) {
36
- return i18n('hoursMin', duration);
37
- }
38
- if (minutes > 0) {
39
- return i18n('minSec', duration);
40
- }
41
- if (seconds > 0) {
42
- return i18n('secMs', duration);
47
+
48
+ if (valuesCount === 1) {
49
+ if (days > 0) {
50
+ return i18n('days', duration);
51
+ }
52
+ if (hours > 0) {
53
+ return i18n('hours', duration);
54
+ }
55
+ if (minutes > 0) {
56
+ return i18n('min', duration);
57
+ }
58
+ if (seconds > 0) {
59
+ return i18n('sec', duration);
60
+ }
43
61
  }
44
62
 
45
63
  return i18n('ms', duration);
@@ -1,7 +1,11 @@
1
1
  {
2
- "daysHours": "{{days}}d {{hours}}h",
3
- "hoursMin": "{{hours}}h {{minutes}}m",
4
- "minSec": "{{minutes}}m {{seconds}}s",
5
- "secMs": "{{seconds}}s {{ms}}ms",
6
- "ms": "{{ms}}ms"
2
+ "daysHours": "{{days}}\u00a0d\u00a0{{hours}}\u00a0h",
3
+ "hoursMin": "{{hours}}\u00a0h\u00a0{{minutes}}\u00a0m",
4
+ "minSec": "{{minutes}}\u00a0m\u00a0{{seconds}}\u00a0s",
5
+ "secMs": "{{seconds}}\u00a0s\u00a0{{ms}}\u00a0ms",
6
+ "days": "{{days}}\u00a0d",
7
+ "hours": "{{hours}}\u00a0h",
8
+ "min": "{{minutes}}\u00a0m",
9
+ "sec": "{{seconds}}\u00a0s",
10
+ "ms": "{{ms}}\u00a0ms"
7
11
  }
@@ -1,7 +1,11 @@
1
1
  {
2
- "daysHours": "{{days}}д {{hours}}ч",
3
- "hoursMin": "{{hours}}ч {{minutes}}м",
4
- "minSec": "{{minutes}}м {{seconds}}с",
5
- "secMs": "{{seconds}}с {{ms}}мс",
6
- "ms": "{{ms}}мс"
2
+ "daysHours": "{{days}}\u00a0д\u00a0{{hours}}\u00a0ч",
3
+ "hoursMin": "{{hours}}\u00a0ч\u00a0{{minutes}}\u00a0м",
4
+ "minSec": "{{minutes}}\u00a0м\u00a0{{seconds}}\u00a0с",
5
+ "secMs": "{{seconds}}\u00a0с\u00a0{{ms}}\u00a0мс",
6
+ "days": "{{days}}\u00a0д",
7
+ "hours": "{{hours}}\u00a0ч",
8
+ "min": "{{minutes}}\u00a0м",
9
+ "sec": "{{seconds}}\u00a0с",
10
+ "ms": "{{ms}}\u00a0мс"
7
11
  }
@@ -1,5 +1,6 @@
1
1
  import type {IProtobufTimeObject} from '../../types/api/common';
2
2
 
3
+ import {isNumeric} from '../utils';
3
4
  import {parseProtobufDurationToMs, parseProtobufTimestampToMs} from '.';
4
5
 
5
6
  export const parseLag = (value: string | IProtobufTimeObject | undefined) =>
@@ -16,3 +17,11 @@ export const parseTimestampToIdleTime = (value: string | IProtobufTimeObject | u
16
17
  // Usually it below 100ms, so it could be omitted
17
18
  return duration < 0 ? 0 : duration;
18
19
  };
20
+
21
+ export const parseUsToMs = (value: string | number | undefined) => {
22
+ if (!value || !isNumeric(value)) {
23
+ return 0;
24
+ }
25
+
26
+ return Math.round(Number(value) / 1000);
27
+ };
@@ -1,11 +1,10 @@
1
1
  export function parseJson(value) {
2
2
  if (!value) {
3
- return;
3
+ return undefined;
4
4
  }
5
5
  try {
6
6
  return JSON.parse(value);
7
7
  } catch (err) {
8
- console.log(err);
9
8
  return value;
10
9
  }
11
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "3.4.5",
3
+ "version": "4.0.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],