ydb-embedded-ui 5.0.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. package/dist/components/BasicNodeViewer/BasicNodeViewer.d.ts +2 -2
  2. package/dist/components/BasicNodeViewer/BasicNodeViewer.js +1 -1
  3. package/dist/components/ComponentsProvider/ComponentsProvider.d.ts +4 -0
  4. package/dist/components/ComponentsProvider/componentsRegistry.d.ts +3 -0
  5. package/dist/components/ComponentsProvider/componentsRegistry.js +3 -1
  6. package/dist/components/EntityStatus/EntityStatus.scss +1 -1
  7. package/dist/components/ErrorBoundary/ErrorBoundary.d.ts +11 -1
  8. package/dist/components/ErrorBoundary/ErrorBoundary.js +11 -3
  9. package/dist/components/FullNodeViewer/FullNodeViewer.d.ts +2 -2
  10. package/dist/components/FullNodeViewer/FullNodeViewer.js +1 -1
  11. package/dist/components/LagImages/LagImages.js +2 -2
  12. package/dist/components/ProgressViewer/ProgressViewer.js +6 -5
  13. package/dist/components/ProgressViewer/ProgressViewer.scss +33 -17
  14. package/dist/components/TabletsOverall/TabletsOverall.js +6 -6
  15. package/dist/containers/App/App.js +2 -1
  16. package/dist/containers/App/Content.js +6 -12
  17. package/dist/containers/App/Providers.js +2 -1
  18. package/dist/containers/App/appSlots.d.ts +7 -7
  19. package/dist/containers/AppIcons/AppIcons.js +1 -1
  20. package/dist/containers/Cluster/Cluster.js +45 -27
  21. package/dist/containers/Cluster/Cluster.scss +15 -0
  22. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.js +4 -18
  23. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +0 -40
  24. package/dist/containers/Cluster/utils.d.ts +6 -1
  25. package/dist/containers/Cluster/utils.js +11 -3
  26. package/dist/containers/ClusterModeGuard/ClusterModeGuard.d.ts +6 -0
  27. package/dist/containers/ClusterModeGuard/ClusterModeGuard.js +6 -0
  28. package/dist/containers/ClusterModeGuard/index.d.ts +1 -0
  29. package/dist/containers/ClusterModeGuard/index.js +1 -0
  30. package/dist/containers/Clusters/Clusters.js +4 -3
  31. package/dist/containers/Clusters/columns.js +1 -1
  32. package/dist/containers/Clusters/constants.d.ts +1 -1
  33. package/dist/containers/Clusters/i18n/en.json +2 -1
  34. package/dist/containers/Clusters/i18n/index.d.ts +1 -1
  35. package/dist/containers/Clusters/i18n/index.js +2 -4
  36. package/dist/containers/Clusters/i18n/ru.json +2 -1
  37. package/dist/containers/Node/Node.js +11 -13
  38. package/dist/containers/Node/NodePages.js +4 -1
  39. package/dist/containers/Node/i18n/index.d.ts +1 -1
  40. package/dist/containers/Node/i18n/index.js +2 -4
  41. package/dist/containers/Nodes/getNodesColumns.js +2 -1
  42. package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.d.ts +1 -1
  43. package/dist/containers/Storage/StorageNodes/getStorageNodesColumns.d.ts +1 -1
  44. package/dist/containers/Storage/StorageNodes/getStorageNodesColumns.js +2 -1
  45. package/dist/containers/Tablet/Tablet.js +24 -20
  46. package/dist/containers/Tablet/i18n/index.d.ts +1 -1
  47. package/dist/containers/Tablet/i18n/index.js +2 -4
  48. package/dist/containers/TabletsFilters/TabletsFilters.d.ts +2 -0
  49. package/dist/containers/TabletsFilters/TabletsFilters.js +25 -19
  50. package/dist/containers/TabletsFilters/i18n/en.json +3 -0
  51. package/dist/containers/TabletsFilters/i18n/index.d.ts +2 -0
  52. package/dist/containers/TabletsFilters/i18n/index.js +5 -0
  53. package/dist/containers/TabletsFilters/i18n/ru.json +3 -0
  54. package/dist/containers/Tenant/Diagnostics/Diagnostics.js +12 -11
  55. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.d.ts +19 -0
  56. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.js +2 -1
  57. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.d.ts +7 -25
  58. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +88 -92
  59. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.scss +1 -33
  60. package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/en.json +4 -0
  61. package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/index.d.ts +2 -0
  62. package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/index.js +5 -0
  63. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.js +4 -1
  64. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.js +3 -4
  65. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +12 -5
  66. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.d.ts +2 -2
  67. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.js +7 -10
  68. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +7 -5
  69. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/index.js +0 -2
  70. package/dist/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.js +10 -0
  71. package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.d.ts +1 -1
  72. package/dist/containers/Tenant/Query/Query.d.ts +2 -2
  73. package/dist/containers/Tenant/Query/Query.js +5 -2
  74. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.d.ts +29 -31
  75. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +150 -167
  76. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.d.ts +2 -2
  77. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.js +3 -3
  78. package/dist/containers/Tenant/Query/QueryTabs/QueryTabs.d.ts +10 -0
  79. package/dist/containers/Tenant/Query/QueryTabs/QueryTabs.js +1 -1
  80. package/dist/containers/Tenant/Query/utils/getPreparedResult.d.ts +1 -1
  81. package/dist/containers/Tenant/Query/utils/getPreparedResult.js +18 -16
  82. package/dist/containers/Tenant/Tenant.js +4 -1
  83. package/dist/containers/Tenant/i18n/en.json +1 -0
  84. package/dist/containers/Tenant/i18n/index.d.ts +1 -1
  85. package/dist/containers/Tenant/i18n/index.js +2 -4
  86. package/dist/containers/Tenant/i18n/ru.json +1 -0
  87. package/dist/containers/UserSettings/Setting.d.ts +2 -1
  88. package/dist/containers/UserSettings/Setting.js +2 -2
  89. package/dist/containers/UserSettings/i18n/en.json +2 -0
  90. package/dist/containers/UserSettings/i18n/index.d.ts +1 -1
  91. package/dist/containers/UserSettings/i18n/index.js +2 -6
  92. package/dist/containers/UserSettings/settings.d.ts +1 -0
  93. package/dist/containers/UserSettings/settings.js +9 -2
  94. package/dist/containers/Versions/NodesTreeTitle/NodesTreeTitle.scss +1 -1
  95. package/dist/lib.d.ts +2 -1
  96. package/dist/lib.js +2 -1
  97. package/dist/routes.d.ts +5 -0
  98. package/dist/routes.js +4 -0
  99. package/dist/services/api.d.ts +2 -1
  100. package/dist/services/api.js +10 -3
  101. package/dist/services/settings.d.ts +0 -1
  102. package/dist/services/settings.js +2 -14
  103. package/dist/store/index.d.ts +1 -1
  104. package/dist/store/reducers/cluster/cluster.d.ts +8 -2
  105. package/dist/store/reducers/cluster/cluster.js +29 -1
  106. package/dist/store/reducers/cluster/types.d.ts +4 -2
  107. package/dist/store/reducers/executeQuery.d.ts +1 -10
  108. package/dist/store/reducers/executeQuery.js +26 -29
  109. package/dist/store/reducers/executeTopQueries/executeTopQueries.js +2 -1
  110. package/dist/store/reducers/executeTopQueries/utils.js +7 -4
  111. package/dist/store/reducers/hotKeys/hotKeys.d.ts +25 -0
  112. package/dist/store/reducers/hotKeys/hotKeys.js +49 -0
  113. package/dist/store/reducers/hotKeys/types.d.ts +10 -0
  114. package/dist/store/reducers/hotKeys/types.js +1 -0
  115. package/dist/store/reducers/index.d.ts +2 -6
  116. package/dist/store/reducers/index.js +1 -1
  117. package/dist/store/reducers/node/node.d.ts +1 -1
  118. package/dist/store/reducers/node/node.js +2 -0
  119. package/dist/store/reducers/node/selectors.js +1 -1
  120. package/dist/store/reducers/node/types.d.ts +7 -3
  121. package/dist/store/reducers/node/utils.d.ts +3 -0
  122. package/dist/store/reducers/node/utils.js +8 -0
  123. package/dist/store/reducers/nodes/types.d.ts +1 -1
  124. package/dist/store/reducers/nodes/utils.js +3 -3
  125. package/dist/store/reducers/storage/types.d.ts +2 -0
  126. package/dist/store/reducers/storage/utils.js +3 -3
  127. package/dist/store/reducers/tenants/utils.d.ts +4 -3
  128. package/dist/store/reducers/tenants/utils.js +17 -12
  129. package/dist/store/reducers/tooltip.d.ts +1 -1
  130. package/dist/types/api/hotkeys.d.ts +7 -0
  131. package/dist/types/api/hotkeys.js +1 -0
  132. package/dist/types/api/nodes.d.ts +2 -1
  133. package/dist/types/store/executeQuery.d.ts +3 -6
  134. package/dist/types/store/explainQuery.d.ts +1 -0
  135. package/dist/utils/constants.d.ts +2 -1
  136. package/dist/utils/constants.js +2 -1
  137. package/dist/utils/diagnostics.d.ts +1 -0
  138. package/dist/utils/diagnostics.js +1 -0
  139. package/dist/utils/i18n/i18n.d.ts +2 -1
  140. package/dist/utils/i18n/i18n.js +15 -2
  141. package/dist/utils/monitoring.js +1 -3
  142. package/dist/utils/versions/getVersionsColors.js +1 -1
  143. package/package.json +9 -8
  144. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +0 -26
  145. package/dist/containers/UserSettings/i18n/ru.json +0 -20
  146. package/dist/store/reducers/hotKeys.d.ts +0 -11
  147. package/dist/store/reducers/hotKeys.js +0 -34
@@ -1,17 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useReducer, useRef, useState } from 'react';
3
- import PropTypes from 'prop-types';
4
3
  import { connect } from 'react-redux';
5
4
  import cn from 'bem-cn-lite';
6
5
  import _ from 'lodash';
7
6
  import MonacoEditor from 'react-monaco-editor';
8
7
  import SplitPane from '../../../../components/SplitPane';
9
- import { sendExecuteQuery, saveQueryToHistory, goToPreviousQuery, goToNextQuery, MONACO_HOT_KEY_ACTIONS, setMonacoHotKey, setTenantPath, } from '../../../../store/reducers/executeQuery';
8
+ import { sendExecuteQuery, saveQueryToHistory, goToPreviousQuery, goToNextQuery, setTenantPath, } from '../../../../store/reducers/executeQuery';
10
9
  import { getExplainQuery, getExplainQueryAst } from '../../../../store/reducers/explainQuery';
11
10
  import { setShowPreview } from '../../../../store/reducers/schema/schema';
12
11
  import { DEFAULT_IS_QUERY_RESULT_COLLAPSED, DEFAULT_SIZE_RESULT_PANE_KEY, SAVED_QUERIES_KEY, LAST_USED_QUERY_ACTION_KEY, QUERY_USE_MULTI_SCHEMA_KEY, } from '../../../../utils/constants';
13
12
  import { useSetting, useQueryModes } from '../../../../utils/hooks';
14
13
  import { QUERY_ACTIONS } from '../../../../utils/query';
14
+ import { parseJson } from '../../../../utils/utils';
15
15
  import { PaneVisibilityActionTypes, paneVisibilityToggleReducerCreator, } from '../../utils/paneVisibilityToggleHelpers';
16
16
  import { Preview } from '../Preview/Preview';
17
17
  import { ExecuteResult } from '../ExecuteResult/ExecuteResult';
@@ -30,27 +30,18 @@ const RESULT_TYPES = {
30
30
  EXECUTE: 'execute',
31
31
  EXPLAIN: 'explain',
32
32
  };
33
- const b = cn('query-editor');
34
- const propTypes = {
35
- sendExecuteQuery: PropTypes.func,
36
- changeUserInput: PropTypes.func,
37
- path: PropTypes.string,
38
- response: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]),
39
- executeQuery: PropTypes.object,
40
- explainQuery: PropTypes.object,
41
- setMonacoHotKey: PropTypes.func,
42
- theme: PropTypes.string,
43
- type: PropTypes.string,
44
- initialQueryMode: PropTypes.string,
45
- setTenantPath: PropTypes.func,
33
+ const MONACO_HOT_KEY_ACTIONS = {
34
+ sendQuery: 'sendQuery',
35
+ sendSelectedQuery: 'sendSelectedQuery',
46
36
  };
37
+ const b = cn('query-editor');
47
38
  const initialTenantCommonInfoState = {
48
39
  triggerExpand: false,
49
40
  triggerCollapse: false,
50
41
  collapsed: true,
51
42
  };
52
43
  function QueryEditor(props) {
53
- const { path, executeQuery, theme, setTenantPath, changeUserInput } = props;
44
+ const { path, setTenantPath: setPath, executeQuery, explainQuery, type, theme, changeUserInput, showPreview, } = props;
54
45
  const { tenantPath: savedPath } = executeQuery;
55
46
  const [resultType, setResultType] = useState(RESULT_TYPES.EXECUTE);
56
47
  const [isResultLoaded, setIsResultLoaded] = useState(false);
@@ -58,27 +49,44 @@ function QueryEditor(props) {
58
49
  const [useMultiSchema] = useSetting(QUERY_USE_MULTI_SCHEMA_KEY);
59
50
  const [lastUsedQueryAction, setLastUsedQueryAction] = useSetting(LAST_USED_QUERY_ACTION_KEY);
60
51
  const [savedQueries, setSavedQueries] = useSetting(SAVED_QUERIES_KEY);
52
+ const [monacoHotKey, setMonacoHotKey] = useState(null);
61
53
  useEffect(() => {
62
54
  if (savedPath !== path) {
63
55
  if (savedPath) {
64
56
  changeUserInput({ input: '' });
65
57
  }
66
- setTenantPath(path);
58
+ setPath(path);
67
59
  }
68
- }, [changeUserInput, setTenantPath, path, savedPath]);
60
+ }, [changeUserInput, setPath, path, savedPath]);
69
61
  const [resultVisibilityState, dispatchResultVisibilityState] = useReducer(paneVisibilityToggleReducerCreator(DEFAULT_IS_QUERY_RESULT_COLLAPSED), initialTenantCommonInfoState);
70
- const editorRef = useRef(null);
62
+ const editorRef = useRef();
71
63
  useEffect(() => {
64
+ const updateEditor = () => {
65
+ if (editorRef.current) {
66
+ editorRef.current.layout();
67
+ }
68
+ };
69
+ const onChangeWindow = _.throttle(() => {
70
+ updateEditor();
71
+ }, 100);
72
72
  updateEditor();
73
73
  window.addEventListener('resize', onChangeWindow);
74
- window.addEventListener('storage', storageEventHandler);
75
74
  return () => {
76
75
  window.removeEventListener('resize', onChangeWindow);
77
- window.removeEventListener('storage', storageEventHandler);
78
- window.onbeforeunload = undefined;
79
- props.setMonacoHotKey(null);
80
76
  };
81
77
  }, []);
78
+ useEffect(() => {
79
+ const storageEventHandler = (event) => {
80
+ if (event.key === SAVED_QUERIES_KEY) {
81
+ const v = parseJson(event.newValue);
82
+ setSavedQueries(v);
83
+ }
84
+ };
85
+ window.addEventListener('storage', storageEventHandler);
86
+ return () => {
87
+ window.removeEventListener('storage', storageEventHandler);
88
+ };
89
+ }, [setSavedQueries]);
82
90
  useEffect(() => {
83
91
  dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerCollapse);
84
92
  }, []);
@@ -92,22 +100,66 @@ function QueryEditor(props) {
92
100
  }, [props.showPreview, isResultLoaded]);
93
101
  useEffect(() => {
94
102
  var _a;
95
- const { explainQuery: { data }, executeQuery: { input, history }, } = props;
103
+ const { input, history } = executeQuery;
96
104
  const hasUnsavedInput = input
97
- ? input !== history.queries[((_a = history.queries) === null || _a === void 0 ? void 0 : _a.length) - 1]
105
+ ? input !== ((_a = history.queries[history.queries.length - 1]) === null || _a === void 0 ? void 0 : _a.queryText)
98
106
  : false;
99
107
  if (hasUnsavedInput) {
100
- window.onbeforeunload = checkIfHasUnsavedInput;
108
+ window.onbeforeunload = (e) => {
109
+ e.preventDefault();
110
+ // Chrome requires returnValue to be set
111
+ e.returnValue = '';
112
+ };
101
113
  }
102
114
  else {
103
- window.onbeforeunload = undefined;
115
+ window.onbeforeunload = null;
104
116
  }
105
- if (!data || resultType !== RESULT_TYPES.EXPLAIN) {
117
+ return () => {
118
+ window.onbeforeunload = null;
119
+ };
120
+ }, [executeQuery]);
121
+ const handleSendExecuteClick = (mode, text) => {
122
+ var _a;
123
+ if (!mode) {
106
124
  return;
107
125
  }
108
- }, [props.executeQuery, props.executeQuery]);
126
+ const { input, history } = executeQuery;
127
+ const schema = useMultiSchema ? 'multi' : 'modern';
128
+ const query = text !== null && text !== void 0 ? text : input;
129
+ setLastUsedQueryAction(QUERY_ACTIONS.execute);
130
+ setResultType(RESULT_TYPES.EXECUTE);
131
+ props.sendExecuteQuery({
132
+ query,
133
+ database: path,
134
+ mode,
135
+ schema,
136
+ });
137
+ setIsResultLoaded(true);
138
+ props.setShowPreview(false);
139
+ // Don't save partial queries in history
140
+ if (!text) {
141
+ const { queries, currentIndex } = history;
142
+ if (query !== ((_a = queries[currentIndex]) === null || _a === void 0 ? void 0 : _a.queryText)) {
143
+ props.saveQueryToHistory(input, mode);
144
+ }
145
+ }
146
+ dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
147
+ };
148
+ const handleGetExplainQueryClick = (mode) => {
149
+ const { input } = executeQuery;
150
+ setLastUsedQueryAction(QUERY_ACTIONS.explain);
151
+ setResultType(RESULT_TYPES.EXPLAIN);
152
+ props.getExplainQuery({
153
+ query: input,
154
+ database: path,
155
+ mode: mode,
156
+ });
157
+ setIsResultLoaded(true);
158
+ props.setShowPreview(false);
159
+ dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
160
+ };
109
161
  useEffect(() => {
110
- const { monacoHotKey, setMonacoHotKey } = props;
162
+ var _a, _b;
111
163
  if (monacoHotKey === null) {
112
164
  return;
113
165
  }
@@ -115,31 +167,30 @@ function QueryEditor(props) {
115
167
  switch (monacoHotKey) {
116
168
  case MONACO_HOT_KEY_ACTIONS.sendQuery: {
117
169
  if (lastUsedQueryAction === QUERY_ACTIONS.explain) {
118
- return handleGetExplainQueryClick(queryMode);
170
+ handleGetExplainQueryClick(queryMode);
119
171
  }
120
172
  else {
121
- return handleSendExecuteClick(queryMode);
173
+ handleSendExecuteClick(queryMode);
122
174
  }
175
+ break;
123
176
  }
124
- case MONACO_HOT_KEY_ACTIONS.goPrev: {
125
- return handlePreviousHistoryClick();
126
- }
127
- case MONACO_HOT_KEY_ACTIONS.goNext: {
128
- return handleNextHistoryClick();
129
- }
130
- default: {
131
- return;
177
+ case MONACO_HOT_KEY_ACTIONS.sendSelectedQuery: {
178
+ const selection = (_a = editorRef.current) === null || _a === void 0 ? void 0 : _a.getSelection();
179
+ const model = (_b = editorRef.current) === null || _b === void 0 ? void 0 : _b.getModel();
180
+ if (selection && model) {
181
+ const text = model.getValueInRange({
182
+ startLineNumber: selection.getSelectionStart().lineNumber,
183
+ startColumn: selection.getSelectionStart().column,
184
+ endLineNumber: selection.getPosition().lineNumber,
185
+ endColumn: selection.getPosition().column,
186
+ });
187
+ handleSendExecuteClick(queryMode, text);
188
+ }
189
+ break;
132
190
  }
133
191
  }
134
- }, [props.monacoHotKey]);
135
- const checkIfHasUnsavedInput = (e) => {
136
- e.preventDefault();
137
- // Chrome requires returnValue to be set
138
- e.returnValue = '';
139
- };
140
- const handleKeyBinding = (value) => {
141
- return () => props.setMonacoHotKey(value);
142
- };
192
+ // eslint-disable-next-line react-hooks/exhaustive-deps
193
+ }, [monacoHotKey]);
143
194
  const editorDidMount = (editor, monaco) => {
144
195
  editorRef.current = editor;
145
196
  editor.focus();
@@ -151,14 +202,33 @@ function QueryEditor(props) {
151
202
  monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
152
203
  ],
153
204
  // A precondition for this action.
154
- precondition: null,
205
+ precondition: undefined,
155
206
  // A rule to evaluate on top of the precondition in order to dispatch the keybindings.
156
- keybindingContext: null,
207
+ keybindingContext: undefined,
157
208
  contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
158
209
  contextMenuOrder: 1,
159
210
  // Method that will be executed when the action is triggered.
160
- // @param editor The editor instance is passed in as a convinience
161
- run: handleKeyBinding(MONACO_HOT_KEY_ACTIONS.sendQuery),
211
+ // @param editor The editor instance is passed in as a convenience
212
+ run: () => setMonacoHotKey(MONACO_HOT_KEY_ACTIONS.sendQuery),
213
+ });
214
+ const canSendSelectedText = editor.createContextKey('canSendSelectedText', false);
215
+ editor.onDidChangeCursorSelection(({ selection, secondarySelections }) => {
216
+ const notEmpty = selection.selectionStartLineNumber !== selection.positionLineNumber ||
217
+ selection.selectionStartColumn !== selection.positionColumn;
218
+ const hasMultipleSelections = secondarySelections.length > 0;
219
+ canSendSelectedText.set(notEmpty && !hasMultipleSelections);
220
+ });
221
+ editor.addAction({
222
+ id: 'sendSelectedQuery',
223
+ label: 'Send selected query',
224
+ keybindings: [
225
+ // eslint-disable-next-line no-bitwise
226
+ monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.Enter,
227
+ ],
228
+ precondition: 'canSendSelectedText',
229
+ contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
230
+ contextMenuOrder: 1,
231
+ run: () => setMonacoHotKey(MONACO_HOT_KEY_ACTIONS.sendSelectedQuery),
162
232
  });
163
233
  editor.addAction({
164
234
  id: 'previous-query',
@@ -169,7 +239,9 @@ function QueryEditor(props) {
169
239
  ],
170
240
  contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
171
241
  contextMenuOrder: 2,
172
- run: handleKeyBinding(MONACO_HOT_KEY_ACTIONS.goPrev),
242
+ run: () => {
243
+ props.goToPreviousQuery();
244
+ },
173
245
  });
174
246
  editor.addAction({
175
247
  id: 'next-query',
@@ -180,47 +252,16 @@ function QueryEditor(props) {
180
252
  ],
181
253
  contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
182
254
  contextMenuOrder: 3,
183
- run: handleKeyBinding(MONACO_HOT_KEY_ACTIONS.goNext),
255
+ run: () => {
256
+ props.goToNextQuery();
257
+ },
184
258
  });
185
259
  };
186
260
  const onChange = (newValue) => {
187
261
  props.changeUserInput({ input: newValue });
188
262
  };
189
- const handleSendExecuteClick = (mode) => {
190
- const { path, executeQuery: { input, history }, sendExecuteQuery, saveQueryToHistory, setShowPreview, } = props;
191
- const schema = useMultiSchema ? 'multi' : 'modern';
192
- setLastUsedQueryAction(QUERY_ACTIONS.execute);
193
- setResultType(RESULT_TYPES.EXECUTE);
194
- sendExecuteQuery({
195
- query: input,
196
- database: path,
197
- mode,
198
- schema,
199
- });
200
- setIsResultLoaded(true);
201
- setShowPreview(false);
202
- const { queries, currentIndex } = history;
203
- if (input !== queries[currentIndex]) {
204
- saveQueryToHistory(input, mode);
205
- }
206
- dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
207
- };
208
- const handleGetExplainQueryClick = (mode) => {
209
- const { path, executeQuery: { input }, getExplainQuery, setShowPreview, } = props;
210
- setLastUsedQueryAction(QUERY_ACTIONS.explain);
211
- setResultType(RESULT_TYPES.EXPLAIN);
212
- getExplainQuery({
213
- query: input,
214
- database: path,
215
- mode: mode,
216
- });
217
- setIsResultLoaded(true);
218
- setShowPreview(false);
219
- dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
220
- };
221
263
  const handleAstQuery = () => {
222
- const { path, executeQuery: { input }, getExplainQueryAst, } = props;
223
- getExplainQueryAst({ query: input, database: path });
264
+ props.getExplainQueryAst({ query: executeQuery.input, database: path });
224
265
  };
225
266
  const onCollapseResultHandler = () => {
226
267
  dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerCollapse);
@@ -231,101 +272,31 @@ function QueryEditor(props) {
231
272
  const onSplitStartDragAdditional = () => {
232
273
  dispatchResultVisibilityState(PaneVisibilityActionTypes.clear);
233
274
  };
234
- const renderExecuteQuery = () => {
235
- const { executeQuery: { data, error, stats }, } = props;
236
- return data || error ? (_jsx(ExecuteResult, { data: data, stats: stats, error: error, isResultsCollapsed: resultVisibilityState.collapsed, onExpandResults: onExpandResultHandler, onCollapseResults: onCollapseResultHandler })) : null;
237
- };
238
- const renderExplainQuery = () => {
239
- const { explainQuery: { data, dataAst, error, loading, loadingAst }, theme, } = props;
240
- return (_jsx(ExplainResult, { error: error, explain: data, astQuery: handleAstQuery, ast: dataAst, loading: loading, loadingAst: loadingAst, theme: theme, isResultsCollapsed: resultVisibilityState.collapsed, onExpandResults: onExpandResultHandler, onCollapseResults: onCollapseResultHandler }));
241
- };
242
- const renderResult = () => {
243
- let result;
244
- switch (resultType) {
245
- case RESULT_TYPES.EXECUTE:
246
- result = renderExecuteQuery();
247
- break;
248
- case RESULT_TYPES.EXPLAIN:
249
- result = renderExplainQuery();
250
- break;
251
- default:
252
- result = null;
253
- }
254
- return result;
255
- };
256
- const renderPreview = () => {
257
- const { path, type } = props;
258
- return _jsx(Preview, { database: path, type: type });
259
- };
260
- const handlePreviousHistoryClick = () => {
261
- const { changeUserInput, executeQuery: { history }, goToPreviousQuery, } = props;
262
- const { queries, currentIndex } = history;
263
- if (previousButtonIsDisabled()) {
264
- return;
265
- }
266
- goToPreviousQuery();
267
- changeUserInput({ input: queries[currentIndex - 1] });
268
- };
269
- const handleNextHistoryClick = () => {
270
- const { changeUserInput, executeQuery: { history }, goToNextQuery, } = props;
271
- const { queries, currentIndex } = history;
272
- if (nextButtonIsDisabled()) {
273
- return;
274
- }
275
- goToNextQuery();
276
- changeUserInput({ input: queries[currentIndex + 1] });
277
- };
278
- const previousButtonIsDisabled = () => {
279
- const { history: { currentIndex }, } = props.executeQuery;
280
- return currentIndex <= 0;
281
- };
282
- const nextButtonIsDisabled = () => {
283
- const { history: { queries, currentIndex }, } = props.executeQuery;
284
- return queries.length - 1 === currentIndex;
285
- };
286
- const onChangeWindow = _.throttle(() => {
287
- updateEditor();
288
- }, 100);
289
- const storageEventHandler = (event) => {
290
- if (event.key === SAVED_QUERIES_KEY) {
291
- setSavedQueries(event.newValue);
292
- }
293
- };
294
- const updateEditor = () => {
295
- if (editorRef.current) {
296
- editorRef.current.layout();
297
- }
298
- };
299
275
  const onSaveQueryHandler = (queryName) => {
300
- const { executeQuery: { input }, } = props;
276
+ const { input } = executeQuery;
301
277
  const queryIndex = savedQueries.findIndex((el) => el.name.toLowerCase() === queryName.toLowerCase());
302
278
  const newSavedQueries = [...savedQueries];
303
279
  const newQuery = { name: queryName, body: input };
304
- if (queryIndex !== -1) {
305
- newSavedQueries[queryIndex] = newQuery;
280
+ if (queryIndex === -1) {
281
+ newSavedQueries.push(newQuery);
306
282
  }
307
283
  else {
308
- newSavedQueries.push(newQuery);
284
+ newSavedQueries[queryIndex] = newQuery;
309
285
  }
310
286
  setSavedQueries(newSavedQueries);
311
287
  };
312
288
  const renderControls = () => {
313
- const { executeQuery, explainQuery } = props;
314
- return (_jsx(QueryEditorControls, { onRunButtonClick: handleSendExecuteClick, runIsLoading: executeQuery.loading, onExplainButtonClick: handleGetExplainQueryClick, explainIsLoading: explainQuery.loading, onSaveQueryClick: onSaveQueryHandler, savedQueries: savedQueries, disabled: !executeQuery.input, onUpdateQueryMode: setQueryMode, queryMode: queryMode, highlitedAction: lastUsedQueryAction }));
289
+ return (_jsx(QueryEditorControls, { onRunButtonClick: handleSendExecuteClick, runIsLoading: executeQuery.loading, onExplainButtonClick: handleGetExplainQueryClick, explainIsLoading: explainQuery.loading, onSaveQueryClick: onSaveQueryHandler, savedQueries: savedQueries, disabled: !executeQuery.input, onUpdateQueryMode: setQueryMode, queryMode: queryMode, highlightedAction: lastUsedQueryAction }));
315
290
  };
316
- const result = renderResult();
317
291
  return (_jsx("div", Object.assign({ className: b() }, { children: _jsxs(SplitPane, Object.assign({ direction: "vertical", defaultSizePaneKey: DEFAULT_SIZE_RESULT_PANE_KEY, triggerCollapse: resultVisibilityState.triggerCollapse, triggerExpand: resultVisibilityState.triggerExpand, minSize: [0, 52], collapsedSizes: [100, 0], onSplitStartDragAdditional: onSplitStartDragAdditional }, { children: [_jsxs("div", Object.assign({ className: b('pane-wrapper', {
318
292
  top: true,
319
- }) }, { children: [_jsx("div", Object.assign({ className: b('monaco-wrapper') }, { children: _jsx("div", Object.assign({ className: b('monaco') }, { children: _jsx(MonacoEditor, { language: "sql", value: executeQuery.input, options: EDITOR_OPTIONS, onChange: onChange, editorDidMount: editorDidMount, theme: `vs-${theme}` }) })) })), renderControls()] })), _jsx("div", Object.assign({ className: b('pane-wrapper') }, { children: props.showPreview ? renderPreview() : result }))] })) })));
293
+ }) }, { children: [_jsx("div", Object.assign({ className: b('monaco-wrapper') }, { children: _jsx("div", Object.assign({ className: b('monaco') }, { children: _jsx(MonacoEditor, { language: "sql", value: executeQuery.input, options: EDITOR_OPTIONS, onChange: onChange, editorDidMount: editorDidMount, theme: `vs-${theme}` }) })) })), renderControls()] })), _jsx("div", Object.assign({ className: b('pane-wrapper') }, { children: _jsx(Result, { executeQuery: executeQuery, explainQuery: explainQuery, resultVisibilityState: resultVisibilityState, onExpandResultHandler: onExpandResultHandler, onCollapseResultHandler: onCollapseResultHandler, type: type, handleAstQuery: handleAstQuery, theme: theme, resultType: resultType, path: path, showPreview: showPreview }) }))] })) })));
320
294
  }
321
295
  const mapStateToProps = (state) => {
322
- var _a;
323
296
  return {
324
297
  executeQuery: state.executeQuery,
325
298
  explainQuery: state.explainQuery,
326
299
  showPreview: state.schema.showPreview,
327
- currentSchema: state.schema.currentSchema,
328
- monacoHotKey: (_a = state.executeQuery) === null || _a === void 0 ? void 0 : _a.monacoHotKey,
329
300
  };
330
301
  };
331
302
  const mapDispatchToProps = {
@@ -336,8 +307,20 @@ const mapDispatchToProps = {
336
307
  getExplainQuery,
337
308
  getExplainQueryAst,
338
309
  setShowPreview,
339
- setMonacoHotKey,
340
310
  setTenantPath,
341
311
  };
342
- QueryEditor.propTypes = propTypes;
343
312
  export default connect(mapStateToProps, mapDispatchToProps)(QueryEditor);
313
+ function Result({ executeQuery, explainQuery, resultVisibilityState, onExpandResultHandler, onCollapseResultHandler, type, handleAstQuery, theme, resultType, path, showPreview, }) {
314
+ if (showPreview) {
315
+ return _jsx(Preview, { database: path, type: type });
316
+ }
317
+ if (resultType === RESULT_TYPES.EXECUTE) {
318
+ const { data, error, stats } = executeQuery;
319
+ return data || error ? (_jsx(ExecuteResult, { data: data, stats: stats, error: error, isResultsCollapsed: resultVisibilityState.collapsed, onExpandResults: onExpandResultHandler, onCollapseResults: onCollapseResultHandler })) : null;
320
+ }
321
+ if (resultType === RESULT_TYPES.EXPLAIN) {
322
+ const { data, dataAst, error, loading, loadingAst } = explainQuery;
323
+ return (_jsx(ExplainResult, { error: error, explain: data, astQuery: handleAstQuery, ast: dataAst, loading: loading, loadingAst: loadingAst, theme: theme, isResultsCollapsed: resultVisibilityState.collapsed, onExpandResults: onExpandResultHandler, onCollapseResults: onCollapseResultHandler }));
324
+ }
325
+ return null;
326
+ }
@@ -10,7 +10,7 @@ interface QueryEditorControlsProps {
10
10
  disabled: boolean;
11
11
  onUpdateQueryMode: (mode: QueryMode) => void;
12
12
  queryMode: QueryMode;
13
- highlitedAction: QueryAction;
13
+ highlightedAction: QueryAction;
14
14
  }
15
- export declare const QueryEditorControls: ({ onRunButtonClick, runIsLoading, onExplainButtonClick, explainIsLoading, onSaveQueryClick, savedQueries, disabled, onUpdateQueryMode, queryMode, highlitedAction, }: QueryEditorControlsProps) => JSX.Element;
15
+ export declare const QueryEditorControls: ({ onRunButtonClick, runIsLoading, onExplainButtonClick, explainIsLoading, onSaveQueryClick, savedQueries, disabled, onUpdateQueryMode, queryMode, highlightedAction, }: QueryEditorControlsProps) => JSX.Element;
16
16
  export {};
@@ -33,7 +33,7 @@ const QueryModeSelectorOptions = {
33
33
  description: i18n('method-description.pg'),
34
34
  },
35
35
  };
36
- export const QueryEditorControls = ({ onRunButtonClick, runIsLoading, onExplainButtonClick, explainIsLoading, onSaveQueryClick, savedQueries, disabled, onUpdateQueryMode, queryMode, highlitedAction, }) => {
36
+ export const QueryEditorControls = ({ onRunButtonClick, runIsLoading, onExplainButtonClick, explainIsLoading, onSaveQueryClick, savedQueries, disabled, onUpdateQueryMode, queryMode, highlightedAction, }) => {
37
37
  const querySelectorMenuItems = useMemo(() => {
38
38
  return Object.entries(QueryModeSelectorOptions).map(([mode, { title, description }]) => {
39
39
  return {
@@ -44,8 +44,8 @@ export const QueryEditorControls = ({ onRunButtonClick, runIsLoading, onExplainB
44
44
  };
45
45
  });
46
46
  }, [onUpdateQueryMode]);
47
- const runView = highlitedAction === 'execute' ? 'action' : undefined;
48
- const explainView = highlitedAction === 'explain' ? 'action' : undefined;
47
+ const runView = highlightedAction === 'execute' ? 'action' : undefined;
48
+ const explainView = highlightedAction === 'explain' ? 'action' : undefined;
49
49
  return (_jsxs("div", Object.assign({ className: b() }, { children: [_jsxs("div", Object.assign({ className: b('left') }, { children: [_jsxs(Button, Object.assign({ onClick: () => {
50
50
  onRunButtonClick(queryMode);
51
51
  }, disabled: disabled, loading: runIsLoading, view: runView }, { children: [_jsx(Icon, { name: "startPlay", viewBox: "0 0 16 16", width: 16, height: 16 }), 'Run'] })), _jsx(Button, Object.assign({ onClick: () => {
@@ -1,4 +1,14 @@
1
1
  import type { TenantQueryTab } from '../../../../store/reducers/tenant/types';
2
+ export declare const queryEditorTabs: ({
3
+ id: "newQuery";
4
+ title: string;
5
+ } | {
6
+ id: "history";
7
+ title: string;
8
+ } | {
9
+ id: "saved";
10
+ title: string;
11
+ })[];
2
12
  interface QueryEditorTabsProps {
3
13
  className?: string;
4
14
  activeTab?: TenantQueryTab;
@@ -18,7 +18,7 @@ const saved = {
18
18
  id: TENANT_QUERY_TABS_ID.saved,
19
19
  title: i18n('tabs.saved'),
20
20
  };
21
- const queryEditorTabs = [newQuery, history, saved];
21
+ export const queryEditorTabs = [newQuery, history, saved];
22
22
  export const QueryTabs = ({ className, activeTab }) => {
23
23
  const location = useLocation();
24
24
  const queryParams = parseQuery(location);
@@ -1,2 +1,2 @@
1
1
  import type { KeyValueRow } from '../../../../types/api/query';
2
- export declare const getPreparedResult: (data: KeyValueRow[] | undefined) => string;
2
+ export declare function getPreparedResult(data: KeyValueRow[] | undefined): string;
@@ -1,23 +1,25 @@
1
- export const getPreparedResult = (data) => {
1
+ export function getPreparedResult(data) {
2
2
  const columnDivider = '\t';
3
3
  const rowDivider = '\n';
4
4
  if (!(data === null || data === void 0 ? void 0 : data.length)) {
5
5
  return '';
6
6
  }
7
7
  const columnHeaders = Object.keys(data[0]);
8
- const rows = Array(columnHeaders).concat(data);
9
- return rows
10
- .map((item) => {
11
- const row = [];
12
- for (const field in item) {
13
- if (typeof item[field] === 'object' || Array.isArray(item[field])) {
14
- row.push(JSON.stringify(item[field]));
15
- }
16
- else {
17
- row.push(item[field]);
18
- }
8
+ const rows = [columnHeaders.map(escapeValue).join(columnDivider)];
9
+ for (const row of data) {
10
+ const value = [];
11
+ for (const column of columnHeaders) {
12
+ const v = row[column];
13
+ value.push(escapeValue(typeof v === 'object' ? JSON.stringify(v) : `${v}`));
19
14
  }
20
- return row.join(columnDivider);
21
- })
22
- .join(rowDivider);
23
- };
15
+ rows.push(value.join(columnDivider));
16
+ }
17
+ return rows.join(rowDivider);
18
+ }
19
+ function escapeValue(value) {
20
+ return value
21
+ .replaceAll('\\', '\\\\')
22
+ .replaceAll('\n', '\\n')
23
+ .replaceAll('\r', '\\r')
24
+ .replaceAll('\t', '\\t');
25
+ }
@@ -4,6 +4,7 @@ import { useDispatch, useSelector } from 'react-redux';
4
4
  import cn from 'bem-cn-lite';
5
5
  import { useLocation } from 'react-router';
6
6
  import qs from 'qs';
7
+ import { Helmet } from 'react-helmet-async';
7
8
  import { DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, DEFAULT_SIZE_TENANT_KEY } from '../../utils/constants';
8
9
  import { useTypedSelector } from '../../utils/hooks';
9
10
  import { setHeaderBreadcrumbs } from '../../store/reducers/header/header';
@@ -13,6 +14,7 @@ import { AccessDenied } from '../../components/Errors/403';
13
14
  import { ObjectSummary } from './ObjectSummary/ObjectSummary';
14
15
  import ObjectGeneral from './ObjectGeneral/ObjectGeneral';
15
16
  import { PaneVisibilityActionTypes, paneVisibilityToggleReducerCreator, } from './utils/paneVisibilityToggleHelpers';
17
+ import i18n from './i18n';
16
18
  import './Tenant.scss';
17
19
  const b = cn('tenant-page');
18
20
  const getTenantSummaryState = () => {
@@ -61,6 +63,7 @@ function Tenant(props) {
61
63
  dispatchSummaryVisibilityAction(PaneVisibilityActionTypes.clear);
62
64
  };
63
65
  const showBlockingError = schemaStatus === 403;
64
- return (_jsx("div", Object.assign({ className: b() }, { children: showBlockingError ? (_jsx(AccessDenied, {})) : (_jsxs(SplitPane, Object.assign({ defaultSizePaneKey: DEFAULT_SIZE_TENANT_KEY, defaultSizes: [25, 75], triggerCollapse: summaryVisibilityState.triggerCollapse, triggerExpand: summaryVisibilityState.triggerExpand, minSize: [36, 200], onSplitStartDragAdditional: onSplitStartDragAdditional }, { children: [_jsx(ObjectSummary, { type: preloadedPathType || currentPathType, subType: preloadedPathSubType || currentPathSubType, onCollapseSummary: onCollapseSummaryHandler, onExpandSummary: onExpandSummaryHandler, isCollapsed: summaryVisibilityState.collapsed }), _jsx(ObjectGeneral, { type: preloadedPathType || currentPathType, additionalTenantProps: props.additionalTenantProps, additionalNodesProps: props.additionalNodesProps })] }))) })));
66
+ const title = currentSchemaPath || tenantName || i18n('page.title');
67
+ return (_jsxs("div", Object.assign({ className: b() }, { children: [_jsx(Helmet, { defaultTitle: `${title} — YDB Monitoring`, titleTemplate: `%s — ${title} — YDB Monitoring` }), showBlockingError ? (_jsx(AccessDenied, {})) : (_jsxs(SplitPane, Object.assign({ defaultSizePaneKey: DEFAULT_SIZE_TENANT_KEY, defaultSizes: [25, 75], triggerCollapse: summaryVisibilityState.triggerCollapse, triggerExpand: summaryVisibilityState.triggerExpand, minSize: [36, 200], onSplitStartDragAdditional: onSplitStartDragAdditional }, { children: [_jsx(ObjectSummary, { type: preloadedPathType || currentPathType, subType: preloadedPathSubType || currentPathSubType, onCollapseSummary: onCollapseSummaryHandler, onExpandSummary: onExpandSummaryHandler, isCollapsed: summaryVisibilityState.collapsed }), _jsx(ObjectGeneral, { type: preloadedPathType || currentPathType, additionalTenantProps: props.additionalTenantProps, additionalNodesProps: props.additionalNodesProps })] })))] })));
65
68
  }
66
69
  export default Tenant;
@@ -1,4 +1,5 @@
1
1
  {
2
+ "page.title": "Database",
2
3
  "acl.owner": "Owner",
3
4
  "acl.empty": "No Acl data",
4
5
  "summary.navigation": "Navigation",
@@ -1,2 +1,2 @@
1
- declare const _default: (key: string, params?: import("@gravity-ui/i18n").Params | undefined) => string;
1
+ declare const _default: (key: "page.title" | "acl.owner" | "acl.empty" | "summary.navigation" | "summary.showPreview" | "summary.copySchemaPath" | "actions.copied" | "actions.notCopied" | "actions.externalTableSelectUnavailable" | "actions.copyPath" | "actions.openPreview" | "actions.createTable" | "actions.createExternalTable" | "actions.createTopic" | "actions.dropTable" | "actions.dropTopic" | "actions.alterTable" | "actions.alterTopic" | "actions.selectQuery" | "actions.upsertQuery", params?: import("@gravity-ui/i18n").Params | undefined) => string;
2
2
  export default _default;
@@ -1,7 +1,5 @@
1
- import { i18n, Lang } from '../../../utils/i18n';
1
+ import { registerKeysets } from '../../../utils/i18n';
2
2
  import en from './en.json';
3
3
  import ru from './ru.json';
4
4
  const COMPONENT = 'ydb-tenant';
5
- i18n.registerKeyset(Lang.En, COMPONENT, en);
6
- i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
7
- export default i18n.keyset(COMPONENT);
5
+ export default registerKeysets(COMPONENT, { en, ru });
@@ -1,4 +1,5 @@
1
1
  {
2
+ "page.title": "База данных",
2
3
  "acl.owner": "Владелец",
3
4
  "acl.empty": "Нет данных об Acl",
4
5
  "summary.navigation": "Навигация",
@@ -3,6 +3,7 @@ export declare type SettingsElementType = 'switch' | 'radio';
3
3
  export interface SettingProps {
4
4
  type?: SettingsElementType;
5
5
  title: string;
6
+ description?: ReactNode;
6
7
  settingKey: string;
7
8
  helpPopoverContent?: ReactNode;
8
9
  options?: {
@@ -12,4 +13,4 @@ export interface SettingProps {
12
13
  defaultValue?: unknown;
13
14
  onValueUpdate?: VoidFunction;
14
15
  }
15
- export declare const Setting: ({ type, settingKey, title, helpPopoverContent, options, defaultValue, onValueUpdate, }: SettingProps) => JSX.Element;
16
+ export declare const Setting: ({ type, settingKey, title, description, helpPopoverContent, options, defaultValue, onValueUpdate, }: SettingProps) => JSX.Element;