ydb-embedded-ui 3.0.1 → 3.2.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 +26 -0
- package/README.md +2 -0
- package/dist/components/DateRange/DateRange.scss +11 -0
- package/dist/components/DateRange/DateRange.tsx +75 -0
- package/dist/components/DateRange/index.ts +1 -0
- package/dist/components/Illustration/Illustration.tsx +4 -11
- package/dist/components/InfoViewer/InfoViewer.scss +2 -0
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +1 -1
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +16 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +4 -5
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +7 -7
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/OverloadedShards.scss +27 -0
- package/dist/containers/Tenant/Diagnostics/{TopShards/TopShards.tsx → OverloadedShards/OverloadedShards.tsx} +75 -20
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/i18n/en.json +4 -0
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/i18n/ru.json +4 -0
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +16 -19
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +202 -0
- package/dist/containers/Tenant/Diagnostics/TopQueries/i18n/en.json +4 -0
- package/dist/containers/Tenant/Diagnostics/TopQueries/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/TopQueries/i18n/ru.json +4 -0
- package/dist/containers/Tenant/Diagnostics/TopQueries/index.ts +1 -0
- package/dist/containers/UserSettings/UserSettings.tsx +1 -1
- package/dist/services/api.d.ts +7 -0
- package/dist/store/reducers/describe.ts +4 -1
- package/dist/store/reducers/executeTopQueries.ts +170 -0
- package/dist/store/reducers/settings.js +1 -1
- package/dist/store/reducers/shardsWorkload.ts +91 -25
- package/dist/store/reducers/storage.js +2 -0
- package/dist/store/reducers/{tablets.js → tablets.ts} +30 -17
- package/dist/store/state-url-mapping.js +16 -0
- package/dist/types/api/compute.ts +52 -0
- package/dist/types/api/consumer.ts +257 -0
- package/dist/types/api/enums.ts +2 -2
- package/dist/types/api/nodes.ts +5 -2
- package/dist/types/api/pdisk.ts +3 -0
- package/dist/types/api/schema.ts +1 -0
- package/dist/types/api/storage.ts +31 -28
- package/dist/types/api/tablet.ts +18 -2
- package/dist/types/api/tenant.ts +4 -1
- package/dist/types/api/topic.ts +157 -0
- package/dist/types/api/vdisk.ts +3 -0
- package/dist/types/store/executeTopQueries.ts +29 -0
- package/dist/types/store/schema.ts +3 -3
- package/dist/types/store/shardsWorkload.ts +11 -2
- package/dist/types/store/tablets.ts +42 -0
- package/dist/utils/getNodesColumns.js +8 -1
- package/dist/utils/query.ts +1 -1
- package/package.json +3 -3
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +0 -188
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.scss +0 -7
- package/dist/containers/Tenant/Diagnostics/TopShards/index.ts +0 -1
- package/dist/store/reducers/executeTopQueries.js +0 -66
- package/dist/types/api/consumers.ts +0 -3
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,31 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [3.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.1.0...v3.2.0) (2023-01-09)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* **Nodes:** display rack in table ([3b8cdd5](https://github.com/ydb-platform/ydb-embedded-ui/commit/3b8cdd5b472f98132b2faaa9b71b8911750545a6))
|
9
|
+
* **StorageNodes:** display datacenter in table ([4507bfd](https://github.com/ydb-platform/ydb-embedded-ui/commit/4507bfde839b0aafa3722828b7528885c6ac8f84))
|
10
|
+
* **TopQueries:** date range filter ([b9a8e95](https://github.com/ydb-platform/ydb-embedded-ui/commit/b9a8e9504fa68556a724b214ee91b73ec900d37e))
|
11
|
+
* **TopQueries:** filter by query text ([2c8ea97](https://github.com/ydb-platform/ydb-embedded-ui/commit/2c8ea97dd215ea59165cf05315bc5809cf7fafd7))
|
12
|
+
|
13
|
+
|
14
|
+
### Bug Fixes
|
15
|
+
|
16
|
+
* **InfoViewer:** min width for values ([64a4fd4](https://github.com/ydb-platform/ydb-embedded-ui/commit/64a4fd4de16738a9e2fac9cb4fba94eafc938762))
|
17
|
+
* **Nodes:** open external link in new tab ([b7c3ddd](https://github.com/ydb-platform/ydb-embedded-ui/commit/b7c3ddd1e611f2b61466e3eda51f3341f8407588))
|
18
|
+
* **TopQueries:** proper table dynamic render type ([9add6ca](https://github.com/ydb-platform/ydb-embedded-ui/commit/9add6ca9fbfe0475caf1586070a800210320cee6))
|
19
|
+
* **TopShards:** rename to overloaded shards ([d9978bd](https://github.com/ydb-platform/ydb-embedded-ui/commit/d9978bdd84b9a883e4eefcac7f85f856da55d770))
|
20
|
+
* **UserSettings:** treat invertedDisks settings as string ([ad7742a](https://github.com/ydb-platform/ydb-embedded-ui/commit/ad7742a6bf0be59c2b9cbbf947aaa66f79d748be))
|
21
|
+
|
22
|
+
## [3.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.0.1...v3.1.0) (2022-12-13)
|
23
|
+
|
24
|
+
|
25
|
+
### Features
|
26
|
+
|
27
|
+
* **TopShards:** date range filter ([aab4396](https://github.com/ydb-platform/ydb-embedded-ui/commit/aab439600ec28d30799c4a7ef7a9c68fcacc148c))
|
28
|
+
|
3
29
|
## [3.0.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.0.0...v3.0.1) (2022-12-12)
|
4
30
|
|
5
31
|
|
package/README.md
CHANGED
@@ -15,6 +15,8 @@ Local viewer for YDB clusters
|
|
15
15
|
3) Open [http://localhost:3000](http://localhost:3000) to view it in the browser. The page will reload if you make edits.\
|
16
16
|
You will also see any lint errors in the console.
|
17
17
|
|
18
|
+
For API reference, open Swagger UI on http://localhost:8765/viewer/api/.
|
19
|
+
|
18
20
|
### Making a production bundle.
|
19
21
|
|
20
22
|
Base command `npm run build` builds the app for production to the `build` folder.\
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import {ChangeEventHandler} from 'react';
|
2
|
+
import cn from 'bem-cn-lite';
|
3
|
+
|
4
|
+
import './DateRange.scss';
|
5
|
+
|
6
|
+
const b = cn('date-range');
|
7
|
+
|
8
|
+
export interface DateRangeValues {
|
9
|
+
/** ms from epoch */
|
10
|
+
from?: number;
|
11
|
+
/** ms from epoch */
|
12
|
+
to?: number;
|
13
|
+
}
|
14
|
+
|
15
|
+
interface DateRangeProps extends DateRangeValues {
|
16
|
+
className?: string;
|
17
|
+
onChange?: (value: DateRangeValues) => void;
|
18
|
+
}
|
19
|
+
|
20
|
+
const toTimezonelessISOString = (timestamp?: number) => {
|
21
|
+
if (!timestamp || isNaN(timestamp)) {
|
22
|
+
return undefined;
|
23
|
+
}
|
24
|
+
|
25
|
+
// shift by local offset to treat toISOString output as local time
|
26
|
+
const shiftedTimestamp = timestamp - new Date().getTimezoneOffset() * 60 * 1000;
|
27
|
+
return new Date(shiftedTimestamp).toISOString().substring(0, 'yyyy-MM-DDThh:mm'.length);
|
28
|
+
};
|
29
|
+
|
30
|
+
export const DateRange = ({from, to, className, onChange}: DateRangeProps) => {
|
31
|
+
const handleFromChange: ChangeEventHandler<HTMLInputElement> = ({target: {value}}) => {
|
32
|
+
let newFrom = value ? new Date(value).getTime() : undefined;
|
33
|
+
|
34
|
+
// some browsers allow selecting time after the boundary specified in `max`
|
35
|
+
if (newFrom && to && newFrom > to) {
|
36
|
+
newFrom = to;
|
37
|
+
}
|
38
|
+
|
39
|
+
onChange?.({from: newFrom, to});
|
40
|
+
};
|
41
|
+
|
42
|
+
const handleToChange: ChangeEventHandler<HTMLInputElement> = ({target: {value}}) => {
|
43
|
+
let newTo = value ? new Date(value).getTime() : undefined;
|
44
|
+
|
45
|
+
// some browsers allow selecting time before the boundary specified in `min`
|
46
|
+
if (from && newTo && from > newTo) {
|
47
|
+
newTo = from;
|
48
|
+
}
|
49
|
+
|
50
|
+
onChange?.({from, to: newTo});
|
51
|
+
};
|
52
|
+
|
53
|
+
const startISO = toTimezonelessISOString(from);
|
54
|
+
const endISO = toTimezonelessISOString(to);
|
55
|
+
|
56
|
+
return (
|
57
|
+
<div className={b(null, className)}>
|
58
|
+
<input
|
59
|
+
type="datetime-local"
|
60
|
+
value={startISO || ''}
|
61
|
+
max={endISO}
|
62
|
+
onChange={handleFromChange}
|
63
|
+
className={b('input')}
|
64
|
+
/>
|
65
|
+
—
|
66
|
+
<input
|
67
|
+
type="datetime-local"
|
68
|
+
min={startISO}
|
69
|
+
value={endISO || ''}
|
70
|
+
onChange={handleToChange}
|
71
|
+
className={b('input')}
|
72
|
+
/>
|
73
|
+
</div>
|
74
|
+
);
|
75
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './DateRange';
|
@@ -1,8 +1,8 @@
|
|
1
|
-
import {useEffect, useState} from 'react';
|
1
|
+
import {ImgHTMLAttributes, useEffect, useState} from 'react';
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
import {useThemeValue} from '@gravity-ui/uikit';
|
4
4
|
|
5
|
-
export interface IllustrationProps {
|
5
|
+
export interface IllustrationProps extends ImgHTMLAttributes<HTMLImageElement> {
|
6
6
|
name: string;
|
7
7
|
className?: string;
|
8
8
|
}
|
@@ -38,12 +38,5 @@ export const Illustration = ({name, className, ...props}: IllustrationProps) =>
|
|
38
38
|
}
|
39
39
|
}, [srcGetter]);
|
40
40
|
|
41
|
-
return (
|
42
|
-
|
43
|
-
alt={name}
|
44
|
-
src={src}
|
45
|
-
className={b(null, className)}
|
46
|
-
{...props}
|
47
|
-
/>
|
48
|
-
);
|
49
|
-
}
|
41
|
+
return <img alt={name} src={src} className={b(null, className)} {...props} />;
|
42
|
+
};
|
@@ -27,7 +27,7 @@ function DiskStateProgressBar({
|
|
27
27
|
diskAllocatedPercent = -1,
|
28
28
|
severity,
|
29
29
|
}: DiskStateProgressBarProps) {
|
30
|
-
const inverted = useSelector((state) => getSettingValue(state, INVERTED_DISKS_KEY));
|
30
|
+
const inverted = useSelector((state) => JSON.parse(getSettingValue(state, INVERTED_DISKS_KEY)));
|
31
31
|
|
32
32
|
const renderAllocatedPercent = () => {
|
33
33
|
return (
|
@@ -16,6 +16,8 @@ import './StorageNodes.scss';
|
|
16
16
|
enum TableColumnsIds {
|
17
17
|
NodeId = 'NodeId',
|
18
18
|
FQDN = 'FQDN',
|
19
|
+
DataCenter = 'DataCenter',
|
20
|
+
Rack = 'Rack',
|
19
21
|
uptime = 'uptime',
|
20
22
|
PDisks = 'PDisks',
|
21
23
|
Missing = 'Missing',
|
@@ -36,6 +38,8 @@ interface StorageNodesProps {
|
|
36
38
|
const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
|
37
39
|
NodeId: 'Node ID',
|
38
40
|
FQDN: 'FQDN',
|
41
|
+
DataCenter: 'DC',
|
42
|
+
Rack: 'Rack',
|
39
43
|
uptime: 'Uptime',
|
40
44
|
PDisks: 'PDisks',
|
41
45
|
Missing: 'Missing',
|
@@ -96,6 +100,18 @@ function StorageNodes({
|
|
96
100
|
},
|
97
101
|
align: DataTable.LEFT,
|
98
102
|
},
|
103
|
+
{
|
104
|
+
name: TableColumnsIds.DataCenter,
|
105
|
+
header: tableColumnsNames[TableColumnsIds.DataCenter],
|
106
|
+
render: ({row}) => row.DataCenter || '—',
|
107
|
+
align: DataTable.LEFT,
|
108
|
+
},
|
109
|
+
{
|
110
|
+
name: TableColumnsIds.Rack,
|
111
|
+
header: tableColumnsNames[TableColumnsIds.Rack],
|
112
|
+
render: ({row}) => row.Rack || '—',
|
113
|
+
align: DataTable.LEFT,
|
114
|
+
},
|
99
115
|
{
|
100
116
|
name: TableColumnsIds.uptime,
|
101
117
|
header: tableColumnsNames[TableColumnsIds.uptime],
|
@@ -9,11 +9,10 @@ import {Switch, Tabs} from '@gravity-ui/uikit';
|
|
9
9
|
|
10
10
|
import {Loader} from '../../../components/Loader';
|
11
11
|
|
12
|
-
|
13
|
-
import TopQueries from './TopQueries/TopQueries';
|
12
|
+
import {TopQueries} from './TopQueries';
|
14
13
|
//@ts-ignore
|
15
14
|
import DetailedOverview from './DetailedOverview/DetailedOverview';
|
16
|
-
import {
|
15
|
+
import {OverloadedShards} from './OverloadedShards';
|
17
16
|
//@ts-ignore
|
18
17
|
import Storage from '../../Storage/Storage';
|
19
18
|
//@ts-ignore
|
@@ -130,8 +129,8 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
130
129
|
/>
|
131
130
|
);
|
132
131
|
}
|
133
|
-
case GeneralPagesIds.
|
134
|
-
return <
|
132
|
+
case GeneralPagesIds.overloadedShards: {
|
133
|
+
return <OverloadedShards tenantPath={tenantNameString} type={type} />;
|
135
134
|
}
|
136
135
|
case GeneralPagesIds.nodes: {
|
137
136
|
return (
|
@@ -3,7 +3,7 @@ import {EPathType} from '../../../types/api/schema';
|
|
3
3
|
export enum GeneralPagesIds {
|
4
4
|
'overview' = 'Overview',
|
5
5
|
'topQueries' = 'topQueries',
|
6
|
-
'
|
6
|
+
'overloadedShards' = 'overloadedShards',
|
7
7
|
'nodes' = 'Nodes',
|
8
8
|
'tablets' = 'Tablets',
|
9
9
|
'storage' = 'Storage',
|
@@ -29,9 +29,9 @@ const topQueries = {
|
|
29
29
|
title: 'Top queries',
|
30
30
|
};
|
31
31
|
|
32
|
-
const
|
33
|
-
id: GeneralPagesIds.
|
34
|
-
title: '
|
32
|
+
const overloadedShards = {
|
33
|
+
id: GeneralPagesIds.overloadedShards,
|
34
|
+
title: 'Overloaded shards',
|
35
35
|
};
|
36
36
|
|
37
37
|
const nodes = {
|
@@ -75,7 +75,7 @@ const consumers = {
|
|
75
75
|
export const DATABASE_PAGES = [
|
76
76
|
overview,
|
77
77
|
topQueries,
|
78
|
-
|
78
|
+
overloadedShards,
|
79
79
|
nodes,
|
80
80
|
tablets,
|
81
81
|
storage,
|
@@ -83,9 +83,9 @@ export const DATABASE_PAGES = [
|
|
83
83
|
describe,
|
84
84
|
];
|
85
85
|
|
86
|
-
export const TABLE_PAGES = [overview,
|
86
|
+
export const TABLE_PAGES = [overview, overloadedShards, graph, tablets, hotKeys, describe];
|
87
87
|
|
88
|
-
export const DIR_PAGES = [overview,
|
88
|
+
export const DIR_PAGES = [overview, overloadedShards, describe];
|
89
89
|
|
90
90
|
export const CDC_STREAM_PAGES = [overview, consumers, describe];
|
91
91
|
export const TOPIC_PAGES = [overview, consumers, describe];
|
@@ -0,0 +1,27 @@
|
|
1
|
+
.overloaded-shards {
|
2
|
+
display: flex;
|
3
|
+
flex-direction: column;
|
4
|
+
|
5
|
+
height: 100%;
|
6
|
+
|
7
|
+
background-color: var(--yc-color-base-background);
|
8
|
+
|
9
|
+
&__loader {
|
10
|
+
display: flex;
|
11
|
+
justify-content: center;
|
12
|
+
}
|
13
|
+
|
14
|
+
&__controls {
|
15
|
+
display: flex;
|
16
|
+
flex-wrap: wrap;
|
17
|
+
align-items: baseline;
|
18
|
+
gap: 16px;
|
19
|
+
|
20
|
+
margin-bottom: 10px;
|
21
|
+
}
|
22
|
+
|
23
|
+
&__table {
|
24
|
+
overflow: auto;
|
25
|
+
flex-grow: 1;
|
26
|
+
}
|
27
|
+
}
|
@@ -5,27 +5,36 @@ import cn from 'bem-cn-lite';
|
|
5
5
|
import DataTable, {Column, Settings, SortOrder} from '@yandex-cloud/react-data-table';
|
6
6
|
import {Loader} from '@gravity-ui/uikit';
|
7
7
|
|
8
|
+
import {DateRange, DateRangeValues} from '../../../../components/DateRange';
|
8
9
|
import InternalLink from '../../../../components/InternalLink/InternalLink';
|
9
10
|
|
10
11
|
import HistoryContext from '../../../../contexts/HistoryContext';
|
11
12
|
|
12
13
|
import routes, {createHref} from '../../../../routes';
|
13
14
|
|
14
|
-
import {
|
15
|
+
import {
|
16
|
+
sendShardQuery,
|
17
|
+
setShardsState,
|
18
|
+
setShardsQueryFilters,
|
19
|
+
} from '../../../../store/reducers/shardsWorkload';
|
15
20
|
import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema';
|
21
|
+
import type {IShardsWorkloadFilters} from '../../../../types/store/shardsWorkload';
|
16
22
|
|
17
23
|
import type {EPathType} from '../../../../types/api/schema';
|
18
24
|
|
19
|
-
import {
|
25
|
+
import {formatDateTime, formatNumber} from '../../../../utils';
|
26
|
+
import {DEFAULT_TABLE_SETTINGS, HOUR_IN_SECONDS} from '../../../../utils/constants';
|
20
27
|
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
|
21
|
-
import {i18n} from '../../../../utils/i18n';
|
22
28
|
import {prepareQueryError} from '../../../../utils/query';
|
23
29
|
|
30
|
+
import {getDefaultNodePath} from '../../../Node/NodePages';
|
31
|
+
|
24
32
|
import {isColumnEntityType} from '../../utils/schema';
|
25
33
|
|
26
|
-
import './
|
34
|
+
import i18n from './i18n';
|
35
|
+
import './OverloadedShards.scss';
|
27
36
|
|
28
|
-
const b = cn('
|
37
|
+
const b = cn('overloaded-shards');
|
29
38
|
const bLink = cn('yc-link');
|
30
39
|
|
31
40
|
const TABLE_SETTINGS: Settings = {
|
@@ -41,16 +50,15 @@ const tableColumnsNames = {
|
|
41
50
|
CPUCores: 'CPUCores',
|
42
51
|
DataSize: 'DataSize',
|
43
52
|
Path: 'Path',
|
53
|
+
NodeId: 'NodeId',
|
54
|
+
PeakTime: 'PeakTime',
|
55
|
+
InFlightTxCount: 'InFlightTxCount',
|
44
56
|
};
|
45
57
|
|
46
58
|
function prepareCPUWorkloadValue(value: string) {
|
47
59
|
return `${(Number(value) * 100).toFixed(2)}%`;
|
48
60
|
}
|
49
61
|
|
50
|
-
function prepareDateSizeValue(value: number) {
|
51
|
-
return new Intl.NumberFormat(i18n.lang).format(value);
|
52
|
-
}
|
53
|
-
|
54
62
|
function stringToDataTableSortOrder(value: string): SortOrder[] | undefined {
|
55
63
|
return value
|
56
64
|
? value.split(',').map((columnId) => ({
|
@@ -74,12 +82,12 @@ function dataTableToStringSortOrder(value: SortOrder | SortOrder[] = []) {
|
|
74
82
|
return sortOrders.map(({columnId}) => columnId).join(',');
|
75
83
|
}
|
76
84
|
|
77
|
-
interface
|
85
|
+
interface OverloadedShardsProps {
|
78
86
|
tenantPath: string;
|
79
87
|
type?: EPathType;
|
80
88
|
}
|
81
89
|
|
82
|
-
export const
|
90
|
+
export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
|
83
91
|
const dispatch = useDispatch();
|
84
92
|
|
85
93
|
const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
|
@@ -87,10 +95,24 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
|
87
95
|
const {
|
88
96
|
loading,
|
89
97
|
data: {result: data = undefined} = {},
|
98
|
+
filters: storeFilters,
|
90
99
|
error,
|
91
100
|
wasLoaded,
|
92
101
|
} = useTypedSelector((state) => state.shardsWorkload);
|
93
102
|
|
103
|
+
// default date range should be the last hour, but shouldn't propagate into URL until user interacts with the control
|
104
|
+
// redux initial value can't be used, as it synchronizes with URL
|
105
|
+
const [filters, setFilters] = useState<IShardsWorkloadFilters>(() => {
|
106
|
+
if (!storeFilters?.from && !storeFilters?.to) {
|
107
|
+
return {
|
108
|
+
from: Date.now() - HOUR_IN_SECONDS * 1000,
|
109
|
+
to: Date.now(),
|
110
|
+
};
|
111
|
+
}
|
112
|
+
|
113
|
+
return storeFilters;
|
114
|
+
});
|
115
|
+
|
94
116
|
const [sortOrder, setSortOrder] = useState(tableColumnsNames.CPUCores);
|
95
117
|
|
96
118
|
useAutofetcher(
|
@@ -100,32 +122,38 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
|
100
122
|
database: tenantPath,
|
101
123
|
path: currentSchemaPath,
|
102
124
|
sortOrder: stringToQuerySortOrder(sortOrder),
|
125
|
+
filters,
|
103
126
|
}),
|
104
127
|
);
|
105
128
|
},
|
106
|
-
[dispatch, currentSchemaPath,
|
129
|
+
[dispatch, tenantPath, currentSchemaPath, sortOrder, filters],
|
107
130
|
autorefresh,
|
108
131
|
);
|
109
132
|
|
110
133
|
// don't show loader for requests triggered by table sort, only for path change
|
111
134
|
useEffect(() => {
|
112
135
|
dispatch(
|
113
|
-
|
136
|
+
setShardsState({
|
114
137
|
wasLoaded: false,
|
115
138
|
data: undefined,
|
116
139
|
}),
|
117
140
|
);
|
118
|
-
}, [dispatch, currentSchemaPath, tenantPath]);
|
141
|
+
}, [dispatch, currentSchemaPath, tenantPath, filters]);
|
119
142
|
|
120
143
|
const history = useContext(HistoryContext);
|
121
144
|
|
122
145
|
const onSort = (newSortOrder?: SortOrder | SortOrder[]) => {
|
123
|
-
// omit information about sort order to disable ASC order, only DESC makes sense for
|
146
|
+
// omit information about sort order to disable ASC order, only DESC makes sense for overloaded shards
|
124
147
|
// use a string (and not the DataTable default format) to prevent reference change,
|
125
148
|
// which would cause an excess state change, to avoid repeating requests
|
126
149
|
setSortOrder(dataTableToStringSortOrder(newSortOrder));
|
127
150
|
};
|
128
151
|
|
152
|
+
const handleDateRangeChange = (value: DateRangeValues) => {
|
153
|
+
dispatch(setShardsQueryFilters(value));
|
154
|
+
setFilters(value);
|
155
|
+
};
|
156
|
+
|
129
157
|
const tableColumns: Column<any>[] = useMemo(() => {
|
130
158
|
const onSchemaClick = (schemaPath: string) => {
|
131
159
|
return () => {
|
@@ -161,7 +189,7 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
|
161
189
|
name: tableColumnsNames.DataSize,
|
162
190
|
header: 'DataSize (B)',
|
163
191
|
render: ({value}) => {
|
164
|
-
return
|
192
|
+
return formatNumber(value as number);
|
165
193
|
},
|
166
194
|
align: DataTable.RIGHT,
|
167
195
|
},
|
@@ -176,6 +204,29 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
|
176
204
|
},
|
177
205
|
sortable: false,
|
178
206
|
},
|
207
|
+
{
|
208
|
+
name: tableColumnsNames.NodeId,
|
209
|
+
render: ({value: nodeId}) => {
|
210
|
+
return (
|
211
|
+
<InternalLink to={getDefaultNodePath(nodeId as string)}>
|
212
|
+
{nodeId as string}
|
213
|
+
</InternalLink>
|
214
|
+
);
|
215
|
+
},
|
216
|
+
align: DataTable.RIGHT,
|
217
|
+
sortable: false,
|
218
|
+
},
|
219
|
+
{
|
220
|
+
name: tableColumnsNames.PeakTime,
|
221
|
+
render: ({value}) => formatDateTime(new Date(value as string).valueOf()),
|
222
|
+
sortable: false,
|
223
|
+
},
|
224
|
+
{
|
225
|
+
name: tableColumnsNames.InFlightTxCount,
|
226
|
+
render: ({value}) => formatNumber(value as number),
|
227
|
+
align: DataTable.RIGHT,
|
228
|
+
sortable: false,
|
229
|
+
},
|
179
230
|
];
|
180
231
|
}, [dispatch, history, tenantPath]);
|
181
232
|
|
@@ -192,12 +243,12 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
|
192
243
|
return renderLoader();
|
193
244
|
}
|
194
245
|
|
195
|
-
if (
|
196
|
-
return
|
246
|
+
if (error && !error.isCancelled) {
|
247
|
+
return <div className="error">{prepareQueryError(error)}</div>;
|
197
248
|
}
|
198
249
|
|
199
|
-
if (
|
200
|
-
return
|
250
|
+
if (!data || isColumnEntityType(type)) {
|
251
|
+
return i18n('no-data');
|
201
252
|
}
|
202
253
|
|
203
254
|
return (
|
@@ -216,6 +267,10 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
|
216
267
|
|
217
268
|
return (
|
218
269
|
<div className={b()}>
|
270
|
+
<div className={b('controls')}>
|
271
|
+
{i18n('description')}
|
272
|
+
<DateRange from={filters.from} to={filters.to} onChange={handleDateRangeChange} />
|
273
|
+
</div>
|
219
274
|
{renderContent()}
|
220
275
|
</div>
|
221
276
|
);
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import {i18n, Lang} from '../../../../../utils/i18n';
|
2
|
+
|
3
|
+
import en from './en.json';
|
4
|
+
import ru from './ru.json';
|
5
|
+
|
6
|
+
const COMPONENT = 'ydb-diagnostics-overloaded-shards';
|
7
|
+
|
8
|
+
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
9
|
+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
10
|
+
|
11
|
+
export default i18n.keyset(COMPONENT);
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './OverloadedShards';
|
@@ -1,43 +1,40 @@
|
|
1
1
|
@import '../../../../styles/mixins.scss';
|
2
2
|
|
3
3
|
.kv-top-queries {
|
4
|
+
display: flex;
|
5
|
+
flex-direction: column;
|
6
|
+
|
4
7
|
height: 100%;
|
5
8
|
|
6
9
|
@include query-data-table;
|
7
|
-
&__message-container {
|
8
|
-
padding: 15px 0;
|
9
|
-
}
|
10
10
|
|
11
11
|
&__loader {
|
12
12
|
display: flex;
|
13
13
|
justify-content: center;
|
14
14
|
}
|
15
15
|
|
16
|
-
&
|
17
|
-
|
16
|
+
&__controls {
|
17
|
+
display: flex;
|
18
|
+
flex-wrap: wrap;
|
19
|
+
gap: 16px;
|
18
20
|
|
19
|
-
|
20
|
-
display: inline-block;
|
21
|
-
}
|
21
|
+
margin-bottom: 10px;
|
22
22
|
}
|
23
23
|
|
24
|
-
&
|
25
|
-
|
26
|
-
line-height: var(--yc-text-body-1-line-height);
|
27
|
-
|
28
|
-
color: var(--yc-color-text-primary);
|
29
|
-
|
30
|
-
&::first-letter {
|
31
|
-
color: var(--yc-color-text-danger);
|
32
|
-
}
|
24
|
+
&__search {
|
25
|
+
@include search();
|
33
26
|
}
|
34
27
|
|
35
|
-
&__result
|
36
|
-
|
28
|
+
&__result {
|
29
|
+
overflow: auto;
|
30
|
+
flex-grow: 1;
|
31
|
+
|
32
|
+
.data-table {
|
37
33
|
&,
|
38
34
|
&__table {
|
39
35
|
width: 100%;
|
40
36
|
}
|
37
|
+
|
41
38
|
&__td {
|
42
39
|
vertical-align: top;
|
43
40
|
white-space: pre;
|