ydb-embedded-ui 5.0.0 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/components/BasicNodeViewer/BasicNodeViewer.d.ts +2 -2
- package/dist/components/BasicNodeViewer/BasicNodeViewer.js +1 -1
- package/dist/components/EntityStatus/EntityStatus.scss +1 -1
- package/dist/components/FullNodeViewer/FullNodeViewer.d.ts +2 -2
- package/dist/components/FullNodeViewer/FullNodeViewer.js +1 -1
- package/dist/components/LagImages/LagImages.js +2 -2
- package/dist/components/ProgressViewer/ProgressViewer.js +6 -5
- package/dist/components/ProgressViewer/ProgressViewer.scss +33 -17
- package/dist/components/TabletsOverall/TabletsOverall.js +6 -6
- package/dist/containers/App/App.js +2 -1
- package/dist/containers/App/Content.js +6 -12
- package/dist/containers/App/Providers.js +2 -1
- package/dist/containers/App/appSlots.d.ts +7 -7
- package/dist/containers/AppIcons/AppIcons.js +1 -1
- package/dist/containers/Cluster/Cluster.js +45 -27
- package/dist/containers/Cluster/Cluster.scss +15 -0
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.js +4 -18
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +0 -40
- package/dist/containers/Cluster/utils.d.ts +6 -1
- package/dist/containers/Cluster/utils.js +11 -3
- package/dist/containers/Clusters/Clusters.js +4 -3
- package/dist/containers/Clusters/columns.js +1 -1
- package/dist/containers/Clusters/constants.d.ts +1 -1
- package/dist/containers/Clusters/i18n/en.json +2 -1
- package/dist/containers/Clusters/i18n/index.d.ts +1 -1
- package/dist/containers/Clusters/i18n/index.js +2 -4
- package/dist/containers/Clusters/i18n/ru.json +2 -1
- package/dist/containers/Node/Node.js +11 -13
- package/dist/containers/Node/NodePages.js +4 -1
- package/dist/containers/Node/i18n/index.d.ts +1 -1
- package/dist/containers/Node/i18n/index.js +2 -4
- package/dist/containers/Nodes/getNodesColumns.js +2 -1
- package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.d.ts +1 -1
- package/dist/containers/Storage/StorageNodes/getStorageNodesColumns.d.ts +1 -1
- package/dist/containers/Storage/StorageNodes/getStorageNodesColumns.js +2 -1
- package/dist/containers/Tablet/Tablet.js +24 -20
- package/dist/containers/Tablet/i18n/index.d.ts +1 -1
- package/dist/containers/Tablet/i18n/index.js +2 -4
- package/dist/containers/TabletsFilters/TabletsFilters.d.ts +2 -0
- package/dist/containers/TabletsFilters/TabletsFilters.js +25 -19
- package/dist/containers/TabletsFilters/i18n/en.json +3 -0
- package/dist/containers/TabletsFilters/i18n/index.d.ts +2 -0
- package/dist/containers/TabletsFilters/i18n/index.js +5 -0
- package/dist/containers/TabletsFilters/i18n/ru.json +3 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.js +12 -11
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.d.ts +19 -0
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.js +2 -1
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.d.ts +7 -25
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +88 -92
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.scss +1 -33
- package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/en.json +4 -0
- package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/index.d.ts +2 -0
- package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/index.js +5 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.js +4 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.js +3 -4
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +12 -5
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.d.ts +2 -2
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.js +7 -10
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +7 -5
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/index.js +0 -2
- package/dist/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.js +10 -0
- package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.d.ts +1 -1
- package/dist/containers/Tenant/Query/Query.d.ts +2 -2
- package/dist/containers/Tenant/Query/Query.js +5 -2
- package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.d.ts +29 -31
- package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +150 -167
- package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.d.ts +2 -2
- package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.js +3 -3
- package/dist/containers/Tenant/Query/QueryTabs/QueryTabs.d.ts +10 -0
- package/dist/containers/Tenant/Query/QueryTabs/QueryTabs.js +1 -1
- package/dist/containers/Tenant/Query/utils/getPreparedResult.d.ts +1 -1
- package/dist/containers/Tenant/Query/utils/getPreparedResult.js +18 -16
- package/dist/containers/Tenant/Tenant.js +4 -1
- package/dist/containers/Tenant/i18n/en.json +1 -0
- package/dist/containers/Tenant/i18n/index.d.ts +1 -1
- package/dist/containers/Tenant/i18n/index.js +2 -4
- package/dist/containers/Tenant/i18n/ru.json +1 -0
- package/dist/containers/Versions/NodesTreeTitle/NodesTreeTitle.scss +1 -1
- package/dist/routes.d.ts +5 -0
- package/dist/routes.js +4 -0
- package/dist/services/api.d.ts +2 -1
- package/dist/services/api.js +2 -2
- package/dist/services/settings.d.ts +0 -1
- package/dist/services/settings.js +1 -14
- package/dist/store/index.d.ts +1 -1
- package/dist/store/reducers/cluster/cluster.d.ts +8 -2
- package/dist/store/reducers/cluster/cluster.js +29 -1
- package/dist/store/reducers/cluster/types.d.ts +4 -2
- package/dist/store/reducers/executeQuery.d.ts +1 -10
- package/dist/store/reducers/executeQuery.js +26 -29
- package/dist/store/reducers/executeTopQueries/executeTopQueries.js +2 -1
- package/dist/store/reducers/executeTopQueries/utils.js +7 -4
- package/dist/store/reducers/hotKeys/hotKeys.d.ts +25 -0
- package/dist/store/reducers/hotKeys/hotKeys.js +49 -0
- package/dist/store/reducers/hotKeys/types.d.ts +10 -0
- package/dist/store/reducers/hotKeys/types.js +1 -0
- package/dist/store/reducers/index.d.ts +2 -6
- package/dist/store/reducers/index.js +1 -1
- package/dist/store/reducers/node/node.d.ts +1 -1
- package/dist/store/reducers/node/node.js +2 -0
- package/dist/store/reducers/node/selectors.js +1 -1
- package/dist/store/reducers/node/types.d.ts +7 -3
- package/dist/store/reducers/node/utils.d.ts +3 -0
- package/dist/store/reducers/node/utils.js +8 -0
- package/dist/store/reducers/nodes/types.d.ts +1 -1
- package/dist/store/reducers/nodes/utils.js +3 -3
- package/dist/store/reducers/storage/types.d.ts +2 -0
- package/dist/store/reducers/storage/utils.js +3 -3
- package/dist/store/reducers/tenants/utils.d.ts +4 -3
- package/dist/store/reducers/tenants/utils.js +17 -12
- package/dist/store/reducers/tooltip.d.ts +1 -1
- package/dist/types/api/hotkeys.d.ts +7 -0
- package/dist/types/api/hotkeys.js +1 -0
- package/dist/types/api/nodes.d.ts +2 -1
- package/dist/types/store/executeQuery.d.ts +3 -6
- package/dist/types/store/explainQuery.d.ts +1 -0
- package/dist/utils/constants.d.ts +1 -1
- package/dist/utils/constants.js +1 -1
- package/dist/utils/diagnostics.d.ts +1 -0
- package/dist/utils/diagnostics.js +1 -0
- package/dist/utils/i18n/i18n.d.ts +2 -1
- package/dist/utils/i18n/i18n.js +15 -2
- package/dist/utils/monitoring.js +1 -3
- package/dist/utils/versions/getVersionsColors.js +1 -1
- package/package.json +9 -8
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +0 -26
- package/dist/store/reducers/hotKeys.d.ts +0 -11
- 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,
|
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
|
34
|
-
|
35
|
-
|
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,
|
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
|
-
|
58
|
+
setPath(path);
|
67
59
|
}
|
68
|
-
}, [changeUserInput,
|
60
|
+
}, [changeUserInput, setPath, path, savedPath]);
|
69
61
|
const [resultVisibilityState, dispatchResultVisibilityState] = useReducer(paneVisibilityToggleReducerCreator(DEFAULT_IS_QUERY_RESULT_COLLAPSED), initialTenantCommonInfoState);
|
70
|
-
const editorRef = useRef(
|
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 {
|
103
|
+
const { input, history } = executeQuery;
|
96
104
|
const hasUnsavedInput = input
|
97
|
-
? input !==
|
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 =
|
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 =
|
115
|
+
window.onbeforeunload = null;
|
104
116
|
}
|
105
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
170
|
+
handleGetExplainQueryClick(queryMode);
|
119
171
|
}
|
120
172
|
else {
|
121
|
-
|
173
|
+
handleSendExecuteClick(queryMode);
|
122
174
|
}
|
175
|
+
break;
|
123
176
|
}
|
124
|
-
case MONACO_HOT_KEY_ACTIONS.
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
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
|
-
|
135
|
-
|
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:
|
205
|
+
precondition: undefined,
|
155
206
|
// A rule to evaluate on top of the precondition in order to dispatch the keybindings.
|
156
|
-
keybindingContext:
|
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
|
161
|
-
run:
|
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:
|
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:
|
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
|
-
|
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 {
|
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
|
305
|
-
newSavedQueries
|
280
|
+
if (queryIndex === -1) {
|
281
|
+
newSavedQueries.push(newQuery);
|
306
282
|
}
|
307
283
|
else {
|
308
|
-
newSavedQueries
|
284
|
+
newSavedQueries[queryIndex] = newQuery;
|
309
285
|
}
|
310
286
|
setSavedQueries(newSavedQueries);
|
311
287
|
};
|
312
288
|
const renderControls = () => {
|
313
|
-
|
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:
|
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
|
-
|
13
|
+
highlightedAction: QueryAction;
|
14
14
|
}
|
15
|
-
export declare const QueryEditorControls: ({ onRunButtonClick, runIsLoading, onExplainButtonClick, explainIsLoading, onSaveQueryClick, savedQueries, disabled, onUpdateQueryMode, queryMode,
|
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,
|
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 =
|
48
|
-
const explainView =
|
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
|
2
|
+
export declare function getPreparedResult(data: KeyValueRow[] | undefined): string;
|
@@ -1,23 +1,25 @@
|
|
1
|
-
export
|
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 =
|
9
|
-
|
10
|
-
|
11
|
-
const
|
12
|
-
|
13
|
-
|
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
|
-
|
21
|
-
}
|
22
|
-
|
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
|
-
|
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,2 +1,2 @@
|
|
1
|
-
declare const _default: (key:
|
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 {
|
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
|
-
|
6
|
-
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
7
|
-
export default i18n.keyset(COMPONENT);
|
5
|
+
export default registerKeysets(COMPONENT, { en, ru });
|
package/dist/routes.d.ts
CHANGED
@@ -18,4 +18,9 @@ export declare const parseQuery: (location: Location) => qs.ParsedQs;
|
|
18
18
|
export declare type Query = Record<string | number, string | number | string[] | number[] | undefined>;
|
19
19
|
export declare function createHref(route: string, params?: Record<string, string | number>, query?: Query): string;
|
20
20
|
export declare const createExternalUILink: (query?: {}) => string;
|
21
|
+
export declare function getLocationObjectFromHref(href: string): {
|
22
|
+
pathname: string;
|
23
|
+
search: string;
|
24
|
+
hash: string;
|
25
|
+
};
|
21
26
|
export default routes;
|
package/dist/routes.js
CHANGED
@@ -53,4 +53,8 @@ export function createHref(route, params, query = {}) {
|
|
53
53
|
// window.location has the full pathname, while location from router ignores path to project
|
54
54
|
// this navigation assumes page reloading
|
55
55
|
export const createExternalUILink = (query = {}) => createHref(window.location.pathname, undefined, query);
|
56
|
+
export function getLocationObjectFromHref(href) {
|
57
|
+
const { pathname, search, hash } = new URL(href, 'http://localhost');
|
58
|
+
return { pathname, search, hash };
|
59
|
+
}
|
56
60
|
export default routes;
|