ydb-embedded-ui 3.4.4 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +31 -0
- package/dist/components/Icon/Icon.tsx +6 -0
- package/dist/components/InfoViewer/InfoViewer.tsx +2 -2
- package/dist/components/InfoViewer/formatters/index.ts +0 -1
- package/dist/components/InfoViewer/formatters/table.ts +6 -0
- package/dist/components/LabelWithPopover/LabelWithPopover.tsx +3 -7
- package/dist/components/LagPopoverContent/LagPopoverContent.scss +13 -0
- package/dist/components/LagPopoverContent/LagPopoverContent.tsx +19 -0
- package/dist/components/LagPopoverContent/index.ts +1 -0
- package/dist/components/Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip.scss +5 -0
- package/dist/components/Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip.tsx +31 -0
- package/dist/components/TruncatedQuery/TruncatedQuery.js +1 -1
- package/dist/components/TruncatedQuery/TruncatedQuery.scss +7 -3
- package/dist/containers/Node/{NodePages.js → NodePages.ts} +1 -1
- package/dist/containers/Nodes/Nodes.tsx +2 -6
- package/dist/containers/Nodes/NodesTable.scss +11 -10
- package/dist/containers/Nodes/getNodesColumns.tsx +29 -24
- package/dist/containers/Storage/PDisk/PDisk.scss +2 -0
- package/dist/containers/Storage/PDiskPopup/PDiskPopup.tsx +6 -9
- package/dist/containers/Storage/Storage.js +12 -5
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +3 -1
- package/dist/containers/Storage/StorageNodes/StorageNodes.scss +20 -7
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +43 -7
- package/dist/containers/Storage/VDisk/VDisk.tsx +3 -2
- package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +4 -2
- package/dist/containers/Tablet/TabletControls/TabletControls.tsx +2 -2
- package/dist/containers/Tenant/Diagnostics/Consumers/Headers/Headers.scss +0 -8
- package/dist/containers/Tenant/Diagnostics/Consumers/Headers/Headers.tsx +3 -10
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/ru.json +1 -1
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +11 -43
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/TableInfo.tsx +19 -17
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +192 -37
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +51 -32
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/en.json +2 -1
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/ru.json +2 -1
- package/dist/containers/Tenant/Diagnostics/Partitions/Headers/Headers.scss +0 -8
- package/dist/containers/Tenant/Diagnostics/Partitions/Headers/Headers.tsx +7 -21
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +20 -14
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +49 -12
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +37 -18
- package/dist/containers/Tenant/QueryEditor/QueryEditor.js +1 -0
- package/dist/routes.ts +1 -1
- package/dist/services/api.d.ts +4 -0
- package/dist/services/api.js +3 -3
- package/dist/store/reducers/{executeQuery.js → executeQuery.ts} +51 -21
- package/dist/store/reducers/executeTopQueries.ts +5 -1
- package/dist/store/reducers/{nodesList.js → nodesList.ts} +19 -7
- package/dist/store/reducers/{olapStats.js → olapStats.ts} +8 -18
- package/dist/store/reducers/settings.js +1 -1
- package/dist/store/reducers/storage.js +8 -18
- package/dist/types/api/nodesList.ts +25 -0
- package/dist/types/api/query.ts +4 -1
- package/dist/types/api/schema.ts +523 -3
- package/dist/types/common.ts +1 -0
- package/dist/types/store/executeQuery.ts +42 -0
- package/dist/types/store/nodesList.ts +24 -0
- package/dist/types/store/olapStats.ts +14 -0
- package/dist/utils/index.js +9 -1
- package/dist/utils/nodes.ts +4 -0
- package/dist/utils/query.test.ts +42 -29
- package/dist/utils/query.ts +34 -22
- package/dist/utils/timeParsers/formatDuration.ts +30 -12
- package/dist/utils/timeParsers/i18n/en.json +4 -0
- package/dist/utils/timeParsers/i18n/ru.json +4 -0
- package/dist/utils/tooltip.js +2 -28
- package/package.json +1 -1
- package/dist/components/InfoViewer/formatters/topicStats.tsx +0 -29
@@ -1,7 +1,7 @@
|
|
1
1
|
import block from 'bem-cn-lite';
|
2
2
|
|
3
3
|
import {LabelWithPopover} from '../../../../../components/LabelWithPopover';
|
4
|
-
import {
|
4
|
+
import {LagPopoverContent} from '../../../../../components/LagPopoverContent';
|
5
5
|
|
6
6
|
import {PARTITIONS_COLUMNS_IDS, PARTITIONS_COLUMNS_TITILES} from '../utils/constants';
|
7
7
|
|
@@ -28,37 +28,23 @@ export const ReadSessionHeader = () => (
|
|
28
28
|
export const WriteLagsHeader = () => (
|
29
29
|
<LabelWithPopover
|
30
30
|
className={b('lags')}
|
31
|
-
|
32
|
-
popoverContent={
|
33
|
-
<div className={b('lags-popover-content')}>
|
34
|
-
<div>{i18n('lagsPopover.writeLags')}</div>
|
35
|
-
<div>
|
36
|
-
<WriteLagImage />
|
37
|
-
</div>
|
38
|
-
</div>
|
39
|
-
}
|
31
|
+
text={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.READ_LAGS]}
|
32
|
+
popoverContent={<LagPopoverContent text={i18n('lagsPopover.readLags')} type="read" />}
|
40
33
|
/>
|
41
34
|
);
|
42
35
|
|
43
36
|
export const ReadLagsHeader = () => (
|
44
37
|
<LabelWithPopover
|
45
38
|
className={b('lags')}
|
46
|
-
|
47
|
-
popoverContent={
|
48
|
-
<div className={b('lags-popover-content')}>
|
49
|
-
<div>{i18n('lagsPopover.readLags')}</div>
|
50
|
-
<div>
|
51
|
-
<ReadLagImage />
|
52
|
-
</div>
|
53
|
-
</div>
|
54
|
-
}
|
39
|
+
text={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.WRITE_LAGS]}
|
40
|
+
popoverContent={<LagPopoverContent text={i18n('lagsPopover.writeLags')} type="write" />}
|
55
41
|
/>
|
56
42
|
);
|
57
43
|
|
58
44
|
export const UnreadMessagesHeader = () => (
|
59
45
|
<LabelWithPopover
|
60
46
|
className={b('messages')}
|
61
|
-
|
47
|
+
text={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.UNREAD_MESSAGES]}
|
62
48
|
popoverContent={
|
63
49
|
<div className={b('messages-popover-content')}>{i18n('headers.unread')}</div>
|
64
50
|
}
|
@@ -68,7 +54,7 @@ export const UnreadMessagesHeader = () => (
|
|
68
54
|
export const UncommitedMessagesHeader = () => (
|
69
55
|
<LabelWithPopover
|
70
56
|
className={b('messages')}
|
71
|
-
|
57
|
+
text={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.UNCOMMITED_MESSAGES]}
|
72
58
|
popoverContent={
|
73
59
|
<div className={b('messages-popover-content')}>{i18n('headers.uncommited')}</div>
|
74
60
|
}
|
@@ -25,27 +25,33 @@
|
|
25
25
|
@include search();
|
26
26
|
}
|
27
27
|
|
28
|
-
&
|
28
|
+
&__table {
|
29
29
|
overflow: auto;
|
30
30
|
flex-grow: 1;
|
31
31
|
|
32
32
|
.data-table {
|
33
|
-
&,
|
34
|
-
&__table {
|
35
|
-
width: 100%;
|
36
|
-
}
|
37
|
-
|
38
|
-
&__td {
|
39
|
-
vertical-align: top;
|
40
|
-
white-space: pre;
|
41
|
-
word-break: break-word;
|
42
|
-
}
|
43
|
-
|
44
33
|
&__row {
|
45
|
-
max-height: 80px;
|
46
|
-
|
47
34
|
cursor: pointer;
|
48
35
|
}
|
49
36
|
}
|
50
37
|
}
|
38
|
+
|
39
|
+
&__query {
|
40
|
+
overflow: hidden;
|
41
|
+
|
42
|
+
width: 500px;
|
43
|
+
|
44
|
+
vertical-align: top;
|
45
|
+
white-space: pre-wrap;
|
46
|
+
text-overflow: ellipsis;
|
47
|
+
word-break: break-word;
|
48
|
+
}
|
49
|
+
|
50
|
+
&__user-sid {
|
51
|
+
overflow: hidden;
|
52
|
+
|
53
|
+
max-width: 200px;
|
54
|
+
|
55
|
+
text-overflow: ellipsis;
|
56
|
+
}
|
51
57
|
}
|
@@ -1,5 +1,7 @@
|
|
1
1
|
import {useCallback, useEffect, useRef, useState} from 'react';
|
2
2
|
import {useDispatch} from 'react-redux';
|
3
|
+
import {useHistory, useLocation} from 'react-router';
|
4
|
+
import qs from 'qs';
|
3
5
|
import cn from 'bem-cn-lite';
|
4
6
|
|
5
7
|
import DataTable, {Column, Settings} from '@gravity-ui/react-data-table';
|
@@ -21,13 +23,14 @@ import type {EPathType} from '../../../../types/api/schema';
|
|
21
23
|
import type {ITopQueriesFilters} from '../../../../types/store/executeTopQueries';
|
22
24
|
import type {IQueryResult} from '../../../../types/store/query';
|
23
25
|
|
24
|
-
import {formatDateTime} from '../../../../utils';
|
26
|
+
import {formatDateTime, formatNumber} from '../../../../utils';
|
25
27
|
import {DEFAULT_TABLE_SETTINGS, HOUR_IN_SECONDS} from '../../../../utils/constants';
|
26
28
|
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
|
27
29
|
import {prepareQueryError} from '../../../../utils/query';
|
30
|
+
import routes, {createHref} from '../../../../routes';
|
28
31
|
|
29
32
|
import {isColumnEntityType} from '../../utils/schema';
|
30
|
-
import {TenantGeneralTabsIds} from '../../TenantPages';
|
33
|
+
import {TenantGeneralTabsIds, TenantTabsGroups} from '../../TenantPages';
|
31
34
|
|
32
35
|
import i18n from './i18n';
|
33
36
|
import './TopQueries.scss';
|
@@ -43,19 +46,41 @@ const MAX_QUERY_HEIGHT = 10;
|
|
43
46
|
const COLUMNS: Column<KeyValueRow>[] = [
|
44
47
|
{
|
45
48
|
name: 'CPUTimeUs',
|
46
|
-
|
47
|
-
|
49
|
+
sortAccessor: (row) => Number(row.CPUTimeUs),
|
50
|
+
align: DataTable.RIGHT,
|
48
51
|
},
|
49
52
|
{
|
50
53
|
name: 'QueryText',
|
51
54
|
width: 500,
|
52
55
|
sortable: false,
|
53
|
-
render: ({
|
56
|
+
render: ({row}) => (
|
57
|
+
<div className={b('query')}>
|
58
|
+
<TruncatedQuery value={row.QueryText} maxQueryHeight={MAX_QUERY_HEIGHT} />
|
59
|
+
</div>
|
60
|
+
),
|
61
|
+
},
|
62
|
+
{
|
63
|
+
name: 'EndTime',
|
64
|
+
render: ({row}) => formatDateTime(new Date(row.EndTime as string).getTime()),
|
65
|
+
align: DataTable.RIGHT,
|
66
|
+
},
|
67
|
+
{
|
68
|
+
name: 'ReadRows',
|
69
|
+
render: ({row}) => formatNumber(row.ReadRows),
|
70
|
+
sortAccessor: (row) => Number(row.ReadRows),
|
71
|
+
align: DataTable.RIGHT,
|
72
|
+
},
|
73
|
+
{
|
74
|
+
name: 'ReadBytes',
|
75
|
+
render: ({row}) => formatNumber(row.ReadBytes),
|
76
|
+
sortAccessor: (row) => Number(row.ReadBytes),
|
77
|
+
align: DataTable.RIGHT,
|
54
78
|
},
|
55
79
|
{
|
56
|
-
name: '
|
57
|
-
|
58
|
-
|
80
|
+
name: 'UserSID',
|
81
|
+
render: ({row}) => <div className={b('user-sid')}>{row.UserSID || '–'}</div>,
|
82
|
+
sortAccessor: (row) => String(row.UserSID),
|
83
|
+
align: DataTable.LEFT,
|
59
84
|
},
|
60
85
|
];
|
61
86
|
|
@@ -65,8 +90,10 @@ interface TopQueriesProps {
|
|
65
90
|
type?: EPathType;
|
66
91
|
}
|
67
92
|
|
68
|
-
export const TopQueries = ({path, type
|
93
|
+
export const TopQueries = ({path, type}: TopQueriesProps) => {
|
69
94
|
const dispatch = useDispatch();
|
95
|
+
const location = useLocation();
|
96
|
+
const history = useHistory();
|
70
97
|
|
71
98
|
const {autorefresh} = useTypedSelector((state) => state.schema);
|
72
99
|
|
@@ -144,9 +171,19 @@ export const TopQueries = ({path, type, changeSchemaTab}: TopQueriesProps) => {
|
|
144
171
|
const {QueryText: input} = row;
|
145
172
|
|
146
173
|
dispatch(changeUserInput({input}));
|
147
|
-
|
174
|
+
|
175
|
+
const queryParams = qs.parse(location.search, {
|
176
|
+
ignoreQueryPrefix: true,
|
177
|
+
});
|
178
|
+
|
179
|
+
const queryPath = createHref(routes.tenant, undefined, {
|
180
|
+
...queryParams,
|
181
|
+
[TenantTabsGroups.general]: TenantGeneralTabsIds.query,
|
182
|
+
});
|
183
|
+
|
184
|
+
history.push(queryPath);
|
148
185
|
},
|
149
|
-
[
|
186
|
+
[dispatch, history, location],
|
150
187
|
);
|
151
188
|
|
152
189
|
const handleTextSearchUpdate = (text: string) => {
|
@@ -179,7 +216,7 @@ export const TopQueries = ({path, type, changeSchemaTab}: TopQueriesProps) => {
|
|
179
216
|
}
|
180
217
|
|
181
218
|
return (
|
182
|
-
<div className={b('
|
219
|
+
<div className={b('table')}>
|
183
220
|
<DataTable
|
184
221
|
columns={COLUMNS}
|
185
222
|
data={data}
|
@@ -20,6 +20,7 @@ import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema
|
|
20
20
|
import {EShardsWorkloadMode, IShardsWorkloadFilters} from '../../../../types/store/shardsWorkload';
|
21
21
|
|
22
22
|
import type {EPathType} from '../../../../types/api/schema';
|
23
|
+
import type {CellValue, KeyValueRow} from '../../../../types/api/query';
|
23
24
|
|
24
25
|
import {formatDateTime, formatNumber} from '../../../../utils';
|
25
26
|
import {DEFAULT_TABLE_SETTINGS, HOUR_IN_SECONDS} from '../../../../utils/constants';
|
@@ -57,10 +58,17 @@ const tableColumnsNames = {
|
|
57
58
|
IntervalEnd: 'IntervalEnd',
|
58
59
|
};
|
59
60
|
|
60
|
-
function prepareCPUWorkloadValue(value: string) {
|
61
|
+
function prepareCPUWorkloadValue(value: string | number) {
|
61
62
|
return `${(Number(value) * 100).toFixed(2)}%`;
|
62
63
|
}
|
63
64
|
|
65
|
+
function prepareDateTimeValue(value: CellValue) {
|
66
|
+
if (!value) {
|
67
|
+
return '–';
|
68
|
+
}
|
69
|
+
return formatDateTime(new Date(value).getTime());
|
70
|
+
}
|
71
|
+
|
64
72
|
function stringToDataTableSortOrder(value: string): SortOrder[] | undefined {
|
65
73
|
return value
|
66
74
|
? value.split(',').map((columnId) => ({
|
@@ -190,16 +198,17 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
|
190
198
|
};
|
191
199
|
};
|
192
200
|
|
193
|
-
const columns: Column<
|
201
|
+
const columns: Column<KeyValueRow>[] = [
|
194
202
|
{
|
195
203
|
name: tableColumnsNames.Path,
|
196
|
-
render: ({
|
204
|
+
render: ({row}) => {
|
205
|
+
// row.Path - relative schema path
|
197
206
|
return (
|
198
207
|
<span
|
199
|
-
onClick={onSchemaClick(tenantPath +
|
208
|
+
onClick={onSchemaClick(tenantPath + row.Path)}
|
200
209
|
className={bLink({view: 'normal'})}
|
201
210
|
>
|
202
|
-
{
|
211
|
+
{row.Path}
|
203
212
|
</span>
|
204
213
|
);
|
205
214
|
},
|
@@ -207,25 +216,28 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
|
207
216
|
},
|
208
217
|
{
|
209
218
|
name: tableColumnsNames.CPUCores,
|
210
|
-
render: ({
|
211
|
-
return prepareCPUWorkloadValue(
|
219
|
+
render: ({row}) => {
|
220
|
+
return prepareCPUWorkloadValue(row.CPUCores || 0);
|
212
221
|
},
|
213
222
|
align: DataTable.RIGHT,
|
214
223
|
},
|
215
224
|
{
|
216
225
|
name: tableColumnsNames.DataSize,
|
217
226
|
header: 'DataSize (B)',
|
218
|
-
render: ({
|
219
|
-
return formatNumber(
|
227
|
+
render: ({row}) => {
|
228
|
+
return formatNumber(row.DataSize);
|
220
229
|
},
|
221
230
|
align: DataTable.RIGHT,
|
222
231
|
},
|
223
232
|
{
|
224
233
|
name: tableColumnsNames.TabletId,
|
225
|
-
render: ({
|
234
|
+
render: ({row}) => {
|
235
|
+
if (!row.TabletId) {
|
236
|
+
return '–';
|
237
|
+
}
|
226
238
|
return (
|
227
|
-
<InternalLink to={createHref(routes.tablet, {id:
|
228
|
-
{
|
239
|
+
<InternalLink to={createHref(routes.tablet, {id: row.TabletId})}>
|
240
|
+
{row.TabletId}
|
229
241
|
</InternalLink>
|
230
242
|
);
|
231
243
|
},
|
@@ -233,10 +245,13 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
|
233
245
|
},
|
234
246
|
{
|
235
247
|
name: tableColumnsNames.NodeId,
|
236
|
-
render: ({
|
248
|
+
render: ({row}) => {
|
249
|
+
if (!row.NodeId) {
|
250
|
+
return '–';
|
251
|
+
}
|
237
252
|
return (
|
238
|
-
<InternalLink to={getDefaultNodePath(
|
239
|
-
{
|
253
|
+
<InternalLink to={getDefaultNodePath(row.NodeId)}>
|
254
|
+
{row.NodeId}
|
240
255
|
</InternalLink>
|
241
256
|
);
|
242
257
|
},
|
@@ -245,7 +260,7 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
|
245
260
|
},
|
246
261
|
{
|
247
262
|
name: tableColumnsNames.InFlightTxCount,
|
248
|
-
render: ({
|
263
|
+
render: ({row}) => formatNumber(row.InFlightTxCount),
|
249
264
|
align: DataTable.RIGHT,
|
250
265
|
sortable: false,
|
251
266
|
},
|
@@ -255,12 +270,16 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
|
255
270
|
// after NodeId
|
256
271
|
columns.splice(5, 0, {
|
257
272
|
name: tableColumnsNames.PeakTime,
|
258
|
-
render: ({
|
273
|
+
render: ({row}) => {
|
274
|
+
return prepareDateTimeValue(row.PeakTime);
|
275
|
+
},
|
259
276
|
sortable: false,
|
260
277
|
});
|
261
278
|
columns.push({
|
262
279
|
name: tableColumnsNames.IntervalEnd,
|
263
|
-
render: ({
|
280
|
+
render: ({row}) => {
|
281
|
+
return prepareDateTimeValue(row.IntervalEnd);
|
282
|
+
},
|
264
283
|
});
|
265
284
|
}
|
266
285
|
|
package/dist/routes.ts
CHANGED
@@ -28,7 +28,7 @@ export const CLUSTER_PAGES = {
|
|
28
28
|
|
29
29
|
export function createHref(
|
30
30
|
route: string,
|
31
|
-
params?:
|
31
|
+
params?: Record<string, string | number>,
|
32
32
|
query: Record<string | number, string | number | string[] | number[] | undefined> = {},
|
33
33
|
) {
|
34
34
|
let extendedQuery = query;
|
package/dist/services/api.d.ts
CHANGED
@@ -77,6 +77,10 @@ interface Window {
|
|
77
77
|
consumer?: string;
|
78
78
|
}) => Promise<import('../types/api/consumer').DescribeConsumerResult>;
|
79
79
|
getHostInfo: () => Promise<import('../types/api/systemState').TEvSystemStateResponse>;
|
80
|
+
getNodeInfo: (
|
81
|
+
id?: string,
|
82
|
+
) => Promise<import('../types/api/systemState').TEvSystemStateResponse>;
|
83
|
+
getNodesList: () => Promise<import('../types/api/nodesList').TEvNodesInfo>;
|
80
84
|
[method: string]: Function;
|
81
85
|
};
|
82
86
|
}
|
package/dist/services/api.js
CHANGED
@@ -96,9 +96,9 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
96
96
|
enums: true,
|
97
97
|
backup: false,
|
98
98
|
private: true,
|
99
|
-
partition_config:
|
100
|
-
partition_stats:
|
101
|
-
partitioning_info:
|
99
|
+
partition_config: true,
|
100
|
+
partition_stats: true,
|
101
|
+
partitioning_info: true,
|
102
102
|
subs: 1,
|
103
103
|
},
|
104
104
|
{concurrentId: concurrentId || `getSchema|${path}`},
|
@@ -1,13 +1,25 @@
|
|
1
|
-
import {
|
2
|
-
|
1
|
+
import type {Reducer} from 'redux';
|
2
|
+
|
3
|
+
import type {Actions} from '../../types/api/query';
|
4
|
+
import type {
|
5
|
+
ExecuteQueryAction,
|
6
|
+
ExecuteQueryState,
|
7
|
+
MonacoHotKeyAction,
|
8
|
+
RunAction,
|
9
|
+
} from '../../types/store/executeQuery';
|
3
10
|
import {getValueFromLS, parseJson} from '../../utils/utils';
|
4
11
|
import {QUERIES_HISTORY_KEY, QUERY_INITIAL_RUN_ACTION_KEY} from '../../utils/constants';
|
5
12
|
import {parseQueryAPIExecuteResponse} from '../../utils/query';
|
13
|
+
import '../../services/api';
|
14
|
+
|
15
|
+
import {createRequestActionTypes, createApiRequest} from '../utils';
|
16
|
+
|
6
17
|
import {readSavedSettingsValue} from './settings';
|
7
18
|
|
8
19
|
const MAXIMUM_QUERIES_IN_HISTORY = 20;
|
9
20
|
|
10
|
-
const SEND_QUERY = createRequestActionTypes('query', 'SEND_QUERY');
|
21
|
+
export const SEND_QUERY = createRequestActionTypes('query', 'SEND_QUERY');
|
22
|
+
|
11
23
|
const CHANGE_USER_INPUT = 'query/CHANGE_USER_INPUT';
|
12
24
|
const SAVE_QUERY_TO_HISTORY = 'query/SAVE_QUERY_TO_HISTORY';
|
13
25
|
const GO_TO_PREVIOUS_QUERY = 'query/GO_TO_PREVIOUS_QUERY';
|
@@ -15,21 +27,21 @@ const GO_TO_NEXT_QUERY = 'query/GO_TO_NEXT_QUERY';
|
|
15
27
|
const SELECT_RUN_ACTION = 'query/SELECT_RUN_ACTION';
|
16
28
|
const MONACO_HOT_KEY = 'query/MONACO_HOT_KEY';
|
17
29
|
|
18
|
-
const queriesHistoryInitial = parseJson(getValueFromLS(QUERIES_HISTORY_KEY, '[]'));
|
30
|
+
const queriesHistoryInitial: string[] = parseJson(getValueFromLS(QUERIES_HISTORY_KEY, '[]'));
|
19
31
|
|
20
32
|
const sliceLimit = queriesHistoryInitial.length - MAXIMUM_QUERIES_IN_HISTORY;
|
21
33
|
|
22
34
|
export const RUN_ACTIONS_VALUES = {
|
23
35
|
script: 'execute-script',
|
24
36
|
scan: 'execute-scan',
|
25
|
-
};
|
37
|
+
} as const;
|
26
38
|
|
27
39
|
export const MONACO_HOT_KEY_ACTIONS = {
|
28
40
|
sendQuery: 'sendQuery',
|
29
41
|
goPrev: 'goPrev',
|
30
42
|
goNext: 'goNext',
|
31
43
|
getExplain: 'getExplain',
|
32
|
-
};
|
44
|
+
} as const;
|
33
45
|
|
34
46
|
const initialState = {
|
35
47
|
loading: false,
|
@@ -45,7 +57,10 @@ const initialState = {
|
|
45
57
|
monacoHotKey: null,
|
46
58
|
};
|
47
59
|
|
48
|
-
const executeQuery
|
60
|
+
const executeQuery: Reducer<ExecuteQueryState, ExecuteQueryAction> = (
|
61
|
+
state = initialState,
|
62
|
+
action,
|
63
|
+
) => {
|
49
64
|
switch (action.type) {
|
50
65
|
case SEND_QUERY.REQUEST: {
|
51
66
|
return {
|
@@ -141,51 +156,66 @@ const executeQuery = (state = initialState, action) => {
|
|
141
156
|
}
|
142
157
|
};
|
143
158
|
|
144
|
-
export const sendQuery = ({
|
159
|
+
export const sendQuery = ({
|
160
|
+
query,
|
161
|
+
database,
|
162
|
+
action,
|
163
|
+
}: {
|
164
|
+
query: string;
|
165
|
+
database: string;
|
166
|
+
action: Actions;
|
167
|
+
}) => {
|
145
168
|
return createApiRequest({
|
146
|
-
request: window.api.sendQuery({
|
169
|
+
request: window.api.sendQuery({
|
170
|
+
schema: 'modern',
|
171
|
+
query,
|
172
|
+
database,
|
173
|
+
action,
|
174
|
+
stats: 'profile',
|
175
|
+
}),
|
147
176
|
actions: SEND_QUERY,
|
148
177
|
dataHandler: parseQueryAPIExecuteResponse,
|
149
178
|
});
|
150
179
|
};
|
151
180
|
|
152
|
-
export const saveQueryToHistory = (query) => {
|
181
|
+
export const saveQueryToHistory = (query: string) => {
|
153
182
|
return {
|
154
183
|
type: SAVE_QUERY_TO_HISTORY,
|
155
184
|
data: query,
|
156
|
-
};
|
185
|
+
} as const;
|
157
186
|
};
|
158
187
|
|
159
|
-
export const selectRunAction = (value) => {
|
188
|
+
export const selectRunAction = (value: RunAction) => {
|
160
189
|
return {
|
161
190
|
type: SELECT_RUN_ACTION,
|
162
191
|
data: value,
|
163
|
-
};
|
192
|
+
} as const;
|
164
193
|
};
|
165
194
|
|
166
195
|
export const goToPreviousQuery = () => {
|
167
196
|
return {
|
168
197
|
type: GO_TO_PREVIOUS_QUERY,
|
169
|
-
};
|
198
|
+
} as const;
|
170
199
|
};
|
171
200
|
|
172
201
|
export const goToNextQuery = () => {
|
173
202
|
return {
|
174
203
|
type: GO_TO_NEXT_QUERY,
|
175
|
-
};
|
204
|
+
} as const;
|
176
205
|
};
|
177
206
|
|
178
|
-
export const changeUserInput = ({input}) => {
|
179
|
-
return
|
180
|
-
|
181
|
-
|
207
|
+
export const changeUserInput = ({input}: {input: string}) => {
|
208
|
+
return {
|
209
|
+
type: CHANGE_USER_INPUT,
|
210
|
+
data: {input},
|
211
|
+
} as const;
|
182
212
|
};
|
183
213
|
|
184
|
-
export const setMonacoHotKey = (value) => {
|
214
|
+
export const setMonacoHotKey = (value: MonacoHotKeyAction) => {
|
185
215
|
return {
|
186
216
|
type: MONACO_HOT_KEY,
|
187
217
|
data: value,
|
188
|
-
};
|
218
|
+
} as const;
|
189
219
|
};
|
190
220
|
|
191
221
|
export default executeQuery;
|
@@ -66,7 +66,11 @@ const getQueryText = (path: string, filters?: ITopQueriesFilters) => {
|
|
66
66
|
SELECT
|
67
67
|
CPUTime as CPUTimeUs,
|
68
68
|
QueryText,
|
69
|
-
IntervalEnd
|
69
|
+
IntervalEnd,
|
70
|
+
EndTime,
|
71
|
+
ReadRows,
|
72
|
+
ReadBytes,
|
73
|
+
UserSID
|
70
74
|
FROM \`${path}/.sys/top_queries_by_cpu_time_one_hour\`
|
71
75
|
WHERE ${filterConditions || 'true'}
|
72
76
|
`;
|
@@ -1,11 +1,19 @@
|
|
1
|
+
import type {Reducer} from 'redux';
|
2
|
+
|
3
|
+
import type {
|
4
|
+
NodesListState,
|
5
|
+
NodesListAction,
|
6
|
+
NodesListRootStateSlice,
|
7
|
+
NodesMap,
|
8
|
+
} from '../../types/store/nodesList';
|
1
9
|
import '../../services/api';
|
2
10
|
import {createRequestActionTypes, createApiRequest} from '../utils';
|
3
11
|
|
4
|
-
const FETCH_NODES_LIST = createRequestActionTypes('
|
12
|
+
export const FETCH_NODES_LIST = createRequestActionTypes('nodesList', 'FETCH_NODES_LIST');
|
5
13
|
|
6
14
|
const initialState = {loading: true, wasLoaded: false, data: []};
|
7
15
|
|
8
|
-
const nodesList =
|
16
|
+
const nodesList: Reducer<NodesListState, NodesListAction> = (state = initialState, action) => {
|
9
17
|
switch (action.type) {
|
10
18
|
case FETCH_NODES_LIST.REQUEST: {
|
11
19
|
return {
|
@@ -36,13 +44,17 @@ const nodesList = function (state = initialState, action) {
|
|
36
44
|
|
37
45
|
export function getNodesList() {
|
38
46
|
return createApiRequest({
|
39
|
-
request: window.api.
|
47
|
+
request: window.api.getNodesList(),
|
40
48
|
actions: FETCH_NODES_LIST,
|
41
|
-
dataHandler: (data) => {
|
42
|
-
const {SystemStateInfo: nodes = []} = data;
|
43
|
-
return nodes;
|
44
|
-
},
|
45
49
|
});
|
46
50
|
}
|
47
51
|
|
52
|
+
export const selectNodesMap = (state: NodesListRootStateSlice) =>
|
53
|
+
state.nodesList.data?.reduce<NodesMap>((nodesMap, node) => {
|
54
|
+
if (node.Id && node.Host) {
|
55
|
+
nodesMap.set(node.Id, node.Host);
|
56
|
+
}
|
57
|
+
return nodesMap;
|
58
|
+
}, new Map());
|
59
|
+
|
48
60
|
export default nodesList;
|