ydb-embedded-ui 3.2.2 → 3.3.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/InfoViewer/InfoViewer.scss +10 -0
- package/dist/components/InfoViewer/InfoViewer.tsx +12 -2
- package/dist/components/InfoViewer/formatters/cdcStream.ts +10 -0
- package/dist/components/InfoViewer/formatters/index.ts +3 -0
- package/dist/components/InfoViewer/formatters/pqGroup.ts +51 -0
- package/dist/components/InfoViewer/formatters/schema.ts +1 -29
- package/dist/components/InfoViewer/formatters/topicStats.tsx +50 -0
- package/dist/components/InfoViewer/schemaInfo/index.ts +0 -2
- package/dist/components/InfoViewer/utils.ts +15 -0
- package/dist/components/InternalLink/InternalLink.tsx +17 -0
- package/dist/components/InternalLink/index.ts +1 -0
- package/dist/components/Tablet/Tablet.js +1 -1
- package/dist/components/TabletsStatistic/TabletsStatistic.tsx +1 -1
- package/dist/components/VerticalBars/VerticalBars.scss +15 -0
- package/dist/components/VerticalBars/VerticalBars.tsx +38 -0
- package/dist/components/VerticalBars/index.ts +1 -0
- package/dist/containers/App/App.js +0 -11
- package/dist/containers/App/App.scss +0 -1
- package/dist/containers/Cluster/Cluster.tsx +2 -2
- package/dist/containers/Nodes/Nodes.scss +5 -1
- package/dist/containers/Nodes/Nodes.tsx +196 -0
- package/dist/containers/{App → Nodes}/NodesTable.scss +2 -2
- package/dist/{utils/getNodesColumns.js → containers/Nodes/getNodesColumns.tsx} +60 -35
- package/dist/containers/Nodes/i18n/en.json +3 -0
- package/dist/containers/Nodes/i18n/index.ts +11 -0
- package/dist/containers/Nodes/i18n/ru.json +3 -0
- package/dist/containers/Nodes/index.ts +1 -0
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +14 -20
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +32 -16
- package/dist/containers/Storage/DiskStateProgressBar/index.ts +1 -0
- package/dist/containers/Storage/{Pdisk/Pdisk.scss → PDisk/PDisk.scss} +15 -4
- package/dist/containers/Storage/PDisk/PDisk.tsx +145 -0
- package/dist/containers/Storage/PDisk/__tests__/colors.tsx +37 -0
- package/dist/containers/Storage/PDisk/index.ts +1 -0
- package/dist/containers/Storage/PDiskPopup/PDiskPopup.scss +3 -0
- package/dist/containers/Storage/PDiskPopup/PDiskPopup.tsx +82 -0
- package/dist/containers/Storage/PDiskPopup/index.ts +1 -0
- package/dist/containers/Storage/Storage.js +1 -1
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +10 -10
- package/dist/containers/Storage/StorageNodes/StorageNodes.scss +1 -0
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +7 -4
- package/dist/containers/Storage/VDisk/VDisk.scss +7 -0
- package/dist/containers/Storage/VDisk/VDisk.tsx +148 -0
- package/dist/containers/Storage/VDisk/__tests__/colors.tsx +209 -0
- package/dist/containers/Storage/VDisk/index.ts +1 -0
- package/dist/containers/Storage/VDiskPopup/VDiskPopup.scss +14 -0
- package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +134 -0
- package/dist/containers/Storage/VDiskPopup/index.ts +1 -0
- package/dist/containers/Storage/utils/constants.ts +2 -9
- package/dist/containers/TabletsFilters/TabletsFilters.js +10 -6
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +2 -1
- package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +2 -2
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -4
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/OverloadedShards.tsx +1 -1
- package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/ChangefeedInfo.tsx +69 -0
- package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +18 -16
- package/dist/containers/Tenant/Diagnostics/Overview/TopicInfo/TopicInfo.tsx +37 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicInfo/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.scss +30 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +94 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/en.json +3 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/ru.json +3 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/utils/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/utils/prepareTopicSchemaInfo.ts +42 -0
- package/dist/containers/Tenant/utils/schema.ts +19 -0
- package/dist/containers/Tenants/Tenants.js +2 -1
- package/dist/containers/UserSettings/UserSettings.tsx +18 -10
- package/dist/services/api.d.ts +8 -1
- package/dist/services/api.js +27 -8
- package/dist/store/reducers/index.ts +3 -1
- package/dist/store/reducers/nodes.ts +148 -14
- package/dist/store/reducers/{clusterNodes.js → nodesList.js} +0 -41
- package/dist/store/reducers/settings.js +10 -4
- package/dist/store/reducers/storage.js +24 -13
- package/dist/store/reducers/tenant.js +5 -4
- package/dist/store/reducers/tooltip.ts +1 -1
- package/dist/store/reducers/topic.ts +52 -0
- package/dist/styles/mixins.scss +19 -11
- package/dist/types/api/common.ts +5 -0
- package/dist/types/api/compute.ts +1 -1
- package/dist/types/api/consumer.ts +12 -10
- package/dist/types/api/nodes.ts +2 -0
- package/dist/types/api/pdisk.ts +1 -0
- package/dist/types/api/schema.ts +3 -3
- package/dist/types/api/topic.ts +5 -4
- package/dist/types/api/vdisk.ts +2 -1
- package/dist/types/store/nodes.ts +56 -6
- package/dist/types/store/tooltip.ts +1 -1
- package/dist/types/store/topic.ts +21 -0
- package/dist/utils/constants.ts +5 -1
- package/dist/utils/i18n/i18n.ts +10 -2
- package/dist/utils/index.js +1 -1
- package/dist/utils/timeParsers/__test__/formatDuration.test.ts +50 -0
- package/dist/utils/timeParsers/__test__/protobuf.test.ts +74 -0
- package/dist/utils/timeParsers/formatDuration.ts +46 -0
- package/dist/utils/timeParsers/i18n/en.json +7 -0
- package/dist/utils/timeParsers/i18n/index.ts +11 -0
- package/dist/utils/timeParsers/i18n/ru.json +7 -0
- package/dist/utils/timeParsers/index.ts +2 -0
- package/dist/utils/timeParsers/protobuf.ts +36 -0
- package/package.json +1 -1
- package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +0 -48
- package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +0 -30
- package/dist/components/InternalLink/InternalLink.js +0 -23
- package/dist/containers/Nodes/Nodes.js +0 -213
- package/dist/containers/NodesViewer/NodesViewer.js +0 -163
- package/dist/containers/NodesViewer/NodesViewer.scss +0 -66
- package/dist/containers/Storage/Pdisk/Pdisk.tsx +0 -153
- package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +0 -41
- package/dist/containers/Storage/Vdisk/Vdisk.js +0 -275
- package/dist/containers/Storage/Vdisk/Vdisk.scss +0 -22
- package/dist/containers/Storage/Vdisk/__tests__/colors.tsx +0 -163
- package/dist/containers/Tenant/Diagnostics/Compute/Compute.js +0 -139
- package/dist/containers/Tenant/Diagnostics/Compute/Compute.scss +0 -14
|
@@ -23,8 +23,7 @@ import Describe from './Describe/Describe';
|
|
|
23
23
|
import HotKeys from './HotKeys/HotKeys';
|
|
24
24
|
//@ts-ignore
|
|
25
25
|
import {Heatmap} from '../../Heatmap';
|
|
26
|
-
|
|
27
|
-
import Compute from './Compute/Compute';
|
|
26
|
+
import {Nodes} from '../../Nodes';
|
|
28
27
|
//@ts-ignore
|
|
29
28
|
import {Tablets} from '../../Tablets';
|
|
30
29
|
import {Consumers} from './Consumers';
|
|
@@ -130,8 +129,8 @@ function Diagnostics(props: DiagnosticsProps) {
|
|
|
130
129
|
}
|
|
131
130
|
case GeneralPagesIds.nodes: {
|
|
132
131
|
return (
|
|
133
|
-
<
|
|
134
|
-
|
|
132
|
+
<Nodes
|
|
133
|
+
tenantPath={tenantNameString}
|
|
135
134
|
additionalNodesInfo={props.additionalNodesInfo}
|
|
136
135
|
/>
|
|
137
136
|
);
|
|
@@ -6,7 +6,7 @@ import DataTable, {Column, Settings, SortOrder} from '@yandex-cloud/react-data-t
|
|
|
6
6
|
import {Loader} from '@gravity-ui/uikit';
|
|
7
7
|
|
|
8
8
|
import {DateRange, DateRangeValues} from '../../../../components/DateRange';
|
|
9
|
-
import InternalLink from '../../../../components/InternalLink
|
|
9
|
+
import {InternalLink} from '../../../../components/InternalLink';
|
|
10
10
|
|
|
11
11
|
import HistoryContext from '../../../../contexts/HistoryContext';
|
|
12
12
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type {TEvDescribeSchemeResult} from '../../../../../types/api/schema';
|
|
2
|
+
|
|
3
|
+
import {formatObject, InfoViewer, InfoViewerItem} from '../../../../../components/InfoViewer';
|
|
4
|
+
import {
|
|
5
|
+
formatCdcStreamItem,
|
|
6
|
+
formatCommonItem,
|
|
7
|
+
} from '../../../../../components/InfoViewer/formatters';
|
|
8
|
+
|
|
9
|
+
import {useTypedSelector} from '../../../../../utils/hooks';
|
|
10
|
+
import {selectSchemaData} from '../../../../../store/reducers/schema';
|
|
11
|
+
|
|
12
|
+
import {getEntityName} from '../../../utils';
|
|
13
|
+
|
|
14
|
+
import {TopicStats} from '../TopicStats';
|
|
15
|
+
|
|
16
|
+
import {prepareTopicSchemaInfo} from '../utils';
|
|
17
|
+
|
|
18
|
+
const prepareChangefeedInfo = (
|
|
19
|
+
changefeedData?: TEvDescribeSchemeResult,
|
|
20
|
+
topicData?: TEvDescribeSchemeResult,
|
|
21
|
+
): Array<InfoViewerItem> => {
|
|
22
|
+
if (!changefeedData && !topicData) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const streamDescription = changefeedData?.PathDescription?.CdcStreamDescription;
|
|
27
|
+
|
|
28
|
+
const {Mode, Format} = streamDescription || {};
|
|
29
|
+
|
|
30
|
+
const created = formatCommonItem(
|
|
31
|
+
'CreateStep',
|
|
32
|
+
changefeedData?.PathDescription?.Self?.CreateStep,
|
|
33
|
+
);
|
|
34
|
+
const changefeedInfo = formatObject(formatCdcStreamItem, {
|
|
35
|
+
Mode,
|
|
36
|
+
Format,
|
|
37
|
+
});
|
|
38
|
+
const topicInfo = prepareTopicSchemaInfo(topicData);
|
|
39
|
+
|
|
40
|
+
return [created, ...changefeedInfo, ...topicInfo];
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
interface ChangefeedProps {
|
|
44
|
+
data?: TEvDescribeSchemeResult;
|
|
45
|
+
childrenPaths?: string[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Displays overview for CDCStream EPathType */
|
|
49
|
+
export const ChangefeedInfo = ({data, childrenPaths}: ChangefeedProps) => {
|
|
50
|
+
const entityName = getEntityName(data?.PathDescription);
|
|
51
|
+
|
|
52
|
+
const {error: schemaError} = useTypedSelector((state) => state.schema);
|
|
53
|
+
const pqGroupData = useTypedSelector((state) => selectSchemaData(state, childrenPaths?.[0]));
|
|
54
|
+
|
|
55
|
+
if (schemaError) {
|
|
56
|
+
return <div className="error">{schemaError.statusText}</div>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!data || !pqGroupData) {
|
|
60
|
+
return <div className="error">No {entityName} data</div>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div>
|
|
65
|
+
<InfoViewer title={entityName} info={prepareChangefeedInfo(data, pqGroupData)} />
|
|
66
|
+
<TopicStats />
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ChangefeedInfo';
|
|
@@ -6,20 +6,17 @@ import {Loader} from '@gravity-ui/uikit';
|
|
|
6
6
|
|
|
7
7
|
//@ts-ignore
|
|
8
8
|
import SchemaInfoViewer from '../../Schema/SchemaInfoViewer/SchemaInfoViewer';
|
|
9
|
-
import {
|
|
10
|
-
CDCStreamInfo,
|
|
11
|
-
TableIndexInfo,
|
|
12
|
-
PersQueueGroupInfo,
|
|
13
|
-
} from '../../../../components/InfoViewer/schemaInfo';
|
|
9
|
+
import {TableIndexInfo} from '../../../../components/InfoViewer/schemaInfo';
|
|
14
10
|
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from '../../../../types/api/schema';
|
|
11
|
+
import {TopicInfo} from './TopicInfo';
|
|
12
|
+
import {ChangefeedInfo} from './ChangefeedInfo';
|
|
13
|
+
|
|
14
|
+
import {EPathType, TEvDescribeSchemeResult} from '../../../../types/api/schema';
|
|
19
15
|
import {
|
|
20
16
|
isEntityWithMergedImplementation,
|
|
21
17
|
isColumnEntityType,
|
|
22
18
|
isTableType,
|
|
19
|
+
isPathTypeWithTopic,
|
|
23
20
|
} from '../../utils/schema';
|
|
24
21
|
//@ts-ignore
|
|
25
22
|
import {
|
|
@@ -28,6 +25,7 @@ import {
|
|
|
28
25
|
resetLoadingState,
|
|
29
26
|
selectSchemaMergedChildrenPaths,
|
|
30
27
|
} from '../../../../store/reducers/schema';
|
|
28
|
+
import {getTopic} from '../../../../store/reducers/topic';
|
|
31
29
|
//@ts-ignore
|
|
32
30
|
import {
|
|
33
31
|
getOlapStats,
|
|
@@ -122,6 +120,10 @@ function Overview({type, tenantName, className}: OverviewProps) {
|
|
|
122
120
|
}
|
|
123
121
|
dispatch(getOlapStats({path: schemaPath}));
|
|
124
122
|
}
|
|
123
|
+
|
|
124
|
+
if (isPathTypeWithTopic(type)) {
|
|
125
|
+
dispatch(getTopic(currentSchemaPath));
|
|
126
|
+
}
|
|
125
127
|
},
|
|
126
128
|
[
|
|
127
129
|
tenantName,
|
|
@@ -163,9 +165,9 @@ function Overview({type, tenantName, className}: OverviewProps) {
|
|
|
163
165
|
[EPathType.EPathTypeColumnStore]: undefined,
|
|
164
166
|
[EPathType.EPathTypeColumnTable]: undefined,
|
|
165
167
|
[EPathType.EPathTypeCdcStream]: () => (
|
|
166
|
-
<
|
|
168
|
+
<ChangefeedInfo data={schemaData} childrenPaths={mergedChildrenPaths} />
|
|
167
169
|
),
|
|
168
|
-
[EPathType.EPathTypePersQueueGroup]: () => <
|
|
170
|
+
[EPathType.EPathTypePersQueueGroup]: () => <TopicInfo data={schemaData} />,
|
|
169
171
|
};
|
|
170
172
|
|
|
171
173
|
return (
|
|
@@ -175,11 +177,11 @@ function Overview({type, tenantName, className}: OverviewProps) {
|
|
|
175
177
|
);
|
|
176
178
|
};
|
|
177
179
|
|
|
178
|
-
|
|
179
|
-
renderLoader()
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
)
|
|
180
|
+
if ((loading && !wasLoaded) || (isEntityWithMergedImpl && !mergedChildrenPaths)) {
|
|
181
|
+
return renderLoader();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return <div className={className}>{renderContent()}</div>;
|
|
183
185
|
}
|
|
184
186
|
|
|
185
187
|
export default Overview;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type {TEvDescribeSchemeResult} from '../../../../../types/api/schema';
|
|
2
|
+
|
|
3
|
+
import {InfoViewer} from '../../../../../components/InfoViewer';
|
|
4
|
+
|
|
5
|
+
import {useTypedSelector} from '../../../../../utils/hooks';
|
|
6
|
+
|
|
7
|
+
import {getEntityName} from '../../../utils';
|
|
8
|
+
|
|
9
|
+
import {prepareTopicSchemaInfo} from '../utils';
|
|
10
|
+
|
|
11
|
+
import {TopicStats} from '../TopicStats';
|
|
12
|
+
|
|
13
|
+
interface TopicInfoProps {
|
|
14
|
+
data?: TEvDescribeSchemeResult;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Displays overview for PersQueueGroup EPathType */
|
|
18
|
+
export const TopicInfo = ({data}: TopicInfoProps) => {
|
|
19
|
+
const entityName = getEntityName(data?.PathDescription);
|
|
20
|
+
|
|
21
|
+
const {error: schemaError} = useTypedSelector((state) => state.schema);
|
|
22
|
+
|
|
23
|
+
if (schemaError) {
|
|
24
|
+
return <div className="error">{schemaError.statusText}</div>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!data) {
|
|
28
|
+
return <div className="error">No {entityName} data</div>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div>
|
|
33
|
+
<InfoViewer title={entityName} info={prepareTopicSchemaInfo(data)} />
|
|
34
|
+
<TopicStats />
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TopicInfo';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
@import '../../../../../styles/mixins.scss';
|
|
2
|
+
|
|
3
|
+
.ydb-overview-topic-stats {
|
|
4
|
+
&__title {
|
|
5
|
+
@include info-viewer-title();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.ydb-loader {
|
|
9
|
+
margin-top: 50px;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.ydb-bars {
|
|
13
|
+
margin-top: -5px;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&__info {
|
|
17
|
+
.info-viewer__label-text_multiline {
|
|
18
|
+
max-width: 150px;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
&__bytes-written {
|
|
23
|
+
margin-top: 7px;
|
|
24
|
+
padding-left: 20px;
|
|
25
|
+
|
|
26
|
+
.info-viewer__label {
|
|
27
|
+
min-width: 180px;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import cn from 'bem-cn-lite';
|
|
2
|
+
import {isEmpty} from 'lodash/fp';
|
|
3
|
+
|
|
4
|
+
import type {DescribeTopicResult} from '../../../../../types/api/topic';
|
|
5
|
+
|
|
6
|
+
import {Loader} from '../../../../../components/Loader';
|
|
7
|
+
import {InfoViewerItem, formatObject, InfoViewer} from '../../../../../components/InfoViewer';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
prepareBytesWritten,
|
|
11
|
+
formatTopicStats,
|
|
12
|
+
} from '../../../../../components/InfoViewer/formatters';
|
|
13
|
+
|
|
14
|
+
import {useTypedSelector} from '../../../../../utils/hooks';
|
|
15
|
+
import {formatBps} from '../../../../../utils';
|
|
16
|
+
|
|
17
|
+
import i18n from './i18n';
|
|
18
|
+
|
|
19
|
+
import './TopicStats.scss';
|
|
20
|
+
|
|
21
|
+
const b = cn('ydb-overview-topic-stats');
|
|
22
|
+
|
|
23
|
+
const prepareTopicInfo = (data: DescribeTopicResult): Array<InfoViewerItem> => {
|
|
24
|
+
return [
|
|
25
|
+
...formatObject(formatTopicStats, {
|
|
26
|
+
...data.topic_stats,
|
|
27
|
+
}),
|
|
28
|
+
];
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const prepareBytesWrittenInfo = (data: DescribeTopicResult): Array<InfoViewerItem> => {
|
|
32
|
+
const preparedBytes = prepareBytesWritten(data?.topic_stats?.bytes_written);
|
|
33
|
+
|
|
34
|
+
return [
|
|
35
|
+
{
|
|
36
|
+
label: 'per minute',
|
|
37
|
+
value: formatBps(preparedBytes.per_minute),
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
label: 'per hour',
|
|
41
|
+
value: formatBps(preparedBytes.per_hour),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
label: 'per day',
|
|
45
|
+
value: formatBps(preparedBytes.per_day),
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const TopicStats = () => {
|
|
51
|
+
const {data, error, loading, wasLoaded} = useTypedSelector((state) => state.topic);
|
|
52
|
+
|
|
53
|
+
if (loading && !wasLoaded) {
|
|
54
|
+
return (
|
|
55
|
+
<div className={b()}>
|
|
56
|
+
<Loader size="s" />
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// There are several backed versions with different behaviour
|
|
62
|
+
// Possible returns on older versions:
|
|
63
|
+
// 1. Error when trying to access endpoint
|
|
64
|
+
// 2. No data
|
|
65
|
+
// 3. HTML page of Internal Viewer with an error
|
|
66
|
+
// 4. Data with no topic stats
|
|
67
|
+
// 5. Topic Stats as an empty object
|
|
68
|
+
if (
|
|
69
|
+
error ||
|
|
70
|
+
!data ||
|
|
71
|
+
typeof data !== 'object' ||
|
|
72
|
+
!data.topic_stats ||
|
|
73
|
+
isEmpty(data.topic_stats)
|
|
74
|
+
) {
|
|
75
|
+
return (
|
|
76
|
+
<div className={b()}>
|
|
77
|
+
<div className={b('title')}>Stats</div>
|
|
78
|
+
<div className="error">{i18n('notSupportedVersion')}</div>
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<div className={b()}>
|
|
85
|
+
<div className={b('title')}>Stats</div>
|
|
86
|
+
<div className={b('info')}>
|
|
87
|
+
<InfoViewer info={prepareTopicInfo(data)} multilineLabels />
|
|
88
|
+
</div>
|
|
89
|
+
<div className={b('bytes-written')}>
|
|
90
|
+
<InfoViewer info={prepareBytesWrittenInfo(data)} />
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
@@ -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-overview-topic-stats';
|
|
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 './TopicStats';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './prepareTopicSchemaInfo';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TEvDescribeSchemeResult,
|
|
3
|
+
TPersQueueGroupDescription,
|
|
4
|
+
TPQTabletConfig,
|
|
5
|
+
TPQPartitionConfig,
|
|
6
|
+
} from '../../../../../types/api/schema';
|
|
7
|
+
|
|
8
|
+
import {formatObject, InfoViewerItem} from '../../../../../components/InfoViewer';
|
|
9
|
+
import {
|
|
10
|
+
formatPQGroupItem,
|
|
11
|
+
formatPQPartitionConfig,
|
|
12
|
+
formatPQTabletConfig,
|
|
13
|
+
} from '../../../../../components/InfoViewer/formatters';
|
|
14
|
+
|
|
15
|
+
export const prepareTopicSchemaInfo = (data?: TEvDescribeSchemeResult): Array<InfoViewerItem> => {
|
|
16
|
+
const pqGroupData = data?.PathDescription?.PersQueueGroup;
|
|
17
|
+
|
|
18
|
+
if (!pqGroupData) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const {Partitions = [], PQTabletConfig = {PartitionConfig: {LifetimeSeconds: 0}}} = pqGroupData;
|
|
23
|
+
|
|
24
|
+
const {Codecs, MeteringMode} = pqGroupData?.PQTabletConfig;
|
|
25
|
+
const {WriteSpeedInBytesPerSecond, StorageLimitBytes} =
|
|
26
|
+
pqGroupData?.PQTabletConfig?.PartitionConfig;
|
|
27
|
+
|
|
28
|
+
const pqGeneralInfo = formatObject<TPersQueueGroupDescription>(formatPQGroupItem, {
|
|
29
|
+
Partitions,
|
|
30
|
+
PQTabletConfig,
|
|
31
|
+
});
|
|
32
|
+
const pqPartitionInfo = formatObject<TPQPartitionConfig>(formatPQPartitionConfig, {
|
|
33
|
+
StorageLimitBytes,
|
|
34
|
+
WriteSpeedInBytesPerSecond,
|
|
35
|
+
});
|
|
36
|
+
const pqTabletInfo = formatObject<TPQTabletConfig>(formatPQTabletConfig, {
|
|
37
|
+
Codecs,
|
|
38
|
+
MeteringMode,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return [...pqGeneralInfo, ...pqPartitionInfo, ...pqTabletInfo];
|
|
42
|
+
};
|
|
@@ -217,3 +217,22 @@ const pathTypeToChildless: Record<EPathType, boolean> = {
|
|
|
217
217
|
|
|
218
218
|
export const isChildlessPathType = (type?: EPathType, subType?: EPathSubType) =>
|
|
219
219
|
((subType && pathSubTypeToChildless[subType]) || (type && pathTypeToChildless[type])) ?? false;
|
|
220
|
+
|
|
221
|
+
// ====================
|
|
222
|
+
|
|
223
|
+
const mapPathTypeToIsWithTopic: Record<EPathType, boolean> = {
|
|
224
|
+
[EPathType.EPathTypeCdcStream]: true,
|
|
225
|
+
[EPathType.EPathTypePersQueueGroup]: true,
|
|
226
|
+
|
|
227
|
+
[EPathType.EPathTypeInvalid]: false,
|
|
228
|
+
[EPathType.EPathTypeColumnStore]: false,
|
|
229
|
+
[EPathType.EPathTypeColumnTable]: false,
|
|
230
|
+
[EPathType.EPathTypeDir]: false,
|
|
231
|
+
[EPathType.EPathTypeTable]: false,
|
|
232
|
+
[EPathType.EPathTypeSubDomain]: false,
|
|
233
|
+
[EPathType.EPathTypeTableIndex]: false,
|
|
234
|
+
[EPathType.EPathTypeExtSubDomain]: false,
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
export const isPathTypeWithTopic = (type?: EPathType) =>
|
|
238
|
+
(type && mapPathTypeToIsWithTopic[type]) ?? false;
|
|
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import cn from 'bem-cn-lite';
|
|
4
4
|
import {connect} from 'react-redux';
|
|
5
5
|
import _ from 'lodash';
|
|
6
|
+
import {escapeRegExp} from 'lodash/fp';
|
|
6
7
|
|
|
7
8
|
import DataTable from '@yandex-cloud/react-data-table';
|
|
8
9
|
import {Loader, TextInput, Button} from '@gravity-ui/uikit';
|
|
@@ -125,7 +126,7 @@ class Tenants extends React.Component {
|
|
|
125
126
|
} = this.props;
|
|
126
127
|
|
|
127
128
|
const filteredTenantsBySearch = tenants.filter((item) => {
|
|
128
|
-
const re = new RegExp(searchQuery, 'i');
|
|
129
|
+
const re = new RegExp(escapeRegExp(searchQuery), 'i');
|
|
129
130
|
return re.test(item.Name) || re.test(this.getControlPlaneValue(item));
|
|
130
131
|
});
|
|
131
132
|
const filteredTenants = Tenants.filterTenants(filteredTenantsBySearch, filter);
|
|
@@ -6,7 +6,11 @@ import {Settings} from '@gravity-ui/navigation';
|
|
|
6
6
|
import favoriteFilledIcon from '../../assets/icons/star.svg';
|
|
7
7
|
import flaskIcon from '../../assets/icons/flask.svg';
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
INVERTED_DISKS_KEY,
|
|
11
|
+
THEME_KEY,
|
|
12
|
+
USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
|
|
13
|
+
} from '../../utils/constants';
|
|
10
14
|
|
|
11
15
|
import {setSettingValue} from '../../store/reducers/settings';
|
|
12
16
|
|
|
@@ -25,6 +29,10 @@ function UserSettings(props: any) {
|
|
|
25
29
|
props.setSettingValue(INVERTED_DISKS_KEY, String(value));
|
|
26
30
|
};
|
|
27
31
|
|
|
32
|
+
const _onNodesEndpointChangeHandler = (value: boolean) => {
|
|
33
|
+
props.setSettingValue(USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, String(value));
|
|
34
|
+
};
|
|
35
|
+
|
|
28
36
|
return (
|
|
29
37
|
<Settings>
|
|
30
38
|
<Settings.Page
|
|
@@ -42,11 +50,7 @@ function UserSettings(props: any) {
|
|
|
42
50
|
</Settings.Item>
|
|
43
51
|
</Settings.Section>
|
|
44
52
|
</Settings.Page>
|
|
45
|
-
<Settings.Page
|
|
46
|
-
id="experiments"
|
|
47
|
-
title="Experiments"
|
|
48
|
-
icon={{data: flaskIcon}}
|
|
49
|
-
>
|
|
53
|
+
<Settings.Page id="experiments" title="Experiments" icon={{data: flaskIcon}}>
|
|
50
54
|
<Settings.Section title="Experiments">
|
|
51
55
|
<Settings.Item title="Inverted disks space indicators">
|
|
52
56
|
<Switch
|
|
@@ -54,6 +58,12 @@ function UserSettings(props: any) {
|
|
|
54
58
|
onUpdate={_onInvertedDisksChangeHandler}
|
|
55
59
|
/>
|
|
56
60
|
</Settings.Item>
|
|
61
|
+
<Settings.Item title="Use /viewer/json/nodes for Nodes Tab in diagnostics">
|
|
62
|
+
<Switch
|
|
63
|
+
checked={props.useNodesEndpointInDiagnostics}
|
|
64
|
+
onUpdate={_onNodesEndpointChangeHandler}
|
|
65
|
+
/>
|
|
66
|
+
</Settings.Item>
|
|
57
67
|
</Settings.Section>
|
|
58
68
|
</Settings.Page>
|
|
59
69
|
</Settings>
|
|
@@ -61,14 +71,12 @@ function UserSettings(props: any) {
|
|
|
61
71
|
}
|
|
62
72
|
|
|
63
73
|
const mapStateToProps = (state: any) => {
|
|
64
|
-
const {
|
|
65
|
-
theme,
|
|
66
|
-
invertedDisks,
|
|
67
|
-
} = state.settings.userSettings;
|
|
74
|
+
const {theme, invertedDisks, useNodesEndpointInDiagnostics} = state.settings.userSettings;
|
|
68
75
|
|
|
69
76
|
return {
|
|
70
77
|
theme,
|
|
71
78
|
invertedDisks: JSON.parse(invertedDisks),
|
|
79
|
+
useNodesEndpointInDiagnostics: JSON.parse(useNodesEndpointInDiagnostics),
|
|
72
80
|
};
|
|
73
81
|
};
|
|
74
82
|
|
package/dist/services/api.d.ts
CHANGED
|
@@ -17,10 +17,14 @@ interface Window {
|
|
|
17
17
|
tenant: string;
|
|
18
18
|
filter: string;
|
|
19
19
|
nodeId: string;
|
|
20
|
-
type: 'Groups' | 'Nodes';
|
|
21
20
|
},
|
|
22
21
|
axiosOptions?: AxiosOptions,
|
|
23
22
|
) => Promise<import('../types/api/storage').TStorageInfo>;
|
|
23
|
+
getNodes: (
|
|
24
|
+
params: import('../types/store/nodes').INodesApiRequestParams,
|
|
25
|
+
axiosOptions?: AxiosOptions,
|
|
26
|
+
) => Promise<import('../types/api/nodes').TNodesInfo>;
|
|
27
|
+
getCompute: (path: string) => Promise<import('../types/api/compute').TComputeInfo>;
|
|
24
28
|
sendQuery: <
|
|
25
29
|
Action extends import('../types/api/query').Actions,
|
|
26
30
|
Schema extends import('../types/api/query').Schemas = undefined,
|
|
@@ -55,6 +59,9 @@ interface Window {
|
|
|
55
59
|
getHeatmapData: (params: {
|
|
56
60
|
path: string;
|
|
57
61
|
}) => Promise<import('../types/api/schema').TEvDescribeSchemeResult>;
|
|
62
|
+
getTopic: (params: {
|
|
63
|
+
path?: string;
|
|
64
|
+
}) => Promise<import('../types/api/topic').DescribeTopicResult>;
|
|
58
65
|
[method: string]: Function;
|
|
59
66
|
};
|
|
60
67
|
}
|
package/dist/services/api.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import AxiosWrapper from '@gravity-ui/axios-wrapper';
|
|
2
2
|
|
|
3
3
|
import {backend as BACKEND} from '../store';
|
|
4
|
-
import {StorageTypes} from '../store/reducers/storage';
|
|
5
4
|
|
|
6
5
|
const config = {withCredentials: !window.custom_backend};
|
|
7
6
|
|
|
@@ -14,9 +13,6 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
|
14
13
|
getClusterInfo() {
|
|
15
14
|
return this.get(this.getPath('/viewer/json/cluster'), {tablets: true});
|
|
16
15
|
}
|
|
17
|
-
getNodes(path) {
|
|
18
|
-
return this.get(this.getPath('/viewer/json/compute?enums=true'), {path});
|
|
19
|
-
}
|
|
20
16
|
getNodeInfo(id) {
|
|
21
17
|
return this.get(this.getPath('/viewer/json/sysinfo?enums=true'), {
|
|
22
18
|
node_id: id,
|
|
@@ -35,11 +31,27 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
|
35
31
|
storage: true,
|
|
36
32
|
});
|
|
37
33
|
}
|
|
38
|
-
|
|
34
|
+
getNodes({tenant, filter, storage, type = 'any', tablets = true}, {concurrentId} = {}) {
|
|
35
|
+
return this.get(
|
|
36
|
+
this.getPath('/viewer/json/nodes?enums=true'),
|
|
37
|
+
{
|
|
38
|
+
tenant,
|
|
39
|
+
with: filter,
|
|
40
|
+
storage,
|
|
41
|
+
type,
|
|
42
|
+
tablets,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
concurrentId,
|
|
46
|
+
},
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
getCompute(path) {
|
|
50
|
+
return this.get(this.getPath('/viewer/json/compute?enums=true'), {path});
|
|
51
|
+
}
|
|
52
|
+
getStorageInfo({tenant, filter, nodeId}, {concurrentId} = {}) {
|
|
39
53
|
return this.get(
|
|
40
|
-
this.getPath(
|
|
41
|
-
`/viewer/json/${type === StorageTypes.nodes ? 'nodes' : 'storage'}?enums=true`,
|
|
42
|
-
),
|
|
54
|
+
this.getPath(`/viewer/json/storage?enums=true`),
|
|
43
55
|
{
|
|
44
56
|
tenant,
|
|
45
57
|
node_id: nodeId,
|
|
@@ -129,6 +141,13 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
|
129
141
|
path,
|
|
130
142
|
});
|
|
131
143
|
}
|
|
144
|
+
getTopic({path}) {
|
|
145
|
+
return this.get(this.getPath('/viewer/json/describe_topic'), {
|
|
146
|
+
enums: true,
|
|
147
|
+
include_stats: true,
|
|
148
|
+
path,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
132
151
|
getPoolInfo(poolName) {
|
|
133
152
|
return this.get(this.getPath('/viewer/json/storage'), {
|
|
134
153
|
pool: poolName,
|
|
@@ -17,12 +17,13 @@ import network from './network';
|
|
|
17
17
|
import pool from './pool';
|
|
18
18
|
import tenants from './tenants';
|
|
19
19
|
import tablet from './tablet';
|
|
20
|
+
import topic from './topic';
|
|
20
21
|
import executeQuery from './executeQuery';
|
|
21
22
|
import explainQuery from './explainQuery';
|
|
22
23
|
import tabletsFilters from './tabletsFilters';
|
|
23
24
|
import settings from './settings';
|
|
24
25
|
import preview from './preview';
|
|
25
|
-
import nodesList from './
|
|
26
|
+
import nodesList from './nodesList';
|
|
26
27
|
import describe from './describe';
|
|
27
28
|
import schemaAcl from './schemaAcl';
|
|
28
29
|
import executeTopQueries from './executeTopQueries';
|
|
@@ -55,6 +56,7 @@ export const rootReducer = {
|
|
|
55
56
|
pool,
|
|
56
57
|
tenants,
|
|
57
58
|
tablet,
|
|
59
|
+
topic,
|
|
58
60
|
executeQuery,
|
|
59
61
|
explainQuery,
|
|
60
62
|
tabletsFilters,
|