ydb-embedded-ui 3.3.3 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +28 -0
- package/dist/components/Errors/ResponseError/ResponseError.tsx +2 -2
- package/dist/components/InfoViewer/formatters/topicStats.tsx +8 -29
- package/dist/components/LabelWithPopover/LabelWithPopover.tsx +20 -0
- package/dist/components/LabelWithPopover/index.ts +1 -0
- package/dist/components/LagImages/LagImages.tsx +205 -0
- package/dist/components/LagImages/index.ts +1 -0
- package/dist/components/SpeedMultiMeter/SpeedMultiMeter.scss +92 -0
- package/dist/components/SpeedMultiMeter/SpeedMultiMeter.tsx +120 -0
- package/dist/components/SpeedMultiMeter/i18n/en.json +6 -0
- package/dist/components/SpeedMultiMeter/i18n/index.ts +13 -0
- package/dist/components/SpeedMultiMeter/i18n/ru.json +6 -0
- package/dist/components/SpeedMultiMeter/index.ts +1 -0
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +26 -14
- package/dist/containers/Storage/VDisk/VDisk.tsx +20 -5
- package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +34 -5
- package/dist/containers/Storage/utils/types.ts +5 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.scss +32 -3
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +62 -69
- package/dist/containers/Tenant/Diagnostics/Consumers/Headers/Headers.scss +13 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Headers/Headers.tsx +27 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Headers/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/TopicStats/ConsumersTopicStats.scss +32 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/TopicStats/ConsumersTopicStats.tsx +43 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/TopicStats/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/columns/Columns.scss +5 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx +66 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/columns/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/en.json +4 -3
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/ru.json +4 -3
- package/dist/containers/Tenant/Diagnostics/Consumers/utils/constants.ts +23 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +7 -3
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +15 -9
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.scss +9 -1
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +6 -8
- package/dist/containers/Tenant/Diagnostics/Partitions/Headers/Headers.scss +33 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/Headers/Headers.tsx +76 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/Headers/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/Partitions.scss +45 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/Partitions.tsx +254 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/PartitionsWrapper.tsx +79 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/columns/Columns.scss +13 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/columns/columns.tsx +246 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/columns/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/i18n/en.json +13 -0
- package/dist/containers/Tenant/Diagnostics/{OverloadedShards → Partitions}/i18n/index.ts +1 -1
- package/dist/containers/Tenant/Diagnostics/Partitions/i18n/ru.json +13 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/utils/constants.ts +74 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/utils/types.ts +6 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/Filters/Filters.scss +8 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/Filters/Filters.tsx +56 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/Filters/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/{OverloadedShards/OverloadedShards.scss → TopShards/TopShards.scss} +2 -10
- package/dist/containers/Tenant/Diagnostics/{OverloadedShards/OverloadedShards.tsx → TopShards/TopShards.tsx} +61 -31
- package/dist/containers/Tenant/Diagnostics/TopShards/i18n/en.json +6 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/i18n/ru.json +6 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/index.ts +1 -0
- package/dist/containers/Tenant/utils/schema.ts +1 -16
- package/dist/services/api.d.ts +4 -0
- package/dist/services/api.js +22 -6
- package/dist/store/reducers/authentication.js +0 -15
- package/dist/store/reducers/consumer.ts +160 -0
- package/dist/store/reducers/index.ts +2 -0
- package/dist/store/reducers/settings.js +2 -0
- package/dist/store/reducers/shardsWorkload.ts +28 -2
- package/dist/store/reducers/topic.ts +82 -2
- package/dist/store/state-url-mapping.js +3 -0
- package/dist/types/store/consumer.ts +55 -0
- package/dist/types/store/shardsWorkload.ts +6 -0
- package/dist/types/store/topic.ts +23 -6
- package/dist/utils/bytesParsers/convertBytesObjectToSpeed.ts +24 -0
- package/dist/utils/bytesParsers/formatBytesCustom.ts +57 -0
- package/dist/utils/bytesParsers/i18n/en.json +7 -0
- package/dist/utils/bytesParsers/i18n/index.ts +11 -0
- package/dist/utils/bytesParsers/i18n/ru.json +7 -0
- package/dist/utils/bytesParsers/index.ts +2 -0
- package/dist/utils/constants.ts +3 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/storage.ts +2 -2
- package/dist/utils/timeParsers/index.ts +2 -1
- package/dist/utils/timeParsers/parsers.ts +18 -0
- package/dist/utils/timeParsers/{protobuf.ts → protobufParsers.ts} +0 -0
- package/dist/utils/typecheckers.ts +5 -0
- package/dist/utils/utils.js +3 -3
- package/package.json +2 -2
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/i18n/en.json +0 -4
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/i18n/ru.json +0 -4
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/index.ts +0 -1
@@ -0,0 +1,246 @@
|
|
1
|
+
import DataTable, {Column} from '@gravity-ui/react-data-table';
|
2
|
+
import block from 'bem-cn-lite';
|
3
|
+
|
4
|
+
import {SpeedMultiMeter} from '../../../../../components/SpeedMultiMeter';
|
5
|
+
import EntityStatus from '../../../../../components/EntityStatus/EntityStatus';
|
6
|
+
import {getDefaultNodePath} from '../../../../Node/NodePages';
|
7
|
+
import {formatBytes, formatMsToUptime} from '../../../../../utils';
|
8
|
+
import {isNumeric} from '../../../../../utils/utils';
|
9
|
+
|
10
|
+
import {
|
11
|
+
PARTITIONS_COLUMNS_IDS,
|
12
|
+
PARTITIONS_COLUMNS_TITILES,
|
13
|
+
PARTITIONS_READ_LAGS_SUB_COLUMNS_IDS,
|
14
|
+
PARTITIONS_READ_LAGS_SUB_COLUMNS_TITLES,
|
15
|
+
PARTITIONS_WRITE_LAGS_SUB_COLUMNS_IDS,
|
16
|
+
PARTITIONS_WRITE_LAGS_SUB_COLUMNS_TITLES,
|
17
|
+
} from '../utils/constants';
|
18
|
+
import type {IPreparedPartitionDataWithHosts} from '../utils/types';
|
19
|
+
|
20
|
+
import {
|
21
|
+
MultilineHeader,
|
22
|
+
ReadLagsHeader,
|
23
|
+
ReadSessionHeader,
|
24
|
+
UncommitedMessagesHeader,
|
25
|
+
UnreadMessagesHeader,
|
26
|
+
WriteLagsHeader,
|
27
|
+
} from '../Headers';
|
28
|
+
|
29
|
+
import './Columns.scss';
|
30
|
+
|
31
|
+
const b = block('ydb-diagnostics-partitions-columns');
|
32
|
+
|
33
|
+
export const columns: Column<IPreparedPartitionDataWithHosts>[] = [
|
34
|
+
{
|
35
|
+
name: PARTITIONS_COLUMNS_IDS.PARTITION_ID,
|
36
|
+
header: (
|
37
|
+
<MultilineHeader
|
38
|
+
title={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.PARTITION_ID]}
|
39
|
+
/>
|
40
|
+
),
|
41
|
+
sortAccessor: (row) => isNumeric(row.partitionId) && Number(row.partitionId),
|
42
|
+
align: DataTable.LEFT,
|
43
|
+
render: ({row}) => row.partitionId,
|
44
|
+
},
|
45
|
+
{
|
46
|
+
name: PARTITIONS_COLUMNS_IDS.STORE_SIZE,
|
47
|
+
header: (
|
48
|
+
<MultilineHeader
|
49
|
+
title={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.STORE_SIZE]}
|
50
|
+
/>
|
51
|
+
),
|
52
|
+
align: DataTable.RIGHT,
|
53
|
+
render: ({row}) => formatBytes(row.storeSize),
|
54
|
+
},
|
55
|
+
{
|
56
|
+
name: PARTITIONS_COLUMNS_IDS.WRITE_SPEED,
|
57
|
+
header: PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.WRITE_SPEED],
|
58
|
+
align: DataTable.LEFT,
|
59
|
+
sortAccessor: (row) => row.writeSpeed.perMinute,
|
60
|
+
render: ({row}) => <SpeedMultiMeter data={row.writeSpeed} />,
|
61
|
+
},
|
62
|
+
{
|
63
|
+
name: PARTITIONS_COLUMNS_IDS.READ_SPEED,
|
64
|
+
header: PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.READ_SPEED],
|
65
|
+
align: DataTable.LEFT,
|
66
|
+
sortAccessor: (row) => row.readSpeed.perMinute,
|
67
|
+
render: ({row}) => <SpeedMultiMeter data={row.readSpeed} />,
|
68
|
+
},
|
69
|
+
{
|
70
|
+
name: PARTITIONS_COLUMNS_IDS.WRITE_LAGS,
|
71
|
+
header: <WriteLagsHeader />,
|
72
|
+
className: b('lags-header'),
|
73
|
+
sub: [
|
74
|
+
{
|
75
|
+
name: PARTITIONS_WRITE_LAGS_SUB_COLUMNS_IDS.PARTITION_WRITE_LAG,
|
76
|
+
header: PARTITIONS_WRITE_LAGS_SUB_COLUMNS_TITLES[
|
77
|
+
PARTITIONS_WRITE_LAGS_SUB_COLUMNS_IDS.PARTITION_WRITE_LAG
|
78
|
+
],
|
79
|
+
align: DataTable.RIGHT,
|
80
|
+
render: ({row}) => formatMsToUptime(row.partitionWriteLag),
|
81
|
+
},
|
82
|
+
{
|
83
|
+
name: PARTITIONS_WRITE_LAGS_SUB_COLUMNS_IDS.PARTITION_WRITE_IDLE_TIME,
|
84
|
+
header: PARTITIONS_WRITE_LAGS_SUB_COLUMNS_TITLES[
|
85
|
+
PARTITIONS_WRITE_LAGS_SUB_COLUMNS_IDS.PARTITION_WRITE_IDLE_TIME
|
86
|
+
],
|
87
|
+
align: DataTable.RIGHT,
|
88
|
+
render: ({row}) => formatMsToUptime(row.partitionWriteIdleTime),
|
89
|
+
},
|
90
|
+
],
|
91
|
+
},
|
92
|
+
{
|
93
|
+
name: PARTITIONS_COLUMNS_IDS.READ_LAGS,
|
94
|
+
header: <ReadLagsHeader />,
|
95
|
+
className: b('lags-header'),
|
96
|
+
sub: [
|
97
|
+
{
|
98
|
+
name: PARTITIONS_READ_LAGS_SUB_COLUMNS_IDS.CONSUMER_WRITE_LAG,
|
99
|
+
header: PARTITIONS_READ_LAGS_SUB_COLUMNS_TITLES[
|
100
|
+
PARTITIONS_READ_LAGS_SUB_COLUMNS_IDS.CONSUMER_WRITE_LAG
|
101
|
+
],
|
102
|
+
align: DataTable.RIGHT,
|
103
|
+
render: ({row}) => formatMsToUptime(row.consumerWriteLag),
|
104
|
+
},
|
105
|
+
{
|
106
|
+
name: PARTITIONS_READ_LAGS_SUB_COLUMNS_IDS.CONSUMER_READ_LAG,
|
107
|
+
header: PARTITIONS_READ_LAGS_SUB_COLUMNS_TITLES[
|
108
|
+
PARTITIONS_READ_LAGS_SUB_COLUMNS_IDS.CONSUMER_READ_LAG
|
109
|
+
],
|
110
|
+
align: DataTable.RIGHT,
|
111
|
+
render: ({row}) => formatMsToUptime(row.consumerReadLag),
|
112
|
+
},
|
113
|
+
{
|
114
|
+
name: PARTITIONS_READ_LAGS_SUB_COLUMNS_IDS.CONSUMER_READ_IDLE_TIME,
|
115
|
+
header: PARTITIONS_READ_LAGS_SUB_COLUMNS_TITLES[
|
116
|
+
PARTITIONS_READ_LAGS_SUB_COLUMNS_IDS.CONSUMER_READ_IDLE_TIME
|
117
|
+
],
|
118
|
+
align: DataTable.RIGHT,
|
119
|
+
render: ({row}) => formatMsToUptime(row.consumerReadIdleTime),
|
120
|
+
},
|
121
|
+
],
|
122
|
+
},
|
123
|
+
{
|
124
|
+
name: PARTITIONS_COLUMNS_IDS.UNCOMMITED_MESSAGES,
|
125
|
+
header: <UncommitedMessagesHeader />,
|
126
|
+
align: DataTable.RIGHT,
|
127
|
+
render: ({row}) => row.uncommitedMessages,
|
128
|
+
},
|
129
|
+
{
|
130
|
+
name: PARTITIONS_COLUMNS_IDS.UNREAD_MESSAGES,
|
131
|
+
header: <UnreadMessagesHeader />,
|
132
|
+
align: DataTable.RIGHT,
|
133
|
+
render: ({row}) => row.unreadMessages,
|
134
|
+
},
|
135
|
+
{
|
136
|
+
name: PARTITIONS_COLUMNS_IDS.START_OFFSET,
|
137
|
+
header: (
|
138
|
+
<MultilineHeader
|
139
|
+
title={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.START_OFFSET]}
|
140
|
+
/>
|
141
|
+
),
|
142
|
+
sortAccessor: (row) => isNumeric(row.startOffset) && Number(row.startOffset),
|
143
|
+
align: DataTable.RIGHT,
|
144
|
+
render: ({row}) => row.startOffset,
|
145
|
+
},
|
146
|
+
{
|
147
|
+
name: PARTITIONS_COLUMNS_IDS.END_OFFSET,
|
148
|
+
header: (
|
149
|
+
<MultilineHeader
|
150
|
+
title={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.END_OFFSET]}
|
151
|
+
/>
|
152
|
+
),
|
153
|
+
sortAccessor: (row) => isNumeric(row.endOffset) && Number(row.endOffset),
|
154
|
+
align: DataTable.RIGHT,
|
155
|
+
render: ({row}) => row.endOffset,
|
156
|
+
},
|
157
|
+
{
|
158
|
+
name: PARTITIONS_COLUMNS_IDS.COMMITED_OFFSET,
|
159
|
+
header: (
|
160
|
+
<MultilineHeader
|
161
|
+
title={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.COMMITED_OFFSET]}
|
162
|
+
/>
|
163
|
+
),
|
164
|
+
sortAccessor: (row) => isNumeric(row.commitedOffset) && Number(row.commitedOffset),
|
165
|
+
align: DataTable.RIGHT,
|
166
|
+
render: ({row}) => row.commitedOffset,
|
167
|
+
},
|
168
|
+
{
|
169
|
+
name: PARTITIONS_COLUMNS_IDS.READ_SESSION_ID,
|
170
|
+
header: <ReadSessionHeader />,
|
171
|
+
align: DataTable.LEFT,
|
172
|
+
render: ({row}) =>
|
173
|
+
row.readSessionId ? (
|
174
|
+
<EntityStatus
|
175
|
+
name={row.readSessionId}
|
176
|
+
showStatus={false}
|
177
|
+
hasClipboardButton
|
178
|
+
className={b('string-with-copy')}
|
179
|
+
/>
|
180
|
+
) : (
|
181
|
+
'–'
|
182
|
+
),
|
183
|
+
},
|
184
|
+
{
|
185
|
+
name: PARTITIONS_COLUMNS_IDS.READER_NAME,
|
186
|
+
header: (
|
187
|
+
<MultilineHeader
|
188
|
+
title={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.READER_NAME]}
|
189
|
+
/>
|
190
|
+
),
|
191
|
+
align: DataTable.LEFT,
|
192
|
+
render: ({row}) =>
|
193
|
+
row.readerName ? (
|
194
|
+
<EntityStatus
|
195
|
+
name={row.readerName}
|
196
|
+
showStatus={false}
|
197
|
+
hasClipboardButton
|
198
|
+
className={b('string-with-copy')}
|
199
|
+
/>
|
200
|
+
) : (
|
201
|
+
'–'
|
202
|
+
),
|
203
|
+
},
|
204
|
+
{
|
205
|
+
name: PARTITIONS_COLUMNS_IDS.PARTITION_HOST,
|
206
|
+
header: (
|
207
|
+
<MultilineHeader
|
208
|
+
title={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.PARTITION_HOST]}
|
209
|
+
/>
|
210
|
+
),
|
211
|
+
align: DataTable.LEFT,
|
212
|
+
render: ({row}) =>
|
213
|
+
row.partitionHost ? (
|
214
|
+
<EntityStatus
|
215
|
+
name={row.partitionHost}
|
216
|
+
path={getDefaultNodePath(row.partitionHost)}
|
217
|
+
showStatus={false}
|
218
|
+
hasClipboardButton
|
219
|
+
className={b('string-with-copy')}
|
220
|
+
/>
|
221
|
+
) : (
|
222
|
+
'–'
|
223
|
+
),
|
224
|
+
},
|
225
|
+
{
|
226
|
+
name: PARTITIONS_COLUMNS_IDS.CONNECTION_HOST,
|
227
|
+
header: (
|
228
|
+
<MultilineHeader
|
229
|
+
title={PARTITIONS_COLUMNS_TITILES[PARTITIONS_COLUMNS_IDS.CONNECTION_HOST]}
|
230
|
+
/>
|
231
|
+
),
|
232
|
+
align: DataTable.LEFT,
|
233
|
+
render: ({row}) =>
|
234
|
+
row.connectionHost ? (
|
235
|
+
<EntityStatus
|
236
|
+
name={row.connectionHost}
|
237
|
+
path={getDefaultNodePath(row.connectionNodeId)}
|
238
|
+
showStatus={false}
|
239
|
+
hasClipboardButton
|
240
|
+
className={b('string-with-copy')}
|
241
|
+
/>
|
242
|
+
) : (
|
243
|
+
'–'
|
244
|
+
),
|
245
|
+
},
|
246
|
+
];
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './columns';
|
@@ -0,0 +1,13 @@
|
|
1
|
+
{
|
2
|
+
"lagsPopover.writeLags": "Write lags statistics (time format dd hh:mm:ss)",
|
3
|
+
"lagsPopover.readLags": "Read lags statistics (time format dd hh:mm:ss)",
|
4
|
+
"headers.unread": "End offset - Last read offset",
|
5
|
+
"headers.uncommited": "End offset - Committed offset",
|
6
|
+
"controls.consumerSelector": "Consumer:",
|
7
|
+
"controls.consumerSelector.placeholder": "Consumer",
|
8
|
+
"controls.partitionSearch": "Partition ID",
|
9
|
+
"controls.generalSearch": "Host, Host ID, Reader, Read Session ID",
|
10
|
+
"table.emptyDataMessage": "No partitions match the current search",
|
11
|
+
"noConsumersMessage.topic": "This topic has no consumers",
|
12
|
+
"noConsumersMessage.stream": "This changefeed has no consumers"
|
13
|
+
}
|
@@ -3,7 +3,7 @@ import {i18n, Lang} from '../../../../../utils/i18n';
|
|
3
3
|
import en from './en.json';
|
4
4
|
import ru from './ru.json';
|
5
5
|
|
6
|
-
const COMPONENT = 'ydb-diagnostics-
|
6
|
+
const COMPONENT = 'ydb-diagnostics-partitions';
|
7
7
|
|
8
8
|
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
9
9
|
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
@@ -0,0 +1,13 @@
|
|
1
|
+
{
|
2
|
+
"lagsPopover.writeLags": "Статистика лагов записи (формат времени дд чч:мм:сс)",
|
3
|
+
"lagsPopover.readLags": "Статистика лагов чтения (формат времени дд чч:мм:сс)",
|
4
|
+
"headers.unread": "End offset - Last read offset",
|
5
|
+
"headers.uncommited": "End offset - Committed offset",
|
6
|
+
"controls.consumerSelector": "Читатель:",
|
7
|
+
"controls.consumerSelector.placeholder": "Читатель",
|
8
|
+
"controls.partitionSearch": "Partition ID",
|
9
|
+
"controls.generalSearch": "Host, Host ID, Reader, Read Session ID",
|
10
|
+
"table.emptyDataMessage": "По заданному поиску нет партиций",
|
11
|
+
"noConsumersMessage.topic": "У этого топика нет читателей",
|
12
|
+
"noConsumersMessage.stream": "У этого стрима нет читателей"
|
13
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './PartitionsWrapper';
|
@@ -0,0 +1,74 @@
|
|
1
|
+
export const PARTITIONS_COLUMNS_IDS = {
|
2
|
+
PARTITION_ID: 'partitionId',
|
3
|
+
|
4
|
+
STORE_SIZE: 'storeSize',
|
5
|
+
|
6
|
+
WRITE_SPEED: 'writeSpeed',
|
7
|
+
READ_SPEED: 'readSpeed',
|
8
|
+
|
9
|
+
WRITE_LAGS: 'writeLags',
|
10
|
+
READ_LAGS: 'readLags',
|
11
|
+
|
12
|
+
UNCOMMITED_MESSAGES: 'uncommitedMessages',
|
13
|
+
UNREAD_MESSAGES: 'unreadMessages',
|
14
|
+
|
15
|
+
START_OFFSET: 'startOffset',
|
16
|
+
END_OFFSET: 'endOffset',
|
17
|
+
COMMITED_OFFSET: 'commitedOffset',
|
18
|
+
|
19
|
+
READ_SESSION_ID: 'readSessionId',
|
20
|
+
READER_NAME: 'readerName',
|
21
|
+
|
22
|
+
PARTITION_HOST: 'partitionHost',
|
23
|
+
CONNECTION_HOST: 'connectionHost',
|
24
|
+
} as const;
|
25
|
+
|
26
|
+
export const PARTITIONS_COLUMNS_TITILES = {
|
27
|
+
[PARTITIONS_COLUMNS_IDS.PARTITION_ID]: 'Partition ID',
|
28
|
+
|
29
|
+
[PARTITIONS_COLUMNS_IDS.STORE_SIZE]: 'Store size',
|
30
|
+
|
31
|
+
[PARTITIONS_COLUMNS_IDS.WRITE_SPEED]: 'Write speed',
|
32
|
+
[PARTITIONS_COLUMNS_IDS.READ_SPEED]: 'Read speed',
|
33
|
+
|
34
|
+
[PARTITIONS_COLUMNS_IDS.WRITE_LAGS]: 'Write lags, duration',
|
35
|
+
|
36
|
+
[PARTITIONS_COLUMNS_IDS.READ_LAGS]: 'Read lags, duration',
|
37
|
+
|
38
|
+
[PARTITIONS_COLUMNS_IDS.UNCOMMITED_MESSAGES]: 'Uncommited messages',
|
39
|
+
[PARTITIONS_COLUMNS_IDS.UNREAD_MESSAGES]: 'Unread messages',
|
40
|
+
|
41
|
+
[PARTITIONS_COLUMNS_IDS.START_OFFSET]: 'Start offset',
|
42
|
+
[PARTITIONS_COLUMNS_IDS.END_OFFSET]: 'End offset',
|
43
|
+
[PARTITIONS_COLUMNS_IDS.COMMITED_OFFSET]: 'Commited offset',
|
44
|
+
|
45
|
+
[PARTITIONS_COLUMNS_IDS.READ_SESSION_ID]: 'Read session ID',
|
46
|
+
[PARTITIONS_COLUMNS_IDS.READER_NAME]: 'Reader name',
|
47
|
+
|
48
|
+
[PARTITIONS_COLUMNS_IDS.PARTITION_HOST]: 'Partition host',
|
49
|
+
[PARTITIONS_COLUMNS_IDS.CONNECTION_HOST]: 'Connection host',
|
50
|
+
} as const;
|
51
|
+
|
52
|
+
export const PARTITIONS_WRITE_LAGS_SUB_COLUMNS_IDS = {
|
53
|
+
PARTITION_WRITE_LAG: 'partitionWriteLag',
|
54
|
+
PARTITION_WRITE_IDLE_TIME: 'partitionWriteIdleTime',
|
55
|
+
} as const;
|
56
|
+
|
57
|
+
export const PARTITIONS_WRITE_LAGS_SUB_COLUMNS_TITLES = {
|
58
|
+
[PARTITIONS_WRITE_LAGS_SUB_COLUMNS_IDS.PARTITION_WRITE_LAG]: 'write lag',
|
59
|
+
[PARTITIONS_WRITE_LAGS_SUB_COLUMNS_IDS.PARTITION_WRITE_IDLE_TIME]: 'write idle time',
|
60
|
+
} as const;
|
61
|
+
|
62
|
+
export const PARTITIONS_READ_LAGS_SUB_COLUMNS_IDS = {
|
63
|
+
CONSUMER_WRITE_LAG: 'consumerWriteLag',
|
64
|
+
CONSUMER_READ_LAG: 'consumerReadLag',
|
65
|
+
CONSUMER_READ_IDLE_TIME: 'consumerReadIdleTime',
|
66
|
+
} as const;
|
67
|
+
|
68
|
+
export const PARTITIONS_READ_LAGS_SUB_COLUMNS_TITLES = {
|
69
|
+
[PARTITIONS_READ_LAGS_SUB_COLUMNS_IDS.CONSUMER_WRITE_LAG]: 'write lag',
|
70
|
+
[PARTITIONS_READ_LAGS_SUB_COLUMNS_IDS.CONSUMER_READ_LAG]: 'read lag',
|
71
|
+
[PARTITIONS_READ_LAGS_SUB_COLUMNS_IDS.CONSUMER_READ_IDLE_TIME]: 'read idle time',
|
72
|
+
} as const;
|
73
|
+
|
74
|
+
export const PARTITIONS_DEFAULT_SELECTED_COLUMNS = Object.values(PARTITIONS_COLUMNS_IDS);
|
@@ -0,0 +1,56 @@
|
|
1
|
+
import {RadioButton} from '@gravity-ui/uikit';
|
2
|
+
|
3
|
+
import {DateRange, DateRangeValues} from '../../../../../components/DateRange';
|
4
|
+
|
5
|
+
import {
|
6
|
+
EShardsWorkloadMode,
|
7
|
+
IShardsWorkloadFilters,
|
8
|
+
} from '../../../../../types/store/shardsWorkload';
|
9
|
+
|
10
|
+
import {isEnumMember} from '../../../../../utils/typecheckers';
|
11
|
+
|
12
|
+
import i18n from '../i18n';
|
13
|
+
import {b} from '../TopShards';
|
14
|
+
|
15
|
+
import './Filters.scss';
|
16
|
+
|
17
|
+
interface FiltersProps {
|
18
|
+
value: IShardsWorkloadFilters;
|
19
|
+
onChange: (value: Partial<IShardsWorkloadFilters>) => void;
|
20
|
+
className?: string;
|
21
|
+
}
|
22
|
+
|
23
|
+
export const Filters = ({value, onChange, className}: FiltersProps) => {
|
24
|
+
const handleModeChange = (mode: string) => {
|
25
|
+
if (!isEnumMember(EShardsWorkloadMode, mode)) {
|
26
|
+
const values = Object.values(EShardsWorkloadMode).join(', ');
|
27
|
+
throw new Error(`Unexpected TopShards mode "${mode}". Should be one of: ${values}`);
|
28
|
+
}
|
29
|
+
|
30
|
+
onChange({mode});
|
31
|
+
};
|
32
|
+
|
33
|
+
const handleDateRangeChange = (dateRange: DateRangeValues) => {
|
34
|
+
onChange({
|
35
|
+
mode: EShardsWorkloadMode.History,
|
36
|
+
...dateRange,
|
37
|
+
});
|
38
|
+
};
|
39
|
+
|
40
|
+
const from = value.mode === EShardsWorkloadMode.Immediate ? undefined : value.from;
|
41
|
+
const to = value.mode === EShardsWorkloadMode.Immediate ? undefined : value.to;
|
42
|
+
|
43
|
+
return (
|
44
|
+
<div className={b('filters', className)}>
|
45
|
+
<RadioButton value={value.mode} onUpdate={handleModeChange}>
|
46
|
+
<RadioButton.Option value={EShardsWorkloadMode.Immediate}>
|
47
|
+
{i18n('filters.mode.immediate')}
|
48
|
+
</RadioButton.Option>
|
49
|
+
<RadioButton.Option value={EShardsWorkloadMode.History}>
|
50
|
+
{i18n('filters.mode.history')}
|
51
|
+
</RadioButton.Option>
|
52
|
+
</RadioButton>
|
53
|
+
<DateRange from={from} to={to} onChange={handleDateRangeChange} />
|
54
|
+
</div>
|
55
|
+
);
|
56
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './Filters';
|
@@ -1,6 +1,7 @@
|
|
1
|
-
.
|
1
|
+
.top-shards {
|
2
2
|
display: flex;
|
3
3
|
flex-direction: column;
|
4
|
+
gap: 10px;
|
4
5
|
|
5
6
|
height: 100%;
|
6
7
|
|
@@ -11,15 +12,6 @@
|
|
11
12
|
justify-content: center;
|
12
13
|
}
|
13
14
|
|
14
|
-
&__controls {
|
15
|
-
display: flex;
|
16
|
-
flex-wrap: wrap;
|
17
|
-
align-items: baseline;
|
18
|
-
gap: 16px;
|
19
|
-
|
20
|
-
margin-bottom: 10px;
|
21
|
-
}
|
22
|
-
|
23
15
|
&__table {
|
24
16
|
overflow: auto;
|
25
17
|
flex-grow: 1;
|
@@ -5,7 +5,6 @@ import cn from 'bem-cn-lite';
|
|
5
5
|
import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
|
6
6
|
import {Loader} from '@gravity-ui/uikit';
|
7
7
|
|
8
|
-
import {DateRange, DateRangeValues} from '../../../../components/DateRange';
|
9
8
|
import {InternalLink} from '../../../../components/InternalLink';
|
10
9
|
|
11
10
|
import HistoryContext from '../../../../contexts/HistoryContext';
|
@@ -18,7 +17,7 @@ import {
|
|
18
17
|
setShardsQueryFilters,
|
19
18
|
} from '../../../../store/reducers/shardsWorkload';
|
20
19
|
import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema';
|
21
|
-
import
|
20
|
+
import {EShardsWorkloadMode, IShardsWorkloadFilters} from '../../../../types/store/shardsWorkload';
|
22
21
|
|
23
22
|
import type {EPathType} from '../../../../types/api/schema';
|
24
23
|
|
@@ -31,10 +30,12 @@ import {getDefaultNodePath} from '../../../Node/NodePages';
|
|
31
30
|
|
32
31
|
import {isColumnEntityType} from '../../utils/schema';
|
33
32
|
|
33
|
+
import {Filters} from './Filters';
|
34
|
+
|
34
35
|
import i18n from './i18n';
|
35
|
-
import './
|
36
|
+
import './TopShards.scss';
|
36
37
|
|
37
|
-
const b = cn('
|
38
|
+
export const b = cn('top-shards');
|
38
39
|
const bLink = cn('yc-link');
|
39
40
|
|
40
41
|
const TABLE_SETTINGS: Settings = {
|
@@ -83,12 +84,18 @@ function dataTableToStringSortOrder(value: SortOrder | SortOrder[] = []) {
|
|
83
84
|
return sortOrders.map(({columnId}) => columnId).join(',');
|
84
85
|
}
|
85
86
|
|
86
|
-
|
87
|
+
function fillDateRangeFor(value: IShardsWorkloadFilters) {
|
88
|
+
value.to = Date.now();
|
89
|
+
value.from = value.to - HOUR_IN_SECONDS * 1000;
|
90
|
+
return value;
|
91
|
+
}
|
92
|
+
|
93
|
+
interface TopShardsProps {
|
87
94
|
tenantPath: string;
|
88
95
|
type?: EPathType;
|
89
96
|
}
|
90
97
|
|
91
|
-
export const
|
98
|
+
export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
92
99
|
const dispatch = useDispatch();
|
93
100
|
|
94
101
|
const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
|
@@ -101,17 +108,20 @@ export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
|
|
101
108
|
wasLoaded,
|
102
109
|
} = useTypedSelector((state) => state.shardsWorkload);
|
103
110
|
|
104
|
-
// default
|
111
|
+
// default filters shouldn't propagate into URL until user interacts with the control
|
105
112
|
// redux initial value can't be used, as it synchronizes with URL
|
106
113
|
const [filters, setFilters] = useState<IShardsWorkloadFilters>(() => {
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
114
|
+
const defaultValue = {...storeFilters};
|
115
|
+
|
116
|
+
if (!defaultValue.mode) {
|
117
|
+
defaultValue.mode = EShardsWorkloadMode.Immediate;
|
118
|
+
}
|
119
|
+
|
120
|
+
if (!defaultValue.from && !defaultValue.to) {
|
121
|
+
fillDateRangeFor(defaultValue);
|
112
122
|
}
|
113
123
|
|
114
|
-
return
|
124
|
+
return defaultValue;
|
115
125
|
});
|
116
126
|
|
117
127
|
const [sortOrder, setSortOrder] = useState(tableColumnsNames.CPUCores);
|
@@ -144,18 +154,34 @@ export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
|
|
144
154
|
const history = useContext(HistoryContext);
|
145
155
|
|
146
156
|
const onSort = (newSortOrder?: SortOrder | SortOrder[]) => {
|
147
|
-
// omit information about sort order to disable ASC order, only DESC makes sense for
|
157
|
+
// omit information about sort order to disable ASC order, only DESC makes sense for top shards
|
148
158
|
// use a string (and not the DataTable default format) to prevent reference change,
|
149
159
|
// which would cause an excess state change, to avoid repeating requests
|
150
160
|
setSortOrder(dataTableToStringSortOrder(newSortOrder));
|
151
161
|
};
|
152
162
|
|
153
|
-
const
|
163
|
+
const handleFiltersChange = (value: Partial<IShardsWorkloadFilters>) => {
|
164
|
+
const newStateValue = {...value};
|
165
|
+
const isDateRangePristine =
|
166
|
+
!storeFilters.from && !storeFilters.to && !value.from && !value.to;
|
167
|
+
|
168
|
+
if (isDateRangePristine) {
|
169
|
+
switch (value.mode) {
|
170
|
+
case EShardsWorkloadMode.Immediate:
|
171
|
+
newStateValue.from = newStateValue.to = undefined;
|
172
|
+
break;
|
173
|
+
case EShardsWorkloadMode.History:
|
174
|
+
// should default to the current datetime every time history mode activates
|
175
|
+
fillDateRangeFor(newStateValue);
|
176
|
+
break;
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
154
180
|
dispatch(setShardsQueryFilters(value));
|
155
|
-
setFilters(
|
181
|
+
setFilters((state) => ({...state, ...newStateValue}));
|
156
182
|
};
|
157
183
|
|
158
|
-
const tableColumns
|
184
|
+
const tableColumns = useMemo(() => {
|
159
185
|
const onSchemaClick = (schemaPath: string) => {
|
160
186
|
return () => {
|
161
187
|
dispatch(setCurrentSchemaPath(schemaPath));
|
@@ -164,7 +190,7 @@ export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
|
|
164
190
|
};
|
165
191
|
};
|
166
192
|
|
167
|
-
|
193
|
+
const columns: Column<any>[] = [
|
168
194
|
{
|
169
195
|
name: tableColumnsNames.Path,
|
170
196
|
render: ({value: relativeNodePath}) => {
|
@@ -217,23 +243,29 @@ export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
|
|
217
243
|
align: DataTable.RIGHT,
|
218
244
|
sortable: false,
|
219
245
|
},
|
220
|
-
{
|
221
|
-
name: tableColumnsNames.PeakTime,
|
222
|
-
render: ({value}) => formatDateTime(new Date(value as string).valueOf()),
|
223
|
-
sortable: false,
|
224
|
-
},
|
225
246
|
{
|
226
247
|
name: tableColumnsNames.InFlightTxCount,
|
227
248
|
render: ({value}) => formatNumber(value as number),
|
228
249
|
align: DataTable.RIGHT,
|
229
250
|
sortable: false,
|
230
251
|
},
|
231
|
-
|
252
|
+
];
|
253
|
+
|
254
|
+
if (filters.mode === EShardsWorkloadMode.History) {
|
255
|
+
// after NodeId
|
256
|
+
columns.splice(5, 0, {
|
257
|
+
name: tableColumnsNames.PeakTime,
|
258
|
+
render: ({value}) => formatDateTime(new Date(value as string).valueOf()),
|
259
|
+
sortable: false,
|
260
|
+
});
|
261
|
+
columns.push({
|
232
262
|
name: tableColumnsNames.IntervalEnd,
|
233
263
|
render: ({value}) => formatDateTime(new Date(value as string).getTime()),
|
234
|
-
}
|
235
|
-
|
236
|
-
|
264
|
+
});
|
265
|
+
}
|
266
|
+
|
267
|
+
return columns;
|
268
|
+
}, [dispatch, filters.mode, history, tenantPath]);
|
237
269
|
|
238
270
|
const renderLoader = () => {
|
239
271
|
return (
|
@@ -272,10 +304,8 @@ export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
|
|
272
304
|
|
273
305
|
return (
|
274
306
|
<div className={b()}>
|
275
|
-
<
|
276
|
-
|
277
|
-
<DateRange from={filters.from} to={filters.to} onChange={handleDateRangeChange} />
|
278
|
-
</div>
|
307
|
+
<Filters value={filters} onChange={handleFiltersChange} />
|
308
|
+
{filters.mode === EShardsWorkloadMode.History && <div>{i18n('description')}</div>}
|
279
309
|
{renderContent()}
|
280
310
|
</div>
|
281
311
|
);
|
@@ -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-top-shards';
|
7
|
+
|
8
|
+
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
9
|
+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
10
|
+
|
11
|
+
export default i18n.keyset(COMPONENT);
|