ydb-embedded-ui 4.8.2 → 4.10.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 (83) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/BasicNodeViewer/BasicNodeViewer.tsx +7 -4
  3. package/dist/components/EntityStatus/EntityStatus.js +3 -1
  4. package/dist/components/FormattedBytes/FormattedBytes.tsx +10 -0
  5. package/dist/components/FormattedBytes/utils.tsx +13 -0
  6. package/dist/components/FullNodeViewer/FullNodeViewer.tsx +73 -0
  7. package/dist/components/InfoViewer/formatters/table.ts +6 -5
  8. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +2 -2
  9. package/dist/components/ProblemFilter/ProblemFilter.tsx +2 -2
  10. package/dist/components/SpeedMultiMeter/SpeedMultiMeter.tsx +4 -4
  11. package/dist/components/TruncatedQuery/{TruncatedQuery.js → TruncatedQuery.tsx} +10 -8
  12. package/dist/containers/AsideNavigation/AsideNavigation.tsx +6 -6
  13. package/dist/containers/Cluster/Cluster.tsx +10 -6
  14. package/dist/containers/Node/Node.tsx +3 -3
  15. package/dist/containers/Nodes/Nodes.tsx +3 -3
  16. package/dist/containers/Nodes/getNodesColumns.tsx +2 -2
  17. package/dist/containers/Storage/PDisk/PDisk.tsx +2 -7
  18. package/dist/containers/Storage/Storage.tsx +240 -0
  19. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +59 -57
  20. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +23 -25
  21. package/dist/containers/Storage/StorageTypeFilter/StorageTypeFilter.tsx +27 -0
  22. package/dist/containers/Storage/StorageVisibleEntityFilter/StorageVisibleEntityFilter.tsx +31 -0
  23. package/dist/containers/Storage/UsageFilter/UsageFilter.scss +1 -0
  24. package/dist/containers/Storage/UsageFilter/UsageFilter.tsx +17 -17
  25. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -3
  26. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +7 -4
  27. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +0 -15
  28. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +10 -3
  29. package/dist/containers/Tenant/{Preview → Query/Preview}/Preview.scss +1 -1
  30. package/dist/containers/Tenant/Query/Preview/Preview.tsx +121 -0
  31. package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx +1 -1
  32. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +23 -51
  33. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.scss +20 -15
  34. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.tsx +74 -27
  35. package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.tsx +1 -1
  36. package/dist/containers/Tenant/Query/i18n/en.json +9 -2
  37. package/dist/containers/Tenant/Query/i18n/ru.json +9 -2
  38. package/dist/containers/Tenants/Tenants.tsx +269 -0
  39. package/dist/containers/UserSettings/i18n/en.json +1 -1
  40. package/dist/containers/UserSettings/i18n/ru.json +1 -1
  41. package/dist/services/api.ts +14 -16
  42. package/dist/store/reducers/executeQuery.ts +2 -3
  43. package/dist/store/reducers/explainQuery.ts +2 -2
  44. package/dist/store/reducers/index.ts +2 -2
  45. package/dist/store/reducers/{nodes.ts → nodes/nodes.ts} +33 -32
  46. package/dist/{types/store/nodes.ts → store/reducers/nodes/types.ts} +24 -27
  47. package/dist/store/reducers/partitions/types.ts +3 -3
  48. package/dist/store/reducers/settings/settings.ts +14 -4
  49. package/dist/store/reducers/settings/types.ts +3 -1
  50. package/dist/store/reducers/storage/constants.ts +10 -0
  51. package/dist/store/reducers/storage/selectors.ts +279 -0
  52. package/dist/store/reducers/storage/storage.ts +191 -0
  53. package/dist/store/reducers/storage/types.ts +92 -0
  54. package/dist/store/reducers/tenants/selectors.ts +46 -0
  55. package/dist/store/reducers/tenants/tenants.ts +21 -14
  56. package/dist/store/reducers/tenants/types.ts +20 -5
  57. package/dist/store/reducers/tenants/utils.ts +68 -0
  58. package/dist/types/additionalProps.ts +8 -0
  59. package/dist/types/api/storage.ts +1 -1
  60. package/dist/types/store/query.ts +5 -6
  61. package/dist/types/store/topic.ts +3 -3
  62. package/dist/utils/bytesParsers/__test__/formatBytes.test.ts +38 -0
  63. package/dist/utils/bytesParsers/convertBytesObjectToSpeed.ts +2 -2
  64. package/dist/utils/bytesParsers/formatBytes.ts +132 -0
  65. package/dist/utils/bytesParsers/i18n/en.json +1 -0
  66. package/dist/utils/bytesParsers/i18n/ru.json +1 -0
  67. package/dist/utils/bytesParsers/index.ts +1 -1
  68. package/dist/utils/constants.ts +1 -0
  69. package/dist/utils/index.js +5 -10
  70. package/dist/utils/nodes.ts +2 -2
  71. package/dist/utils/numeral.ts +8 -0
  72. package/dist/utils/query.ts +12 -0
  73. package/package.json +1 -1
  74. package/dist/components/FullNodeViewer/FullNodeViewer.js +0 -89
  75. package/dist/containers/Node/NodeOverview/NodeOverview.scss +0 -0
  76. package/dist/containers/Node/NodeOverview/NodeOverview.tsx +0 -21
  77. package/dist/containers/Storage/Storage.js +0 -372
  78. package/dist/containers/Tenant/Preview/Preview.js +0 -168
  79. package/dist/containers/Tenant/Query/QueryEditorControls/OldQueryEditorControls.tsx +0 -90
  80. package/dist/containers/Tenant/Query/QueryEditorControls/shared.ts +0 -18
  81. package/dist/containers/Tenants/Tenants.js +0 -363
  82. package/dist/store/reducers/storage.js +0 -438
  83. package/dist/utils/bytesParsers/formatBytesCustom.ts +0 -57
@@ -0,0 +1,27 @@
1
+ import {RadioButton} from '@gravity-ui/uikit';
2
+
3
+ import type {StorageType} from '../../../store/reducers/storage/types';
4
+ import {STORAGE_TYPES} from '../../../store/reducers/storage/constants';
5
+
6
+ const StorageTypesTitles = {
7
+ [STORAGE_TYPES.groups]: 'Groups',
8
+ [STORAGE_TYPES.nodes]: 'Nodes',
9
+ };
10
+
11
+ interface StorageTypeFilterProps {
12
+ value: StorageType;
13
+ onChange: (value: string) => void;
14
+ }
15
+
16
+ export const StorageTypeFilter = ({value, onChange}: StorageTypeFilterProps) => {
17
+ return (
18
+ <RadioButton value={value} onUpdate={onChange}>
19
+ <RadioButton.Option value={STORAGE_TYPES.groups}>
20
+ {StorageTypesTitles[STORAGE_TYPES.groups]}
21
+ </RadioButton.Option>
22
+ <RadioButton.Option value={STORAGE_TYPES.nodes}>
23
+ {StorageTypesTitles[STORAGE_TYPES.nodes]}
24
+ </RadioButton.Option>
25
+ </RadioButton>
26
+ );
27
+ };
@@ -0,0 +1,31 @@
1
+ import {RadioButton} from '@gravity-ui/uikit';
2
+
3
+ import type {VisibleEntities} from '../../../store/reducers/storage/types';
4
+ import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
5
+
6
+ export const VisibleEntitiesTitles = {
7
+ [VISIBLE_ENTITIES.all]: 'All',
8
+ [VISIBLE_ENTITIES.missing]: 'Degraded',
9
+ [VISIBLE_ENTITIES.space]: 'Out of Space',
10
+ };
11
+
12
+ interface StorageProblemFilterProps {
13
+ value: VisibleEntities;
14
+ onChange: (value: string) => void;
15
+ }
16
+
17
+ export const StorageVisibleEntityFilter = ({value, onChange}: StorageProblemFilterProps) => {
18
+ return (
19
+ <RadioButton value={value} onUpdate={onChange}>
20
+ <RadioButton.Option value={VISIBLE_ENTITIES.missing}>
21
+ {VisibleEntitiesTitles[VISIBLE_ENTITIES.missing]}
22
+ </RadioButton.Option>
23
+ <RadioButton.Option value={VISIBLE_ENTITIES.space}>
24
+ {VisibleEntitiesTitles[VISIBLE_ENTITIES.space]}
25
+ </RadioButton.Option>
26
+ <RadioButton.Option value={VISIBLE_ENTITIES.all}>
27
+ {VisibleEntitiesTitles[VISIBLE_ENTITIES.all]}
28
+ </RadioButton.Option>
29
+ </RadioButton>
30
+ );
31
+ };
@@ -13,6 +13,7 @@
13
13
 
14
14
  &-meta {
15
15
  position: relative;
16
+ z-index: 0;
16
17
 
17
18
  padding: 0 5px;
18
19
 
@@ -3,7 +3,7 @@ import cn from 'bem-cn-lite';
3
3
 
4
4
  import {Select, SelectOption} from '@gravity-ui/uikit';
5
5
 
6
- import EntityStatus from "../../../components/EntityStatus/EntityStatus";
6
+ import EntityStatus from '../../../components/EntityStatus/EntityStatus';
7
7
 
8
8
  import {getUsageSeverityForEntityStatus} from '../utils';
9
9
 
@@ -27,14 +27,7 @@ interface UsageFilterProps {
27
27
  const b = cn('usage-filter');
28
28
 
29
29
  export const UsageFilter = (props: UsageFilterProps) => {
30
- const {
31
- className,
32
- value = [],
33
- groups = [],
34
- onChange,
35
- debounce = 200,
36
- disabled,
37
- } = props;
30
+ const {className, value = [], groups = [], onChange, debounce = 200, disabled} = props;
38
31
 
39
32
  const [filterValue, setFilterValue] = useState(value);
40
33
  const timer = useRef<number>();
@@ -50,11 +43,15 @@ export const UsageFilter = (props: UsageFilterProps) => {
50
43
  });
51
44
  }, [value]);
52
45
 
53
- const options = useMemo(() => groups.map(({threshold, count}) => ({
54
- value: String(threshold),
55
- text: `${threshold}%`,
56
- data: {count}
57
- })), [groups]);
46
+ const options = useMemo(
47
+ () =>
48
+ groups.map(({threshold, count}) => ({
49
+ value: String(threshold),
50
+ text: `${threshold}%`,
51
+ data: {count},
52
+ })),
53
+ [groups],
54
+ );
58
55
 
59
56
  const handleUpdate = (newValue: string[]) => {
60
57
  setFilterValue(newValue);
@@ -67,17 +64,20 @@ export const UsageFilter = (props: UsageFilterProps) => {
67
64
 
68
65
  const maxWidth = Math.max(...groups.map(({count}) => count));
69
66
 
70
- const renderOption = ({value, data, text}: SelectOption) => (
67
+ const renderOption = ({value: optionValue, data, text}: SelectOption) => (
71
68
  <div className={b('option')}>
72
69
  <EntityStatus
73
70
  className={b('option-title')}
74
- status={getUsageSeverityForEntityStatus(Number(value))}
71
+ status={getUsageSeverityForEntityStatus(Number(optionValue))}
75
72
  name={text}
76
73
  size="xs"
77
74
  />
78
75
  <div className={b('option-meta')}>
79
76
  {i18n('groups_count', {count: data.count})}
80
- <div className={b('option-bar')} style={{width: `${data.count / maxWidth * 100}%`}} />
77
+ <div
78
+ className={b('option-bar')}
79
+ style={{width: `${(data.count / maxWidth) * 100}%`}}
80
+ />
81
81
  </div>
82
82
  </div>
83
83
  );
@@ -13,14 +13,14 @@ import {useTypedSelector} from '../../../utils/hooks';
13
13
  import routes, {createHref} from '../../../routes';
14
14
  import type {TenantDiagnosticsTab} from '../../../store/reducers/tenant/types';
15
15
  import {enableAutorefresh, disableAutorefresh} from '../../../store/reducers/schema/schema';
16
- import { setDiagnosticsTab} from '../../../store/reducers/tenant/tenant';
16
+ import {setDiagnosticsTab} from '../../../store/reducers/tenant/tenant';
17
17
  import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../store/reducers/tenant/constants';
18
18
 
19
19
  import {Loader} from '../../../components/Loader';
20
20
 
21
21
  import {Heatmap} from '../../Heatmap';
22
22
  import {Nodes} from '../../Nodes';
23
- import Storage from '../../Storage/Storage';
23
+ import {Storage} from '../../Storage/Storage';
24
24
  import {Tablets} from '../../Tablets';
25
25
 
26
26
  import Describe from './Describe/Describe';
@@ -130,7 +130,7 @@ function Diagnostics(props: DiagnosticsProps) {
130
130
  return <Tablets path={currentSchemaPath} />;
131
131
  }
132
132
  case TENANT_DIAGNOSTICS_TABS_IDS.storage: {
133
- return <Storage tenant={tenantNameString} database={true} />;
133
+ return <Storage tenant={tenantNameString} />;
134
134
  }
135
135
  case TENANT_DIAGNOSTICS_TABS_IDS.network: {
136
136
  return <Network path={tenantNameString} />;
@@ -27,10 +27,13 @@ const renderName = (tenant) => {
27
27
  const {Name} = tenant;
28
28
  return (
29
29
  <div className={b('tenant-name-wrapper')}>
30
- <EntityStatus status={tenant.State} />
31
- <span className={b('tenant-name-trim')}>
32
- <span className={b('tenant-name')}>{Name}</span>
33
- </span>
30
+ <EntityStatus
31
+ status={tenant.State}
32
+ name={Name}
33
+ withLeftTrim
34
+ hasClipboardButton
35
+ clipboardButtonAlwaysVisible
36
+ />
34
37
  </div>
35
38
  );
36
39
  }
@@ -10,21 +10,6 @@
10
10
  display: flex;
11
11
  overflow: hidden;
12
12
  align-items: center;
13
-
14
- & .yc-link {
15
- display: flex;
16
- }
17
- }
18
- &__tenant-name-trim {
19
- overflow: hidden;
20
-
21
- white-space: nowrap;
22
- text-overflow: ellipsis;
23
- direction: rtl;
24
- }
25
-
26
- &__tenant-name {
27
- unicode-bidi: plaintext;
28
13
  }
29
14
 
30
15
  &__top {
@@ -9,7 +9,7 @@ import {Loader} from '@gravity-ui/uikit';
9
9
 
10
10
  import {DateRange, DateRangeValues} from '../../../../components/DateRange';
11
11
  import {Search} from '../../../../components/Search';
12
- import TruncatedQuery from '../../../../components/TruncatedQuery/TruncatedQuery';
12
+ import {TruncatedQuery} from '../../../../components/TruncatedQuery/TruncatedQuery';
13
13
 
14
14
  import {changeUserInput} from '../../../../store/reducers/executeQuery';
15
15
  import {
@@ -23,7 +23,11 @@ import type {EPathType} from '../../../../types/api/schema';
23
23
  import type {ITopQueriesFilters} from '../../../../types/store/executeTopQueries';
24
24
  import type {IQueryResult} from '../../../../types/store/query';
25
25
 
26
- import {TENANT_PAGE, TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID} from '../../../../store/reducers/tenant/constants';
26
+ import {
27
+ TENANT_PAGE,
28
+ TENANT_PAGES_IDS,
29
+ TENANT_QUERY_TABS_ID,
30
+ } from '../../../../store/reducers/tenant/constants';
27
31
  import {formatDateTime, formatNumber} from '../../../../utils';
28
32
  import {HOUR_IN_SECONDS} from '../../../../utils/constants';
29
33
  import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
@@ -50,7 +54,10 @@ const COLUMNS: Column<KeyValueRow>[] = [
50
54
  sortable: false,
51
55
  render: ({row}) => (
52
56
  <div className={b('query')}>
53
- <TruncatedQuery value={row.QueryText} maxQueryHeight={MAX_QUERY_HEIGHT} />
57
+ <TruncatedQuery
58
+ value={row.QueryText?.toString()}
59
+ maxQueryHeight={MAX_QUERY_HEIGHT}
60
+ />
54
61
  </div>
55
62
  ),
56
63
  },
@@ -1,4 +1,4 @@
1
- @import '../../../styles/mixins.scss';
1
+ @import '../../../../styles/mixins.scss';
2
2
 
3
3
  .kv-preview {
4
4
  height: 100%;
@@ -0,0 +1,121 @@
1
+ import {useCallback} from 'react';
2
+ import {useDispatch} from 'react-redux';
3
+ import cn from 'bem-cn-lite';
4
+
5
+ import {Loader, Button} from '@gravity-ui/uikit';
6
+
7
+ import type {EPathType} from '../../../../types/api/schema';
8
+ import {sendQuery, setQueryOptions} from '../../../../store/reducers/preview';
9
+ import {setShowPreview} from '../../../../store/reducers/schema/schema';
10
+ import {prepareQueryError} from '../../../../utils/query';
11
+ import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
12
+
13
+ import {Icon} from '../../../../components/Icon';
14
+ import Fullscreen from '../../../../components/Fullscreen/Fullscreen';
15
+ import {QueryResultTable} from '../../../../components/QueryResultTable';
16
+ import EnableFullscreenButton from '../../../../components/EnableFullscreenButton/EnableFullscreenButton';
17
+
18
+ import {isTableType} from '../../utils/schema';
19
+
20
+ import i18n from '../i18n';
21
+
22
+ import './Preview.scss';
23
+
24
+ const b = cn('kv-preview');
25
+
26
+ interface PreviewProps {
27
+ database: string;
28
+ type: EPathType | undefined;
29
+ }
30
+
31
+ export const Preview = ({database, type}: PreviewProps) => {
32
+ const dispatch = useDispatch();
33
+
34
+ const {data = {}, loading, error, wasLoaded} = useTypedSelector((state) => state.preview);
35
+ const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
36
+ const isFullscreen = useTypedSelector((state) => state.fullscreen);
37
+
38
+ const sendQueryForPreview = useCallback(
39
+ (isBackground) => {
40
+ if (!isTableType(type)) {
41
+ return;
42
+ }
43
+
44
+ if (!isBackground) {
45
+ dispatch(
46
+ setQueryOptions({
47
+ wasLoaded: false,
48
+ data: undefined,
49
+ }),
50
+ );
51
+ }
52
+
53
+ const query = `--!syntax_v1\nselect * from \`${currentSchemaPath}\` limit 32`;
54
+
55
+ dispatch(
56
+ sendQuery({
57
+ query,
58
+ database,
59
+ action: 'execute-scan',
60
+ }),
61
+ );
62
+ },
63
+ [dispatch, database, currentSchemaPath, type],
64
+ );
65
+
66
+ useAutofetcher(sendQueryForPreview, [sendQueryForPreview], autorefresh);
67
+
68
+ const handleClosePreview = () => {
69
+ dispatch(setShowPreview(false));
70
+ };
71
+
72
+ const renderHeader = () => {
73
+ return (
74
+ <div className={b('header')}>
75
+ <div className={b('title')}>
76
+ {i18n('preview.title')}{' '}
77
+ <div className={b('table-name')}>{currentSchemaPath}</div>
78
+ </div>
79
+ <div className={b('controls-left')}>
80
+ <EnableFullscreenButton disabled={Boolean(error)} />
81
+ <Button
82
+ view="flat-secondary"
83
+ onClick={handleClosePreview}
84
+ title={i18n('preview.close')}
85
+ >
86
+ <Icon name="close" viewBox={'0 0 16 16'} width={16} height={16} />
87
+ </Button>
88
+ </div>
89
+ </div>
90
+ );
91
+ };
92
+
93
+ if (loading && !wasLoaded) {
94
+ return (
95
+ <div className={b('loader-container')}>
96
+ <Loader size="m" />
97
+ </div>
98
+ );
99
+ }
100
+
101
+ let message;
102
+
103
+ if (!isTableType(type)) {
104
+ message = <div className={b('message-container')}>{i18n('preview.not-available')}</div>;
105
+ } else if (error) {
106
+ message = <div className={b('message-container')}>{prepareQueryError(error)}</div>;
107
+ }
108
+
109
+ const content = message ?? (
110
+ <div className={b('result')}>
111
+ <QueryResultTable data={data.result} columns={data.columns} />
112
+ </div>
113
+ );
114
+
115
+ return (
116
+ <div className={b()}>
117
+ {renderHeader()}
118
+ {isFullscreen ? <Fullscreen>{content}</Fullscreen> : content}
119
+ </div>
120
+ );
121
+ };
@@ -3,7 +3,7 @@ import block from 'bem-cn-lite';
3
3
 
4
4
  import DataTable, {Column} from '@gravity-ui/react-data-table';
5
5
 
6
- import TruncatedQuery from '../../../../components/TruncatedQuery/TruncatedQuery';
6
+ import {TruncatedQuery} from '../../../../components/TruncatedQuery/TruncatedQuery';
7
7
  import {setQueryTab} from '../../../../store/reducers/tenant/tenant';
8
8
  import {TENANT_QUERY_TABS_ID} from '../../../../store/reducers/tenant/constants';
9
9
  import {useTypedSelector} from '../../../../utils/hooks';
@@ -26,20 +26,20 @@ import {
26
26
  SAVED_QUERIES_KEY,
27
27
  QUERY_INITIAL_MODE_KEY,
28
28
  ENABLE_ADDITIONAL_QUERY_MODES,
29
+ LAST_USED_QUERY_ACTION_KEY,
29
30
  } from '../../../../utils/constants';
30
31
  import {useSetting} from '../../../../utils/hooks';
31
- import {QueryModes} from '../../../../types/store/query';
32
+ import {QUERY_ACTIONS, QUERY_MODES} from '../../../../utils/query';
32
33
 
33
34
  import {
34
35
  PaneVisibilityActionTypes,
35
36
  paneVisibilityToggleReducerCreator,
36
37
  } from '../../utils/paneVisibilityToggleHelpers';
37
- import Preview from '../../Preview/Preview';
38
+ import {Preview} from '../Preview/Preview';
38
39
 
39
40
  import {ExecuteResult} from '../ExecuteResult/ExecuteResult';
40
41
  import {ExplainResult} from '../ExplainResult/ExplainResult';
41
42
  import {QueryEditorControls} from '../QueryEditorControls/QueryEditorControls';
42
- import {OldQueryEditorControls} from '../QueryEditorControls/OldQueryEditorControls';
43
43
 
44
44
  import {getPreparedResult} from '../utils/getPreparedResult';
45
45
 
@@ -93,18 +93,21 @@ function QueryEditor(props) {
93
93
  const [isResultLoaded, setIsResultLoaded] = useState(false);
94
94
  const [queryMode, setQueryMode] = useSetting(QUERY_INITIAL_MODE_KEY);
95
95
  const [enableAdditionalQueryModes] = useSetting(ENABLE_ADDITIONAL_QUERY_MODES);
96
+ const [lastUsedQueryAction, setLastUsedQueryAction] = useSetting(LAST_USED_QUERY_ACTION_KEY);
96
97
 
97
98
  useEffect(() => {
98
- const isNewQueryMode = queryMode !== QueryModes.script && queryMode !== QueryModes.scan;
99
+ const isNewQueryMode = queryMode !== QUERY_MODES.script && queryMode !== QUERY_MODES.scan;
99
100
  if (!enableAdditionalQueryModes && isNewQueryMode) {
100
- setQueryMode(QueryModes.script);
101
+ setQueryMode(QUERY_MODES.script);
101
102
  }
102
103
  }, [enableAdditionalQueryModes, queryMode, setQueryMode]);
103
104
 
104
105
  useEffect(() => {
105
106
  if (savedPath !== path) {
107
+ if (savedPath) {
108
+ changeUserInput({input: ''});
109
+ }
106
110
  setTenantPath(path);
107
- changeUserInput({input: ''});
108
111
  }
109
112
  }, [changeUserInput, setTenantPath, path, savedPath]);
110
113
 
@@ -170,7 +173,11 @@ function QueryEditor(props) {
170
173
  setMonacoHotKey(null);
171
174
  switch (monacoHotKey) {
172
175
  case MONACO_HOT_KEY_ACTIONS.sendQuery: {
173
- return handleSendExecuteClick(queryMode);
176
+ if (lastUsedQueryAction === QUERY_ACTIONS.explain) {
177
+ return handleGetExplainQueryClick(queryMode);
178
+ } else {
179
+ return handleSendExecuteClick(queryMode);
180
+ }
174
181
  }
175
182
  case MONACO_HOT_KEY_ACTIONS.goPrev: {
176
183
  return handlePreviousHistoryClick();
@@ -178,9 +185,6 @@ function QueryEditor(props) {
178
185
  case MONACO_HOT_KEY_ACTIONS.goNext: {
179
186
  return handleNextHistoryClick();
180
187
  }
181
- case MONACO_HOT_KEY_ACTIONS.getExplain: {
182
- return handleGetExplainQueryClick();
183
- }
184
188
  default: {
185
189
  return;
186
190
  }
@@ -201,8 +205,8 @@ function QueryEditor(props) {
201
205
  editorRef.current = editor;
202
206
  editor.focus();
203
207
  editor.addAction({
204
- id: 'run',
205
- label: 'Run',
208
+ id: 'sendQuery',
209
+ label: 'Send query',
206
210
  keybindings: [
207
211
  // eslint-disable-next-line no-bitwise
208
212
  monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
@@ -240,22 +244,6 @@ function QueryEditor(props) {
240
244
  contextMenuOrder: 3,
241
245
  run: handleKeyBinding(MONACO_HOT_KEY_ACTIONS.goNext),
242
246
  });
243
-
244
- editor.addAction({
245
- id: 'explain',
246
- label: 'Explain',
247
- keybindings: [
248
- // eslint-disable-next-line no-bitwise
249
- monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_E,
250
- ],
251
- // A precondition for this action.
252
- precondition: null,
253
- // A rule to evaluate on top of the precondition in order to dispatch the keybindings.
254
- keybindingContext: null,
255
- contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
256
- contextMenuOrder: 4,
257
- run: handleKeyBinding(MONACO_HOT_KEY_ACTIONS.getExplain),
258
- });
259
247
  };
260
248
  const onChange = (newValue) => {
261
249
  props.changeUserInput({input: newValue});
@@ -270,6 +258,7 @@ function QueryEditor(props) {
270
258
  setShowPreview,
271
259
  } = props;
272
260
 
261
+ setLastUsedQueryAction(QUERY_ACTIONS.execute);
273
262
  setResultType(RESULT_TYPES.EXECUTE);
274
263
  sendExecuteQuery({query: input, database: path, mode});
275
264
  setIsResultLoaded(true);
@@ -290,6 +279,7 @@ function QueryEditor(props) {
290
279
  setShowPreview,
291
280
  } = props;
292
281
 
282
+ setLastUsedQueryAction(QUERY_ACTIONS.explain);
293
283
  setResultType(RESULT_TYPES.EXPLAIN);
294
284
  getExplainQuery({
295
285
  query: input,
@@ -392,12 +382,8 @@ function QueryEditor(props) {
392
382
  };
393
383
 
394
384
  const renderPreview = () => {
395
- const {path, type, currentSchema = {}} = props;
396
- const partCount = currentSchema?.PathDescription?.TableStats?.PartCount;
397
- // onExpandResultHandler();
398
- return (
399
- <Preview database={path} table={currentSchema.Path} type={type} partCount={partCount} />
400
- );
385
+ const {path, type} = props;
386
+ return <Preview database={path} type={type} />;
401
387
  };
402
388
 
403
389
  const handlePreviousHistoryClick = () => {
@@ -488,24 +474,8 @@ function QueryEditor(props) {
488
474
  const renderControls = () => {
489
475
  const {executeQuery, explainQuery, savedQueries} = props;
490
476
 
491
- if (enableAdditionalQueryModes) {
492
- return (
493
- <QueryEditorControls
494
- onRunButtonClick={handleSendExecuteClick}
495
- runIsLoading={executeQuery.loading}
496
- onExplainButtonClick={handleGetExplainQueryClick}
497
- explainIsLoading={explainQuery.loading}
498
- onSaveQueryClick={onSaveQueryHandler}
499
- savedQueries={savedQueries}
500
- disabled={!executeQuery.input}
501
- onUpdateQueryMode={setQueryMode}
502
- queryMode={queryMode}
503
- />
504
- );
505
- }
506
-
507
477
  return (
508
- <OldQueryEditorControls
478
+ <QueryEditorControls
509
479
  onRunButtonClick={handleSendExecuteClick}
510
480
  runIsLoading={executeQuery.loading}
511
481
  onExplainButtonClick={handleGetExplainQueryClick}
@@ -515,6 +485,8 @@ function QueryEditor(props) {
515
485
  disabled={!executeQuery.input}
516
486
  onUpdateQueryMode={setQueryMode}
517
487
  queryMode={queryMode}
488
+ enableAdditionalQueryModes={enableAdditionalQueryModes}
489
+ highlitedAction={lastUsedQueryAction}
518
490
  />
519
491
  );
520
492
  };
@@ -15,12 +15,6 @@
15
15
  }
16
16
 
17
17
  &__run {
18
- display: flex;
19
- align-items: center;
20
- .yc-select__option-text {
21
- display: none;
22
- }
23
-
24
18
  .yc-button__text {
25
19
  display: flex;
26
20
  justify-content: center;
@@ -29,17 +23,11 @@
29
23
  }
30
24
  }
31
25
 
32
- &__select-query-action {
33
- margin-left: 2px;
34
- }
35
-
36
26
  &__mode-selector {
37
- &__popup {
38
- width: 120px;
39
- }
27
+ $b: &;
40
28
 
41
29
  &__button {
42
- width: 120px;
30
+ width: 189px;
43
31
  margin-left: 2px;
44
32
  }
45
33
 
@@ -48,7 +36,24 @@
48
36
  justify-content: space-between;
49
37
  align-items: center;
50
38
 
51
- width: 100px;
39
+ width: 163px;
40
+ }
41
+
42
+ &__popup {
43
+ width: 189px;
44
+
45
+ &_extended {
46
+ width: 241px;
47
+ }
48
+ }
49
+
50
+ &_extended {
51
+ #{$b}__button {
52
+ width: 241px;
53
+ }
54
+ #{$b}__button-content {
55
+ width: 215px;
56
+ }
52
57
  }
53
58
  }
54
59
  }