ydb-embedded-ui 4.8.2 → 4.10.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }