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
@@ -1,5 +1,7 @@
1
1
  import {useCallback, useEffect, useRef, useState} from 'react';
2
2
  import {useDispatch} from 'react-redux';
3
+ import {useHistory, useLocation} from 'react-router';
4
+ import qs from 'qs';
3
5
  import cn from 'bem-cn-lite';
4
6
 
5
7
  import DataTable, {Column, Settings} from '@gravity-ui/react-data-table';
@@ -21,13 +23,14 @@ import type {EPathType} from '../../../../types/api/schema';
21
23
  import type {ITopQueriesFilters} from '../../../../types/store/executeTopQueries';
22
24
  import type {IQueryResult} from '../../../../types/store/query';
23
25
 
24
- import {formatDateTime} from '../../../../utils';
26
+ import {formatDateTime, formatNumber} from '../../../../utils';
25
27
  import {DEFAULT_TABLE_SETTINGS, HOUR_IN_SECONDS} from '../../../../utils/constants';
26
28
  import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
27
29
  import {prepareQueryError} from '../../../../utils/query';
30
+ import routes, {createHref} from '../../../../routes';
28
31
 
29
32
  import {isColumnEntityType} from '../../utils/schema';
30
- import {TenantGeneralTabsIds} from '../../TenantPages';
33
+ import {TenantGeneralTabsIds, TenantTabsGroups} from '../../TenantPages';
31
34
 
32
35
  import i18n from './i18n';
33
36
  import './TopQueries.scss';
@@ -43,19 +46,41 @@ const MAX_QUERY_HEIGHT = 10;
43
46
  const COLUMNS: Column<KeyValueRow>[] = [
44
47
  {
45
48
  name: 'CPUTimeUs',
46
- width: 140,
47
- sortAccessor: (row) => Number(row['CPUTimeUs']),
49
+ sortAccessor: (row) => Number(row.CPUTimeUs),
50
+ align: DataTable.RIGHT,
48
51
  },
49
52
  {
50
53
  name: 'QueryText',
51
54
  width: 500,
52
55
  sortable: false,
53
- render: ({value}) => <TruncatedQuery value={value} maxQueryHeight={MAX_QUERY_HEIGHT} />,
56
+ render: ({row}) => (
57
+ <div className={b('query')}>
58
+ <TruncatedQuery value={row.QueryText} maxQueryHeight={MAX_QUERY_HEIGHT} />
59
+ </div>
60
+ ),
61
+ },
62
+ {
63
+ name: 'EndTime',
64
+ render: ({row}) => formatDateTime(new Date(row.EndTime as string).getTime()),
65
+ align: DataTable.RIGHT,
66
+ },
67
+ {
68
+ name: 'ReadRows',
69
+ render: ({row}) => formatNumber(row.ReadRows),
70
+ sortAccessor: (row) => Number(row.ReadRows),
71
+ align: DataTable.RIGHT,
72
+ },
73
+ {
74
+ name: 'ReadBytes',
75
+ render: ({row}) => formatNumber(row.ReadBytes),
76
+ sortAccessor: (row) => Number(row.ReadBytes),
77
+ align: DataTable.RIGHT,
54
78
  },
55
79
  {
56
- name: 'IntervalEnd',
57
- width: 140,
58
- render: ({value}) => formatDateTime(new Date(value as string).getTime()),
80
+ name: 'UserSID',
81
+ render: ({row}) => <div className={b('user-sid')}>{row.UserSID || '–'}</div>,
82
+ sortAccessor: (row) => String(row.UserSID),
83
+ align: DataTable.LEFT,
59
84
  },
60
85
  ];
61
86
 
@@ -65,8 +90,10 @@ interface TopQueriesProps {
65
90
  type?: EPathType;
66
91
  }
67
92
 
68
- export const TopQueries = ({path, type, changeSchemaTab}: TopQueriesProps) => {
93
+ export const TopQueries = ({path, type}: TopQueriesProps) => {
69
94
  const dispatch = useDispatch();
95
+ const location = useLocation();
96
+ const history = useHistory();
70
97
 
71
98
  const {autorefresh} = useTypedSelector((state) => state.schema);
72
99
 
@@ -144,9 +171,19 @@ export const TopQueries = ({path, type, changeSchemaTab}: TopQueriesProps) => {
144
171
  const {QueryText: input} = row;
145
172
 
146
173
  dispatch(changeUserInput({input}));
147
- changeSchemaTab(TenantGeneralTabsIds.query);
174
+
175
+ const queryParams = qs.parse(location.search, {
176
+ ignoreQueryPrefix: true,
177
+ });
178
+
179
+ const queryPath = createHref(routes.tenant, undefined, {
180
+ ...queryParams,
181
+ [TenantTabsGroups.general]: TenantGeneralTabsIds.query,
182
+ });
183
+
184
+ history.push(queryPath);
148
185
  },
149
- [changeSchemaTab, dispatch],
186
+ [dispatch, history, location],
150
187
  );
151
188
 
152
189
  const handleTextSearchUpdate = (text: string) => {
@@ -179,7 +216,7 @@ export const TopQueries = ({path, type, changeSchemaTab}: TopQueriesProps) => {
179
216
  }
180
217
 
181
218
  return (
182
- <div className={b('result')}>
219
+ <div className={b('table')}>
183
220
  <DataTable
184
221
  columns={COLUMNS}
185
222
  data={data}
@@ -20,6 +20,7 @@ import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema
20
20
  import {EShardsWorkloadMode, IShardsWorkloadFilters} from '../../../../types/store/shardsWorkload';
21
21
 
22
22
  import type {EPathType} from '../../../../types/api/schema';
23
+ import type {CellValue, KeyValueRow} from '../../../../types/api/query';
23
24
 
24
25
  import {formatDateTime, formatNumber} from '../../../../utils';
25
26
  import {DEFAULT_TABLE_SETTINGS, HOUR_IN_SECONDS} from '../../../../utils/constants';
@@ -57,10 +58,17 @@ const tableColumnsNames = {
57
58
  IntervalEnd: 'IntervalEnd',
58
59
  };
59
60
 
60
- function prepareCPUWorkloadValue(value: string) {
61
+ function prepareCPUWorkloadValue(value: string | number) {
61
62
  return `${(Number(value) * 100).toFixed(2)}%`;
62
63
  }
63
64
 
65
+ function prepareDateTimeValue(value: CellValue) {
66
+ if (!value) {
67
+ return '–';
68
+ }
69
+ return formatDateTime(new Date(value).getTime());
70
+ }
71
+
64
72
  function stringToDataTableSortOrder(value: string): SortOrder[] | undefined {
65
73
  return value
66
74
  ? value.split(',').map((columnId) => ({
@@ -190,16 +198,17 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
190
198
  };
191
199
  };
192
200
 
193
- const columns: Column<any>[] = [
201
+ const columns: Column<KeyValueRow>[] = [
194
202
  {
195
203
  name: tableColumnsNames.Path,
196
- render: ({value: relativeNodePath}) => {
204
+ render: ({row}) => {
205
+ // row.Path - relative schema path
197
206
  return (
198
207
  <span
199
- onClick={onSchemaClick(tenantPath + relativeNodePath)}
208
+ onClick={onSchemaClick(tenantPath + row.Path)}
200
209
  className={bLink({view: 'normal'})}
201
210
  >
202
- {relativeNodePath as string}
211
+ {row.Path}
203
212
  </span>
204
213
  );
205
214
  },
@@ -207,25 +216,28 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
207
216
  },
208
217
  {
209
218
  name: tableColumnsNames.CPUCores,
210
- render: ({value}) => {
211
- return prepareCPUWorkloadValue(value as string);
219
+ render: ({row}) => {
220
+ return prepareCPUWorkloadValue(row.CPUCores || 0);
212
221
  },
213
222
  align: DataTable.RIGHT,
214
223
  },
215
224
  {
216
225
  name: tableColumnsNames.DataSize,
217
226
  header: 'DataSize (B)',
218
- render: ({value}) => {
219
- return formatNumber(value as number);
227
+ render: ({row}) => {
228
+ return formatNumber(row.DataSize);
220
229
  },
221
230
  align: DataTable.RIGHT,
222
231
  },
223
232
  {
224
233
  name: tableColumnsNames.TabletId,
225
- render: ({value}) => {
234
+ render: ({row}) => {
235
+ if (!row.TabletId) {
236
+ return '–';
237
+ }
226
238
  return (
227
- <InternalLink to={createHref(routes.tablet, {id: value})}>
228
- {value as string}
239
+ <InternalLink to={createHref(routes.tablet, {id: row.TabletId})}>
240
+ {row.TabletId}
229
241
  </InternalLink>
230
242
  );
231
243
  },
@@ -233,10 +245,13 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
233
245
  },
234
246
  {
235
247
  name: tableColumnsNames.NodeId,
236
- render: ({value: nodeId}) => {
248
+ render: ({row}) => {
249
+ if (!row.NodeId) {
250
+ return '–';
251
+ }
237
252
  return (
238
- <InternalLink to={getDefaultNodePath(nodeId as string)}>
239
- {nodeId as string}
253
+ <InternalLink to={getDefaultNodePath(row.NodeId)}>
254
+ {row.NodeId}
240
255
  </InternalLink>
241
256
  );
242
257
  },
@@ -245,7 +260,7 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
245
260
  },
246
261
  {
247
262
  name: tableColumnsNames.InFlightTxCount,
248
- render: ({value}) => formatNumber(value as number),
263
+ render: ({row}) => formatNumber(row.InFlightTxCount),
249
264
  align: DataTable.RIGHT,
250
265
  sortable: false,
251
266
  },
@@ -255,12 +270,16 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
255
270
  // after NodeId
256
271
  columns.splice(5, 0, {
257
272
  name: tableColumnsNames.PeakTime,
258
- render: ({value}) => formatDateTime(new Date(value as string).valueOf()),
273
+ render: ({row}) => {
274
+ return prepareDateTimeValue(row.PeakTime);
275
+ },
259
276
  sortable: false,
260
277
  });
261
278
  columns.push({
262
279
  name: tableColumnsNames.IntervalEnd,
263
- render: ({value}) => formatDateTime(new Date(value as string).getTime()),
280
+ render: ({row}) => {
281
+ return prepareDateTimeValue(row.IntervalEnd);
282
+ },
264
283
  });
265
284
  }
266
285
 
@@ -2,8 +2,9 @@ import React, {useRef, useState} from 'react';
2
2
  import cn from 'bem-cn-lite';
3
3
  import _ from 'lodash';
4
4
  import {Button, Popup} from '@gravity-ui/uikit';
5
+
5
6
  import TruncatedQuery from '../../../../components/TruncatedQuery/TruncatedQuery';
6
- import {useSelector} from 'react-redux';
7
+ import {useTypedSelector} from '../../../../utils/hooks';
7
8
 
8
9
  import './QueriesHistory.scss';
9
10
 
@@ -17,8 +18,7 @@ interface QueriesHistoryProps {
17
18
 
18
19
  function QueriesHistory(props: QueriesHistoryProps) {
19
20
  const [isHistoryVisible, setIsHistoryVisible] = useState(false);
20
- const history: string[] =
21
- useSelector((state: any) => state.executeQuery.history?.queries) ?? [];
21
+ const history = useTypedSelector((state) => state.executeQuery.history.queries) ?? [];
22
22
  const anchor = useRef(null);
23
23
 
24
24
  const onShowHistoryClick = () => {
@@ -0,0 +1,8 @@
1
+ .ydb-query-duration {
2
+ display: flex;
3
+ align-items: center;
4
+
5
+ margin-left: 10px;
6
+
7
+ color: var(--yc-color-text-complementary);
8
+ }
@@ -0,0 +1,21 @@
1
+ import block from 'bem-cn-lite';
2
+
3
+ import {formatDurationToShortTimeFormat, parseUsToMs} from '../../../../utils/timeParsers';
4
+
5
+ import './QueryDuration.scss';
6
+
7
+ interface QueryDurationProps {
8
+ duration?: string;
9
+ }
10
+
11
+ const b = block('ydb-query-duration');
12
+
13
+ export const QueryDuration = ({duration}: QueryDurationProps) => {
14
+ if (!duration) {
15
+ return null;
16
+ }
17
+
18
+ const parsedDuration = formatDurationToShortTimeFormat(parseUsToMs(duration), 1);
19
+
20
+ return <span className={b()}>{parsedDuration}</span>;
21
+ };
@@ -4,41 +4,36 @@ import {connect} from 'react-redux';
4
4
  import cn from 'bem-cn-lite';
5
5
  import _ from 'lodash';
6
6
  import MonacoEditor from 'react-monaco-editor';
7
- import {Button, DropdownMenu} from '@gravity-ui/uikit';
8
7
 
9
8
  import SplitPane from '../../../components/SplitPane';
10
9
  import {QueryResultTable} from '../../../components/QueryResultTable';
11
10
 
12
- import SaveQuery from './SaveQuery/SaveQuery';
13
11
  import SavedQueries from './SavedQueries/SavedQueries';
14
- import {Icon} from '../../../components/Icon';
15
12
  import QueryResult from './QueryResult/QueryResult';
16
13
  import QueryExplain from './QueryExplain/QueryExplain';
14
+ import {QueryEditorControls} from './QueryEditorControls/QueryEditorControls';
15
+ import {OldQueryEditorControls} from './QueryEditorControls/OldQueryEditorControls';
17
16
 
18
17
  import {
19
- sendQuery,
18
+ sendExecuteQuery,
20
19
  changeUserInput,
21
20
  saveQueryToHistory,
22
21
  goToPreviousQuery,
23
22
  goToNextQuery,
24
- selectRunAction,
25
- RUN_ACTIONS_VALUES,
26
23
  MONACO_HOT_KEY_ACTIONS,
27
24
  setMonacoHotKey,
28
25
  } from '../../../store/reducers/executeQuery';
29
26
  import {getExplainQuery, getExplainQueryAst} from '../../../store/reducers/explainQuery';
30
- import {getSettingValue, setSettingValue} from '../../../store/reducers/settings';
27
+ import {getParsedSettingValue, setSettingValue} from '../../../store/reducers/settings';
31
28
  import {
32
29
  DEFAULT_IS_QUERY_RESULT_COLLAPSED,
33
30
  DEFAULT_SIZE_RESULT_PANE_KEY,
34
31
  SAVED_QUERIES_KEY,
35
- QUERY_INITIAL_RUN_ACTION_KEY,
32
+ QUERY_INITIAL_MODE_KEY,
33
+ ENABLE_QUERY_MODES_FOR_EXPLAIN,
36
34
  } from '../../../utils/constants';
37
35
 
38
- import {parseJson} from '../../../utils/utils';
39
-
40
36
  import './QueryEditor.scss';
41
- import Divider from '../../../components/Divider/Divider';
42
37
  import QueriesHistory from './QueriesHistory/QueriesHistory';
43
38
  import {
44
39
  PaneVisibilityActionTypes,
@@ -47,11 +42,6 @@ import {
47
42
  import Preview from '../Preview/Preview';
48
43
  import {setShowPreview} from '../../../store/reducers/schema';
49
44
 
50
- export const RUN_ACTIONS = [
51
- {value: RUN_ACTIONS_VALUES.script, content: 'Run Script'},
52
- {value: RUN_ACTIONS_VALUES.scan, content: 'Run Scan'},
53
- ];
54
-
55
45
  const TABLE_SETTINGS = {
56
46
  sortable: false,
57
47
  };
@@ -73,7 +63,7 @@ const RESULT_TYPES = {
73
63
  const b = cn('query-editor');
74
64
 
75
65
  const propTypes = {
76
- sendQuery: PropTypes.func,
66
+ sendExecuteQuery: PropTypes.func,
77
67
  path: PropTypes.string,
78
68
  response: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]),
79
69
  executeQuery: PropTypes.object,
@@ -81,6 +71,7 @@ const propTypes = {
81
71
  setMonacoHotKey: PropTypes.func,
82
72
  theme: PropTypes.string,
83
73
  type: PropTypes.string,
74
+ initialQueryMode: PropTypes.string,
84
75
  };
85
76
 
86
77
  const initialTenantCommonInfoState = {
@@ -92,6 +83,7 @@ function QueryEditor(props) {
92
83
  const [resultType, setResultType] = useState(RESULT_TYPES.EXECUTE);
93
84
 
94
85
  const [isResultLoaded, setIsResultLoaded] = useState(false);
86
+ const [queryMode, setQueryMode] = useState(props.initialQueryMode);
95
87
 
96
88
  const [resultVisibilityState, dispatchResultVisibilityState] = useReducer(
97
89
  paneVisibilityToggleReducerCreator(DEFAULT_IS_QUERY_RESULT_COLLAPSED),
@@ -155,7 +147,7 @@ function QueryEditor(props) {
155
147
  setMonacoHotKey(null);
156
148
  switch (monacoHotKey) {
157
149
  case MONACO_HOT_KEY_ACTIONS.sendQuery: {
158
- return handleSendClick();
150
+ return handleSendExecuteClick(queryMode);
159
151
  }
160
152
  case MONACO_HOT_KEY_ACTIONS.goPrev: {
161
153
  return handlePreviousHistoryClick();
@@ -246,17 +238,17 @@ function QueryEditor(props) {
246
238
  props.changeUserInput({input: newValue});
247
239
  };
248
240
 
249
- const handleSendClick = () => {
241
+ const handleSendExecuteClick = (mode) => {
250
242
  const {
251
243
  path,
252
- executeQuery: {input, history, runAction},
253
- sendQuery,
244
+ executeQuery: {input, history},
245
+ sendExecuteQuery,
254
246
  saveQueryToHistory,
255
247
  setShowPreview,
256
248
  } = props;
257
249
 
258
250
  setResultType(RESULT_TYPES.EXECUTE);
259
- sendQuery({query: input, database: path, action: runAction});
251
+ sendExecuteQuery({query: input, database: path, mode});
260
252
  setIsResultLoaded(true);
261
253
  setShowPreview(false);
262
254
 
@@ -267,15 +259,20 @@ function QueryEditor(props) {
267
259
  dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
268
260
  };
269
261
 
270
- const handleGetExplainQueryClick = () => {
262
+ const handleGetExplainQueryClick = (mode) => {
271
263
  const {
272
264
  path,
273
265
  executeQuery: {input},
274
266
  getExplainQuery,
275
267
  setShowPreview,
276
268
  } = props;
269
+
277
270
  setResultType(RESULT_TYPES.EXPLAIN);
278
- getExplainQuery({query: input, database: path});
271
+ getExplainQuery({
272
+ query: input,
273
+ database: path,
274
+ mode: mode,
275
+ });
279
276
  setIsResultLoaded(true);
280
277
  setShowPreview(false);
281
278
  dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
@@ -513,64 +510,42 @@ function QueryEditor(props) {
513
510
  setSettingValue(SAVED_QUERIES_KEY, JSON.stringify(newSavedQueries));
514
511
  };
515
512
 
516
- const renderControls = () => {
517
- const {executeQuery, explainQuery, savedQueries, selectRunAction, setSettingValue} = props;
518
- const {runAction} = executeQuery;
519
- const runIsDisabled = !executeQuery.input || executeQuery.loading;
520
- const runText = _.find(RUN_ACTIONS, {value: runAction}).content;
521
-
522
- const menuItems = RUN_ACTIONS.map((action) => {
523
- return {
524
- text: action.content,
525
- action: () => {
526
- selectRunAction(action.value);
527
- setSettingValue(QUERY_INITIAL_RUN_ACTION_KEY, action.value);
528
- },
529
- };
530
- });
513
+ const onUpdateQueryMode = (mode) => {
514
+ setQueryMode(mode);
515
+ props.setSettingValue(QUERY_INITIAL_MODE_KEY, mode);
516
+ };
531
517
 
532
- return (
533
- <div className={b('controls')}>
534
- <div className={b('control-run')}>
535
- <Button
536
- onClick={handleSendClick}
537
- view="action"
538
- pin="round-brick"
539
- disabled={runIsDisabled}
540
- loading={executeQuery.loading}
541
- >
542
- <Icon name="startPlay" viewBox="0 0 16 16" width={16} height={16} />
543
- {runText}
544
- </Button>
545
- <DropdownMenu
546
- items={menuItems}
547
- switcher={
548
- <Button
549
- view="action"
550
- pin="brick-round"
551
- disabled={runIsDisabled}
552
- loading={executeQuery.loading}
553
- className={b('select-query-action')}
554
- >
555
- <Icon name="chevron-down" width={16} height={16} />
556
- </Button>
557
- }
558
- />
559
- </div>
560
- <Button
561
- onClick={handleGetExplainQueryClick}
562
- disabled={!executeQuery.input}
563
- loading={explainQuery.loading}
564
- >
565
- Explain
566
- </Button>
567
- <Divider />
568
- <SaveQuery
518
+ const renderControls = () => {
519
+ const {executeQuery, explainQuery, savedQueries, enableQueryModesForExplain} = props;
520
+
521
+ if (enableQueryModesForExplain) {
522
+ return (
523
+ <QueryEditorControls
524
+ onRunButtonClick={handleSendExecuteClick}
525
+ runIsLoading={executeQuery.loading}
526
+ onExplainButtonClick={handleGetExplainQueryClick}
527
+ explainIsLoading={explainQuery.loading}
528
+ onSaveQueryClick={onSaveQueryHandler}
569
529
  savedQueries={savedQueries}
570
- onSaveQuery={onSaveQueryHandler}
571
- saveButtonDisabled={runIsDisabled}
530
+ disabled={!executeQuery.input}
531
+ onUpdateQueryMode={onUpdateQueryMode}
532
+ queryMode={queryMode}
572
533
  />
573
- </div>
534
+ );
535
+ }
536
+
537
+ return (
538
+ <OldQueryEditorControls
539
+ onRunButtonClick={handleSendExecuteClick}
540
+ runIsLoading={executeQuery.loading}
541
+ onExplainButtonClick={handleGetExplainQueryClick}
542
+ explainIsLoading={explainQuery.loading}
543
+ onSaveQueryClick={onSaveQueryHandler}
544
+ savedQueries={savedQueries}
545
+ disabled={!executeQuery.input}
546
+ onUpdateQueryMode={onUpdateQueryMode}
547
+ queryMode={queryMode}
548
+ />
574
549
  );
575
550
  };
576
551
 
@@ -631,7 +606,9 @@ const mapStateToProps = (state) => {
631
606
  return {
632
607
  executeQuery: state.executeQuery,
633
608
  explainQuery: state.explainQuery,
634
- savedQueries: parseJson(getSettingValue(state, SAVED_QUERIES_KEY)),
609
+ savedQueries: getParsedSettingValue(state, SAVED_QUERIES_KEY),
610
+ initialQueryMode: getParsedSettingValue(state, QUERY_INITIAL_MODE_KEY),
611
+ enableQueryModesForExplain: getParsedSettingValue(state, ENABLE_QUERY_MODES_FOR_EXPLAIN),
635
612
  showPreview: state.schema.showPreview,
636
613
  currentSchema: state.schema.currentSchema,
637
614
  monacoHotKey: state.executeQuery?.monacoHotKey,
@@ -639,7 +616,7 @@ const mapStateToProps = (state) => {
639
616
  };
640
617
 
641
618
  const mapDispatchToProps = {
642
- sendQuery,
619
+ sendExecuteQuery,
643
620
  changeUserInput,
644
621
  saveQueryToHistory,
645
622
  goToPreviousQuery,
@@ -647,7 +624,6 @@ const mapDispatchToProps = {
647
624
  getExplainQuery,
648
625
  getExplainQueryAst,
649
626
  setSettingValue,
650
- selectRunAction,
651
627
  setShowPreview,
652
628
  setMonacoHotKey,
653
629
  };
@@ -54,35 +54,6 @@
54
54
  align-items: center;
55
55
  }
56
56
 
57
- &__controls {
58
- display: flex;
59
- flex: 0 0 40px;
60
- align-items: flex-end;
61
-
62
- min-height: 40px;
63
- padding: 5px 20px;
64
-
65
- border-top: 1px solid var(--yc-color-line-generic);
66
- border-bottom: 1px solid var(--yc-color-line-generic);
67
- background-color: var(--yc-color-base-background);
68
- gap: 12px;
69
- }
70
-
71
- &__control-run {
72
- display: flex;
73
- align-items: center;
74
- .yc-select__option-text {
75
- display: none;
76
- }
77
-
78
- .yc-button__text {
79
- display: flex;
80
- justify-content: center;
81
- align-items: center;
82
- gap: 8px;
83
- }
84
- }
85
-
86
57
  &__history-controls {
87
58
  display: flex;
88
59
  align-items: center;
@@ -93,8 +64,4 @@
93
64
 
94
65
  color: var(--yc-color-text-secondary);
95
66
  }
96
-
97
- &__select-query-action {
98
- margin-left: 2px;
99
- }
100
67
  }