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.
- package/CHANGELOG.md +27 -0
- package/dist/components/BasicNodeViewer/BasicNodeViewer.tsx +7 -4
- package/dist/components/EntityStatus/EntityStatus.js +3 -1
- package/dist/components/FormattedBytes/FormattedBytes.tsx +10 -0
- package/dist/components/FormattedBytes/utils.tsx +13 -0
- package/dist/components/FullNodeViewer/FullNodeViewer.tsx +73 -0
- package/dist/components/InfoViewer/formatters/table.ts +6 -5
- package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +2 -2
- package/dist/components/ProblemFilter/ProblemFilter.tsx +2 -2
- package/dist/components/SpeedMultiMeter/SpeedMultiMeter.tsx +4 -4
- package/dist/components/TruncatedQuery/{TruncatedQuery.js → TruncatedQuery.tsx} +10 -8
- package/dist/containers/AsideNavigation/AsideNavigation.tsx +6 -6
- package/dist/containers/Cluster/Cluster.tsx +10 -6
- package/dist/containers/Node/Node.tsx +3 -3
- package/dist/containers/Nodes/Nodes.tsx +3 -3
- package/dist/containers/Nodes/getNodesColumns.tsx +2 -2
- package/dist/containers/Storage/PDisk/PDisk.tsx +2 -7
- package/dist/containers/Storage/Storage.tsx +240 -0
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +59 -57
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +23 -25
- package/dist/containers/Storage/StorageTypeFilter/StorageTypeFilter.tsx +27 -0
- package/dist/containers/Storage/StorageVisibleEntityFilter/StorageVisibleEntityFilter.tsx +31 -0
- package/dist/containers/Storage/UsageFilter/UsageFilter.scss +1 -0
- package/dist/containers/Storage/UsageFilter/UsageFilter.tsx +17 -17
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -3
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +7 -4
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +0 -15
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +10 -3
- package/dist/containers/Tenant/{Preview → Query/Preview}/Preview.scss +1 -1
- package/dist/containers/Tenant/Query/Preview/Preview.tsx +121 -0
- package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx +1 -1
- package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +23 -51
- package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.scss +20 -15
- package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.tsx +74 -27
- package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.tsx +1 -1
- package/dist/containers/Tenant/Query/i18n/en.json +9 -2
- package/dist/containers/Tenant/Query/i18n/ru.json +9 -2
- package/dist/containers/Tenants/Tenants.tsx +269 -0
- package/dist/containers/UserSettings/i18n/en.json +1 -1
- package/dist/containers/UserSettings/i18n/ru.json +1 -1
- package/dist/services/api.ts +14 -16
- package/dist/store/reducers/executeQuery.ts +2 -3
- package/dist/store/reducers/explainQuery.ts +2 -2
- package/dist/store/reducers/index.ts +2 -2
- package/dist/store/reducers/{nodes.ts → nodes/nodes.ts} +33 -32
- package/dist/{types/store/nodes.ts → store/reducers/nodes/types.ts} +24 -27
- package/dist/store/reducers/partitions/types.ts +3 -3
- package/dist/store/reducers/settings/settings.ts +14 -4
- package/dist/store/reducers/settings/types.ts +3 -1
- package/dist/store/reducers/storage/constants.ts +10 -0
- package/dist/store/reducers/storage/selectors.ts +279 -0
- package/dist/store/reducers/storage/storage.ts +191 -0
- package/dist/store/reducers/storage/types.ts +92 -0
- package/dist/store/reducers/tenants/selectors.ts +46 -0
- package/dist/store/reducers/tenants/tenants.ts +21 -14
- package/dist/store/reducers/tenants/types.ts +20 -5
- package/dist/store/reducers/tenants/utils.ts +68 -0
- package/dist/types/additionalProps.ts +8 -0
- package/dist/types/api/storage.ts +1 -1
- package/dist/types/store/query.ts +5 -6
- package/dist/types/store/topic.ts +3 -3
- package/dist/utils/bytesParsers/__test__/formatBytes.test.ts +38 -0
- package/dist/utils/bytesParsers/convertBytesObjectToSpeed.ts +2 -2
- package/dist/utils/bytesParsers/formatBytes.ts +132 -0
- package/dist/utils/bytesParsers/i18n/en.json +1 -0
- package/dist/utils/bytesParsers/i18n/ru.json +1 -0
- package/dist/utils/bytesParsers/index.ts +1 -1
- package/dist/utils/constants.ts +1 -0
- package/dist/utils/index.js +5 -10
- package/dist/utils/nodes.ts +2 -2
- package/dist/utils/numeral.ts +8 -0
- package/dist/utils/query.ts +12 -0
- package/package.json +1 -1
- package/dist/components/FullNodeViewer/FullNodeViewer.js +0 -89
- package/dist/containers/Node/NodeOverview/NodeOverview.scss +0 -0
- package/dist/containers/Node/NodeOverview/NodeOverview.tsx +0 -21
- package/dist/containers/Storage/Storage.js +0 -372
- package/dist/containers/Tenant/Preview/Preview.js +0 -168
- package/dist/containers/Tenant/Query/QueryEditorControls/OldQueryEditorControls.tsx +0 -90
- package/dist/containers/Tenant/Query/QueryEditorControls/shared.ts +0 -18
- package/dist/containers/Tenants/Tenants.js +0 -363
- package/dist/store/reducers/storage.js +0 -438
- 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
|
+
};
|
@@ -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
|
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(
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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(
|
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
|
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 {
|
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}
|
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
|
31
|
-
|
32
|
-
|
33
|
-
|
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 {
|
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
|
57
|
+
<TruncatedQuery
|
58
|
+
value={row.QueryText?.toString()}
|
59
|
+
maxQueryHeight={MAX_QUERY_HEIGHT}
|
60
|
+
/>
|
54
61
|
</div>
|
55
62
|
),
|
56
63
|
},
|
@@ -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 {
|
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 '
|
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 !==
|
99
|
+
const isNewQueryMode = queryMode !== QUERY_MODES.script && queryMode !== QUERY_MODES.scan;
|
99
100
|
if (!enableAdditionalQueryModes && isNewQueryMode) {
|
100
|
-
setQueryMode(
|
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
|
-
|
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: '
|
205
|
-
label: '
|
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
|
396
|
-
|
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
|
-
<
|
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
|
-
|
38
|
-
width: 120px;
|
39
|
-
}
|
27
|
+
$b: &;
|
40
28
|
|
41
29
|
&__button {
|
42
|
-
width:
|
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:
|
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
|
}
|