ydb-embedded-ui 3.5.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/containers/Tenant/QueryEditor/QueriesHistory/QueriesHistory.tsx +3 -3
  3. package/dist/containers/Tenant/QueryEditor/QueryDuration/QueryDuration.scss +8 -0
  4. package/dist/containers/Tenant/QueryEditor/QueryDuration/QueryDuration.tsx +21 -0
  5. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +58 -83
  6. package/dist/containers/Tenant/QueryEditor/QueryEditor.scss +0 -33
  7. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/OldQueryEditorControls.tsx +83 -0
  8. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.scss +57 -0
  9. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.tsx +84 -0
  10. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/shared.ts +23 -0
  11. package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.js +12 -23
  12. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.js +4 -6
  13. package/dist/containers/Tenant/QueryEditor/i18n/en.json +3 -0
  14. package/dist/containers/Tenant/QueryEditor/i18n/index.ts +11 -0
  15. package/dist/containers/Tenant/QueryEditor/i18n/ru.json +3 -0
  16. package/dist/containers/UserSettings/UserSettings.tsx +30 -1
  17. package/dist/services/api.d.ts +4 -3
  18. package/dist/services/api.js +2 -2
  19. package/dist/store/reducers/executeQuery.ts +12 -37
  20. package/dist/store/reducers/{explainQuery.js → explainQuery.ts} +44 -59
  21. package/dist/store/reducers/settings.js +18 -3
  22. package/dist/types/api/error.ts +14 -0
  23. package/dist/types/api/query.ts +226 -117
  24. package/dist/types/store/executeQuery.ts +4 -8
  25. package/dist/types/store/explainQuery.ts +38 -0
  26. package/dist/types/store/query.ts +23 -3
  27. package/dist/utils/constants.ts +2 -1
  28. package/dist/utils/error.ts +25 -0
  29. package/dist/utils/index.js +0 -49
  30. package/dist/utils/prepareQueryExplain.ts +7 -24
  31. package/dist/utils/query.test.ts +153 -231
  32. package/dist/utils/query.ts +44 -78
  33. package/dist/utils/timeParsers/i18n/en.json +9 -9
  34. package/dist/utils/timeParsers/i18n/ru.json +9 -9
  35. package/dist/utils/timeParsers/parsers.ts +9 -0
  36. package/dist/utils/utils.js +1 -2
  37. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.0.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.5.0...v4.0.0) (2023-04-28)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * app no longer parses query responses from older ydb versions
9
+ * v0.1 explain plans are no longer rendered
10
+
11
+ ### Features
12
+
13
+ * enable explain-script parsing, remove deprecated code ([5c6e9a2](https://github.com/ydb-platform/ydb-embedded-ui/commit/5c6e9a21026ea9eb3e32650e6fdda89c7900e7e6))
14
+ * **QueryEditor:** add explain query modes ([39ad943](https://github.com/ydb-platform/ydb-embedded-ui/commit/39ad9434c1622e22901e6cc1af1568e0edf6b434))
15
+ * **QueryEditor:** display query duration ([967f102](https://github.com/ydb-platform/ydb-embedded-ui/commit/967f10296d2362709654172ed7318509286efc78))
16
+ * remove support for explain v0.1 ([c8741a6](https://github.com/ydb-platform/ydb-embedded-ui/commit/c8741a69b82053185a07c7ba563455d4f28ecdce))
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * **query:** correctly process NetworkError on actions failure ([cf5bd6c](https://github.com/ydb-platform/ydb-embedded-ui/commit/cf5bd6c5c4c2972fec93b2dc9135c92c639fa5f9))
22
+ * **QueryExplain:** do not request ast when missing ([54cf151](https://github.com/ydb-platform/ydb-embedded-ui/commit/54cf151452e17256173736450f5727085ea591ff))
23
+ * **QueryExplain:** request AST if it is empty ([d028b4e](https://github.com/ydb-platform/ydb-embedded-ui/commit/d028b4ed08a98281baff81683204f1cbc1c20c37))
24
+
3
25
  ## [3.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.4.5...v3.5.0) (2023-04-18)
4
26
 
5
27
 
@@ -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,65 +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
- popupClassName={b('select-query-action-popup')}
548
- switcher={
549
- <Button
550
- view="action"
551
- pin="brick-round"
552
- disabled={runIsDisabled}
553
- loading={executeQuery.loading}
554
- className={b('select-query-action')}
555
- >
556
- <Icon name="chevron-down" width={16} height={16} />
557
- </Button>
558
- }
559
- />
560
- </div>
561
- <Button
562
- onClick={handleGetExplainQueryClick}
563
- disabled={!executeQuery.input}
564
- loading={explainQuery.loading}
565
- >
566
- Explain
567
- </Button>
568
- <Divider />
569
- <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}
570
529
  savedQueries={savedQueries}
571
- onSaveQuery={onSaveQueryHandler}
572
- saveButtonDisabled={runIsDisabled}
530
+ disabled={!executeQuery.input}
531
+ onUpdateQueryMode={onUpdateQueryMode}
532
+ queryMode={queryMode}
573
533
  />
574
- </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
+ />
575
549
  );
576
550
  };
577
551
 
@@ -632,7 +606,9 @@ const mapStateToProps = (state) => {
632
606
  return {
633
607
  executeQuery: state.executeQuery,
634
608
  explainQuery: state.explainQuery,
635
- 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),
636
612
  showPreview: state.schema.showPreview,
637
613
  currentSchema: state.schema.currentSchema,
638
614
  monacoHotKey: state.executeQuery?.monacoHotKey,
@@ -640,7 +616,7 @@ const mapStateToProps = (state) => {
640
616
  };
641
617
 
642
618
  const mapDispatchToProps = {
643
- sendQuery,
619
+ sendExecuteQuery,
644
620
  changeUserInput,
645
621
  saveQueryToHistory,
646
622
  goToPreviousQuery,
@@ -648,7 +624,6 @@ const mapDispatchToProps = {
648
624
  getExplainQuery,
649
625
  getExplainQueryAst,
650
626
  setSettingValue,
651
- selectRunAction,
652
627
  setShowPreview,
653
628
  setMonacoHotKey,
654
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
  }
@@ -0,0 +1,83 @@
1
+ import {Button, DropdownMenu} from '@gravity-ui/uikit';
2
+ import {useMemo} from 'react';
3
+
4
+ import {QueryModes} from '../../../../types/store/query';
5
+ import {Icon} from '../../../../components/Icon';
6
+
7
+ import SaveQuery from '../SaveQuery/SaveQuery';
8
+
9
+ import {b, QueryEditorControlsProps, QueryModeSelectorTitles} from './shared';
10
+
11
+ import './QueryEditorControls.scss';
12
+
13
+ export const OldQueryEditorControls = ({
14
+ onRunButtonClick,
15
+ runIsLoading,
16
+ onExplainButtonClick,
17
+ explainIsLoading,
18
+ onSaveQueryClick,
19
+ savedQueries,
20
+ disabled,
21
+ onUpdateQueryMode,
22
+ queryMode,
23
+ }: QueryEditorControlsProps) => {
24
+ const runModeSelectorMenuItems = useMemo(() => {
25
+ return Object.entries(QueryModeSelectorTitles).map(([mode, title]) => {
26
+ return {
27
+ text: `Run ${title}`,
28
+ action: () => {
29
+ onUpdateQueryMode(mode as QueryModes);
30
+ },
31
+ };
32
+ });
33
+ }, [onUpdateQueryMode]);
34
+
35
+ return (
36
+ <div className={b()}>
37
+ <div className={b('left')}>
38
+ <div className={b('run')}>
39
+ <Button
40
+ onClick={() => onRunButtonClick(queryMode)}
41
+ view="action"
42
+ pin="round-brick"
43
+ disabled={disabled}
44
+ loading={runIsLoading}
45
+ >
46
+ <Icon name="startPlay" viewBox="0 0 16 16" width={16} height={16} />
47
+ {`Run ${QueryModeSelectorTitles[queryMode]}`}
48
+ </Button>
49
+ <DropdownMenu
50
+ items={runModeSelectorMenuItems}
51
+ popupClassName={b('select-query-action-popup')}
52
+ switcher={
53
+ <Button
54
+ view="action"
55
+ pin="brick-round"
56
+ disabled={disabled}
57
+ loading={runIsLoading}
58
+ className={b('select-query-action')}
59
+ >
60
+ <Icon name="chevron-down" width={16} height={16} />
61
+ </Button>
62
+ }
63
+ />
64
+ </div>
65
+ <Button
66
+ onClick={() => {
67
+ // Without defined query mode it sends 'explain' action
68
+ onExplainButtonClick();
69
+ }}
70
+ disabled={disabled}
71
+ loading={explainIsLoading}
72
+ >
73
+ Explain
74
+ </Button>
75
+ </div>
76
+ <SaveQuery
77
+ savedQueries={savedQueries}
78
+ onSaveQuery={onSaveQueryClick}
79
+ saveButtonDisabled={disabled}
80
+ />
81
+ </div>
82
+ );
83
+ };
@@ -0,0 +1,57 @@
1
+ .ydb-query-editor-controls {
2
+ display: flex;
3
+ flex: 0 0 40px;
4
+ justify-content: space-between;
5
+ align-items: flex-end;
6
+
7
+ min-height: 40px;
8
+ padding: 5px 20px;
9
+
10
+ border-top: 1px solid var(--yc-color-line-generic);
11
+ border-bottom: 1px solid var(--yc-color-line-generic);
12
+ background-color: var(--yc-color-base-background);
13
+ gap: 24px;
14
+
15
+ &__left {
16
+ display: flex;
17
+ gap: 12px;
18
+ }
19
+
20
+ &__run {
21
+ display: flex;
22
+ align-items: center;
23
+ .yc-select__option-text {
24
+ display: none;
25
+ }
26
+
27
+ .yc-button__text {
28
+ display: flex;
29
+ justify-content: center;
30
+ align-items: center;
31
+ gap: 8px;
32
+ }
33
+ }
34
+
35
+ &__select-query-action {
36
+ margin-left: 2px;
37
+ }
38
+
39
+ &__mode-selector {
40
+ &__popup {
41
+ width: 120px;
42
+ }
43
+
44
+ &__button {
45
+ width: 120px;
46
+ margin-left: 2px;
47
+ }
48
+
49
+ &__button-content {
50
+ display: flex;
51
+ justify-content: space-between;
52
+ align-items: center;
53
+
54
+ width: 100px;
55
+ }
56
+ }
57
+ }
@@ -0,0 +1,84 @@
1
+ import {Button, DropdownMenu} from '@gravity-ui/uikit';
2
+ import {useMemo} from 'react';
3
+
4
+ import {QueryModes} from '../../../../types/store/query';
5
+ import {Icon} from '../../../../components/Icon';
6
+
7
+ import SaveQuery from '../SaveQuery/SaveQuery';
8
+
9
+ import i18n from '../i18n';
10
+
11
+ import {b, QueryEditorControlsProps, QueryModeSelectorTitles} from './shared';
12
+
13
+ import './QueryEditorControls.scss';
14
+
15
+ export const QueryEditorControls = ({
16
+ onRunButtonClick,
17
+ runIsLoading,
18
+ onExplainButtonClick,
19
+ explainIsLoading,
20
+ onSaveQueryClick,
21
+ savedQueries,
22
+ disabled,
23
+ onUpdateQueryMode,
24
+ queryMode,
25
+ }: QueryEditorControlsProps) => {
26
+ const querySelectorMenuItems = useMemo(() => {
27
+ return Object.entries(QueryModeSelectorTitles).map(([mode, title]) => {
28
+ return {
29
+ text: title,
30
+ action: () => {
31
+ onUpdateQueryMode(mode as QueryModes);
32
+ },
33
+ };
34
+ });
35
+ }, [onUpdateQueryMode]);
36
+
37
+ return (
38
+ <div className={b()}>
39
+ <div className={b('left')}>
40
+ <div className={b('run')}>
41
+ <Button
42
+ onClick={() => {
43
+ onRunButtonClick(queryMode);
44
+ }}
45
+ view="action"
46
+ disabled={disabled}
47
+ loading={runIsLoading}
48
+ >
49
+ <Icon name="startPlay" viewBox="0 0 16 16" width={16} height={16} />
50
+ {'Run'}
51
+ </Button>
52
+ </div>
53
+ <Button
54
+ onClick={() => {
55
+ onExplainButtonClick(queryMode);
56
+ }}
57
+ disabled={disabled}
58
+ loading={explainIsLoading}
59
+ >
60
+ Explain
61
+ </Button>
62
+ <DropdownMenu
63
+ items={querySelectorMenuItems}
64
+ popupClassName={b('mode-selector__popup')}
65
+ switcher={
66
+ <Button className={b('mode-selector__button')}>
67
+ <span className={b('mode-selector__button-content')}>
68
+ {`${i18n('controls.query-mode-selector_type')} ${
69
+ QueryModeSelectorTitles[queryMode]
70
+ }`}
71
+ <Icon name="chevron-down" width={16} height={16} />
72
+ </span>
73
+ </Button>
74
+ }
75
+ />
76
+ </div>
77
+ <SaveQuery
78
+ savedQueries={savedQueries}
79
+ onSaveQuery={onSaveQueryClick}
80
+ saveButtonDisabled={disabled}
81
+ />
82
+ </div>
83
+ );
84
+ };
@@ -0,0 +1,23 @@
1
+ import block from 'bem-cn-lite';
2
+
3
+ import {QueryModes} from '../../../../types/store/query';
4
+
5
+ export const b = block('ydb-query-editor-controls');
6
+
7
+ export const QueryModeSelectorTitles = {
8
+ [QueryModes.script]: 'Script',
9
+ [QueryModes.scan]: 'Scan',
10
+ } as const;
11
+
12
+ export interface QueryEditorControlsProps {
13
+ onRunButtonClick: (mode?: QueryModes) => void;
14
+ runIsLoading: boolean;
15
+ onExplainButtonClick: (mode?: QueryModes) => void;
16
+ explainIsLoading: boolean;
17
+ onSaveQueryClick: (queryName: string) => void;
18
+ savedQueries: unknown;
19
+ disabled: boolean;
20
+ onUpdateQueryMode: (mode: QueryModes) => void;
21
+ queryMode: QueryModes;
22
+ enableQueryModesForExplain: boolean;
23
+ }