ydb-embedded-ui 3.5.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/components/ClusterInfo/ClusterInfo.tsx +3 -3
  3. package/dist/{containers/Nodes/NodesTable.scss → components/NodeHostWrapper/NodeHostWrapper.scss} +4 -6
  4. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +60 -0
  5. package/dist/containers/AsideNavigation/AsideNavigation.tsx +1 -11
  6. package/dist/containers/Header/Header.tsx +1 -1
  7. package/dist/containers/Nodes/getNodesColumns.tsx +7 -46
  8. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +0 -24
  9. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +2 -39
  10. package/dist/containers/Tenant/QueryEditor/QueriesHistory/QueriesHistory.tsx +3 -3
  11. package/dist/containers/Tenant/QueryEditor/QueryDuration/QueryDuration.scss +8 -0
  12. package/dist/containers/Tenant/QueryEditor/QueryDuration/QueryDuration.tsx +21 -0
  13. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +58 -83
  14. package/dist/containers/Tenant/QueryEditor/QueryEditor.scss +0 -33
  15. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/OldQueryEditorControls.tsx +83 -0
  16. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.scss +57 -0
  17. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.tsx +84 -0
  18. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/shared.ts +23 -0
  19. package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.js +12 -23
  20. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.js +4 -6
  21. package/dist/containers/Tenant/QueryEditor/i18n/en.json +3 -0
  22. package/dist/containers/Tenant/QueryEditor/i18n/index.ts +11 -0
  23. package/dist/containers/Tenant/QueryEditor/i18n/ru.json +3 -0
  24. package/dist/containers/Tenants/Tenants.js +1 -1
  25. package/dist/containers/UserSettings/UserSettings.tsx +30 -1
  26. package/dist/services/api.ts +383 -0
  27. package/dist/store/reducers/{cluster.js → cluster/cluster.ts} +9 -14
  28. package/dist/store/reducers/cluster/types.ts +13 -0
  29. package/dist/store/reducers/executeQuery.ts +12 -37
  30. package/dist/store/reducers/executeTopQueries.ts +2 -2
  31. package/dist/store/reducers/{explainQuery.js → explainQuery.ts} +44 -59
  32. package/dist/store/reducers/index.ts +5 -4
  33. package/dist/store/reducers/settings.js +19 -17
  34. package/dist/store/reducers/{tenants.js → tenants/tenants.ts} +14 -9
  35. package/dist/store/reducers/tenants/types.ts +17 -0
  36. package/dist/store/utils.ts +3 -2
  37. package/dist/types/api/acl.ts +25 -0
  38. package/dist/types/api/cluster.ts +3 -0
  39. package/dist/types/api/compute.ts +5 -3
  40. package/dist/types/api/error.ts +14 -0
  41. package/dist/types/api/netInfo.ts +48 -0
  42. package/dist/types/api/nodes.ts +5 -3
  43. package/dist/types/api/pdisk.ts +11 -2
  44. package/dist/types/api/query.ts +226 -117
  45. package/dist/types/api/storage.ts +5 -3
  46. package/dist/types/api/tenant.ts +18 -3
  47. package/dist/types/api/vdisk.ts +10 -2
  48. package/dist/types/api/whoami.ts +19 -0
  49. package/dist/types/store/executeQuery.ts +4 -8
  50. package/dist/types/store/explainQuery.ts +38 -0
  51. package/dist/types/store/query.ts +23 -3
  52. package/dist/types/window.d.ts +5 -0
  53. package/dist/utils/constants.ts +2 -1
  54. package/dist/utils/error.ts +25 -0
  55. package/dist/utils/hooks/useTypedSelector.ts +2 -2
  56. package/dist/utils/index.js +0 -49
  57. package/dist/utils/nodes.ts +3 -1
  58. package/dist/utils/prepareQueryExplain.ts +7 -24
  59. package/dist/utils/query.test.ts +153 -231
  60. package/dist/utils/query.ts +44 -78
  61. package/dist/utils/timeParsers/i18n/en.json +9 -9
  62. package/dist/utils/timeParsers/i18n/ru.json +9 -9
  63. package/dist/utils/timeParsers/parsers.ts +9 -0
  64. package/dist/utils/utils.js +1 -2
  65. package/package.json +1 -1
  66. package/dist/services/api.d.ts +0 -86
  67. package/dist/services/api.js +0 -278
@@ -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
+ }
@@ -5,12 +5,7 @@ import MonacoEditor from 'react-monaco-editor';
5
5
  import JSONTree from 'react-json-inspector';
6
6
  import 'react-json-inspector/json-inspector.css';
7
7
 
8
- import {
9
- TextOverflow,
10
- getYdbPlanNodeShape,
11
- getCompactTopology,
12
- getTopology,
13
- } from '@gravity-ui/paranoid';
8
+ import {TextOverflow, getYdbPlanNodeShape, getTopology} from '@gravity-ui/paranoid';
14
9
  import {Loader, RadioButton} from '@gravity-ui/uikit';
15
10
 
16
11
  import Divider from '../../../../components/Divider/Divider';
@@ -55,7 +50,7 @@ const explainOptions = [
55
50
  function GraphRoot(props) {
56
51
  const paranoid = useRef();
57
52
 
58
- const {data, opts, shapes, version, theme} = props;
53
+ const {data, opts, shapes, theme} = props;
59
54
 
60
55
  const [componentTheme, updateComponentTheme] = useState(theme);
61
56
 
@@ -64,13 +59,8 @@ function GraphRoot(props) {
64
59
  }, [theme]);
65
60
 
66
61
  const render = () => {
67
- if (version === explainVersions.v2) {
68
- paranoid.current = getTopology('graphRoot', data, opts, shapes);
69
- paranoid.current.render();
70
- } else if (version === explainVersions.v1) {
71
- paranoid.current = getCompactTopology('graphRoot', data, opts);
72
- paranoid.current.renderCompactTopology();
73
- }
62
+ paranoid.current = getTopology('graphRoot', data, opts, shapes);
63
+ paranoid.current.render();
74
64
  };
75
65
 
76
66
  useEffect(() => {
@@ -112,12 +102,6 @@ function QueryExplain(props) {
112
102
  };
113
103
  }, []);
114
104
 
115
- useEffect(() => {
116
- if (!props.ast && activeOption === ExplainOptionIds.ast) {
117
- props.astQuery();
118
- }
119
- }, [activeOption]);
120
-
121
105
  const onSelectOption = (tabId) => {
122
106
  setActiveOption(tabId);
123
107
  };
@@ -131,7 +115,9 @@ function QueryExplain(props) {
131
115
  };
132
116
 
133
117
  const renderStub = () => {
134
- return <div className={b('text-message')}>There is no explanation for the request</div>;
118
+ return (
119
+ <div className={b('text-message')}>{`There is no ${activeOption} for the request`}</div>
120
+ );
135
121
  };
136
122
 
137
123
  const hasContent = () => {
@@ -189,8 +175,12 @@ function QueryExplain(props) {
189
175
  const renderGraph = () => {
190
176
  const {explain = {}, theme} = props;
191
177
  const {links, nodes, version} = explain;
178
+
179
+ const isSupportedVersion = version === explainVersions.v2;
180
+ const isEnoughDataForGraph = links && nodes && nodes.length;
181
+
192
182
  const content =
193
- links && nodes && nodes.length ? (
183
+ isSupportedVersion && isEnoughDataForGraph ? (
194
184
  <div
195
185
  className={b('explain-canvas-container', {
196
186
  hidden: activeOption !== ExplainOptionIds.schema,
@@ -198,7 +188,6 @@ function QueryExplain(props) {
198
188
  >
199
189
  <GraphRoot
200
190
  theme={theme}
201
- version={version}
202
191
  data={{links, nodes}}
203
192
  opts={{
204
193
  renderNodeTitle: renderExplainNode,
@@ -18,6 +18,7 @@ import {prepareQueryError} from '../../../../utils/query';
18
18
  import {PaneVisibilityToggleButtons} from '../../utils/paneVisibilityToggleHelpers';
19
19
 
20
20
  import ResultIssues from '../Issues/Issues';
21
+ import {QueryDuration} from '../QueryDuration/QueryDuration';
21
22
 
22
23
  import './QueryResult.scss';
23
24
 
@@ -116,15 +117,11 @@ function QueryResult(props) {
116
117
  </Fullscreen>
117
118
  )}
118
119
  </React.Fragment>
119
- )
120
+ );
120
121
  }
121
122
 
122
123
  if (error) {
123
- return (
124
- <div className={b('error')}>
125
- {prepareQueryError(error)}
126
- </div>
127
- );
124
+ return <div className={b('error')}>{prepareQueryError(error)}</div>;
128
125
  }
129
126
  };
130
127
 
@@ -136,6 +133,7 @@ function QueryResult(props) {
136
133
 
137
134
  {props.stats && !props.error && (
138
135
  <React.Fragment>
136
+ <QueryDuration duration={props.stats?.DurationUs} />
139
137
  <Divider />
140
138
  <RadioButton
141
139
  options={resultOptions}
@@ -0,0 +1,3 @@
1
+ {
2
+ "controls.query-mode-selector_type": "Type:"
3
+ }