ydb-embedded-ui 3.2.3 → 3.3.1

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.
Files changed (117) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/InfoViewer/InfoViewer.scss +10 -0
  3. package/dist/components/InfoViewer/InfoViewer.tsx +12 -2
  4. package/dist/components/InfoViewer/formatters/cdcStream.ts +10 -0
  5. package/dist/components/InfoViewer/formatters/index.ts +3 -0
  6. package/dist/components/InfoViewer/formatters/pqGroup.ts +51 -0
  7. package/dist/components/InfoViewer/formatters/schema.ts +1 -29
  8. package/dist/components/InfoViewer/formatters/topicStats.tsx +50 -0
  9. package/dist/components/InfoViewer/schemaInfo/index.ts +0 -2
  10. package/dist/components/InfoViewer/utils.ts +15 -0
  11. package/dist/components/InternalLink/InternalLink.tsx +17 -0
  12. package/dist/components/InternalLink/index.ts +1 -0
  13. package/dist/components/Tablet/Tablet.js +1 -1
  14. package/dist/components/TabletsStatistic/TabletsStatistic.tsx +1 -1
  15. package/dist/components/VerticalBars/VerticalBars.scss +15 -0
  16. package/dist/components/VerticalBars/VerticalBars.tsx +38 -0
  17. package/dist/components/VerticalBars/index.ts +1 -0
  18. package/dist/containers/App/App.js +0 -11
  19. package/dist/containers/App/App.scss +0 -1
  20. package/dist/containers/Cluster/Cluster.tsx +2 -2
  21. package/dist/containers/Nodes/Nodes.scss +5 -1
  22. package/dist/containers/Nodes/Nodes.tsx +196 -0
  23. package/dist/containers/{App → Nodes}/NodesTable.scss +2 -2
  24. package/dist/{utils/getNodesColumns.js → containers/Nodes/getNodesColumns.tsx} +60 -35
  25. package/dist/containers/Nodes/i18n/en.json +3 -0
  26. package/dist/containers/Nodes/i18n/index.ts +11 -0
  27. package/dist/containers/Nodes/i18n/ru.json +3 -0
  28. package/dist/containers/Nodes/index.ts +1 -0
  29. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +14 -20
  30. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +32 -16
  31. package/dist/containers/Storage/DiskStateProgressBar/index.ts +1 -0
  32. package/dist/containers/Storage/{Pdisk/Pdisk.scss → PDisk/PDisk.scss} +15 -4
  33. package/dist/containers/Storage/PDisk/PDisk.tsx +145 -0
  34. package/dist/containers/Storage/PDisk/__tests__/colors.tsx +37 -0
  35. package/dist/containers/Storage/PDisk/index.ts +1 -0
  36. package/dist/containers/Storage/PDiskPopup/PDiskPopup.scss +3 -0
  37. package/dist/containers/Storage/PDiskPopup/PDiskPopup.tsx +82 -0
  38. package/dist/containers/Storage/PDiskPopup/index.ts +1 -0
  39. package/dist/containers/Storage/Storage.js +1 -1
  40. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +10 -10
  41. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +1 -0
  42. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +7 -4
  43. package/dist/containers/Storage/VDisk/VDisk.scss +7 -0
  44. package/dist/containers/Storage/VDisk/VDisk.tsx +148 -0
  45. package/dist/containers/Storage/VDisk/__tests__/colors.tsx +209 -0
  46. package/dist/containers/Storage/VDisk/index.ts +1 -0
  47. package/dist/containers/Storage/VDiskPopup/VDiskPopup.scss +14 -0
  48. package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +134 -0
  49. package/dist/containers/Storage/VDiskPopup/index.ts +1 -0
  50. package/dist/containers/Storage/utils/constants.ts +2 -9
  51. package/dist/containers/TabletsFilters/TabletsFilters.js +10 -6
  52. package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +2 -2
  53. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -4
  54. package/dist/containers/Tenant/Diagnostics/OverloadedShards/OverloadedShards.tsx +1 -1
  55. package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/ChangefeedInfo.tsx +69 -0
  56. package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/index.ts +1 -0
  57. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +18 -16
  58. package/dist/containers/Tenant/Diagnostics/Overview/TopicInfo/TopicInfo.tsx +37 -0
  59. package/dist/containers/Tenant/Diagnostics/Overview/TopicInfo/index.ts +1 -0
  60. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.scss +30 -0
  61. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +94 -0
  62. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/en.json +3 -0
  63. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/index.ts +11 -0
  64. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/ru.json +3 -0
  65. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/index.ts +1 -0
  66. package/dist/containers/Tenant/Diagnostics/Overview/utils/index.ts +1 -0
  67. package/dist/containers/Tenant/Diagnostics/Overview/utils/prepareTopicSchemaInfo.ts +42 -0
  68. package/dist/containers/Tenant/utils/schema.ts +19 -0
  69. package/dist/containers/UserSettings/UserSettings.scss +9 -0
  70. package/dist/containers/UserSettings/UserSettings.tsx +41 -11
  71. package/dist/services/api.d.ts +8 -1
  72. package/dist/services/api.js +27 -8
  73. package/dist/store/reducers/index.ts +3 -1
  74. package/dist/store/reducers/nodes.ts +148 -14
  75. package/dist/store/reducers/{clusterNodes.js → nodesList.js} +0 -41
  76. package/dist/store/reducers/settings.js +10 -4
  77. package/dist/store/reducers/storage.js +24 -13
  78. package/dist/store/reducers/tenant.js +5 -4
  79. package/dist/store/reducers/tooltip.ts +1 -1
  80. package/dist/store/reducers/topic.ts +52 -0
  81. package/dist/styles/mixins.scss +19 -11
  82. package/dist/types/api/common.ts +5 -0
  83. package/dist/types/api/compute.ts +1 -1
  84. package/dist/types/api/consumer.ts +12 -10
  85. package/dist/types/api/nodes.ts +2 -0
  86. package/dist/types/api/pdisk.ts +1 -0
  87. package/dist/types/api/schema.ts +3 -3
  88. package/dist/types/api/topic.ts +5 -4
  89. package/dist/types/api/vdisk.ts +2 -1
  90. package/dist/types/store/nodes.ts +56 -6
  91. package/dist/types/store/tooltip.ts +1 -1
  92. package/dist/types/store/topic.ts +21 -0
  93. package/dist/utils/constants.ts +5 -1
  94. package/dist/utils/i18n/i18n.ts +10 -2
  95. package/dist/utils/index.js +1 -1
  96. package/dist/utils/timeParsers/__test__/formatDuration.test.ts +50 -0
  97. package/dist/utils/timeParsers/__test__/protobuf.test.ts +74 -0
  98. package/dist/utils/timeParsers/formatDuration.ts +46 -0
  99. package/dist/utils/timeParsers/i18n/en.json +7 -0
  100. package/dist/utils/timeParsers/i18n/index.ts +11 -0
  101. package/dist/utils/timeParsers/i18n/ru.json +7 -0
  102. package/dist/utils/timeParsers/index.ts +2 -0
  103. package/dist/utils/timeParsers/protobuf.ts +36 -0
  104. package/package.json +1 -1
  105. package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +0 -48
  106. package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +0 -30
  107. package/dist/components/InternalLink/InternalLink.js +0 -23
  108. package/dist/containers/Nodes/Nodes.js +0 -214
  109. package/dist/containers/NodesViewer/NodesViewer.js +0 -163
  110. package/dist/containers/NodesViewer/NodesViewer.scss +0 -66
  111. package/dist/containers/Storage/Pdisk/Pdisk.tsx +0 -153
  112. package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +0 -41
  113. package/dist/containers/Storage/Vdisk/Vdisk.js +0 -275
  114. package/dist/containers/Storage/Vdisk/Vdisk.scss +0 -22
  115. package/dist/containers/Storage/Vdisk/__tests__/colors.tsx +0 -163
  116. package/dist/containers/Tenant/Diagnostics/Compute/Compute.js +0 -139
  117. 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
- //@ts-ignore
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
- <Compute
134
- tenantName={tenantNameString}
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/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
- EPathType,
17
- TEvDescribeSchemeResult,
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
- <CDCStreamInfo data={schemaData} childrenPaths={mergedChildrenPaths} />
168
+ <ChangefeedInfo data={schemaData} childrenPaths={mergedChildrenPaths} />
167
169
  ),
168
- [EPathType.EPathTypePersQueueGroup]: () => <PersQueueGroupInfo data={schemaData} />,
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
- return (loading && !wasLoaded) || (isEntityWithMergedImpl && !mergedChildrenPaths) ? (
179
- renderLoader()
180
- ) : (
181
- <div className={className}>{renderContent()}</div>
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,3 @@
1
+ {
2
+ "notSupportedVersion": "Topic stats are not supported in the current cluster version. Update cluster version to see topic stats"
3
+ }
@@ -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,3 @@
1
+ {
2
+ "notSupportedVersion": "Статистика топиков не поддерживается в текущей версии. Обновите кластер до более новой версии, чтобы увидеть статистику топиков"
3
+ }
@@ -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;
@@ -0,0 +1,9 @@
1
+ .ydb-user-settings {
2
+ &__item-with-popup {
3
+ max-width: 180px;
4
+ }
5
+
6
+ &__popup {
7
+ max-width: 370px;
8
+ }
9
+ }
@@ -1,15 +1,25 @@
1
+ import {ReactNode} from 'react';
1
2
  import {connect} from 'react-redux';
3
+ import cn from 'bem-cn-lite';
2
4
 
3
- import {RadioButton, Switch} from '@gravity-ui/uikit';
5
+ import {RadioButton, Switch, HelpPopover} from '@gravity-ui/uikit';
4
6
  import {Settings} from '@gravity-ui/navigation';
5
7
 
6
8
  import favoriteFilledIcon from '../../assets/icons/star.svg';
7
9
  import flaskIcon from '../../assets/icons/flask.svg';
8
10
 
9
- import {INVERTED_DISKS_KEY, THEME_KEY} from '../../utils/constants';
11
+ import {
12
+ INVERTED_DISKS_KEY,
13
+ THEME_KEY,
14
+ USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
15
+ } from '../../utils/constants';
10
16
 
11
17
  import {setSettingValue} from '../../store/reducers/settings';
12
18
 
19
+ import './UserSettings.scss';
20
+
21
+ const b = cn('ydb-user-settings');
22
+
13
23
  enum Theme {
14
24
  light = 'light',
15
25
  dark = 'dark',
@@ -25,6 +35,23 @@ function UserSettings(props: any) {
25
35
  props.setSettingValue(INVERTED_DISKS_KEY, String(value));
26
36
  };
27
37
 
38
+ const _onNodesEndpointChangeHandler = (value: boolean) => {
39
+ props.setSettingValue(USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, String(value));
40
+ };
41
+
42
+ const renderBreakNodesSettingsItem = (title: ReactNode) => {
43
+ return (
44
+ <div className={b('item-with-popup')}>
45
+ {title}
46
+ <HelpPopover
47
+ content="Use /viewer/json/nodes endpoint for Nodes Tab in diagnostics. It returns incorrect data on older versions"
48
+ contentClassName={b('popup')}
49
+ hasArrow={true}
50
+ />
51
+ </div>
52
+ );
53
+ };
54
+
28
55
  return (
29
56
  <Settings>
30
57
  <Settings.Page
@@ -42,11 +69,7 @@ function UserSettings(props: any) {
42
69
  </Settings.Item>
43
70
  </Settings.Section>
44
71
  </Settings.Page>
45
- <Settings.Page
46
- id="experiments"
47
- title="Experiments"
48
- icon={{data: flaskIcon}}
49
- >
72
+ <Settings.Page id="experiments" title="Experiments" icon={{data: flaskIcon}}>
50
73
  <Settings.Section title="Experiments">
51
74
  <Settings.Item title="Inverted disks space indicators">
52
75
  <Switch
@@ -54,6 +77,15 @@ function UserSettings(props: any) {
54
77
  onUpdate={_onInvertedDisksChangeHandler}
55
78
  />
56
79
  </Settings.Item>
80
+ <Settings.Item
81
+ title="Break the Nodes tab in Diagnostics"
82
+ renderTitleComponent={renderBreakNodesSettingsItem}
83
+ >
84
+ <Switch
85
+ checked={props.useNodesEndpointInDiagnostics}
86
+ onUpdate={_onNodesEndpointChangeHandler}
87
+ />
88
+ </Settings.Item>
57
89
  </Settings.Section>
58
90
  </Settings.Page>
59
91
  </Settings>
@@ -61,14 +93,12 @@ function UserSettings(props: any) {
61
93
  }
62
94
 
63
95
  const mapStateToProps = (state: any) => {
64
- const {
65
- theme,
66
- invertedDisks,
67
- } = state.settings.userSettings;
96
+ const {theme, invertedDisks, useNodesEndpointInDiagnostics} = state.settings.userSettings;
68
97
 
69
98
  return {
70
99
  theme,
71
100
  invertedDisks: JSON.parse(invertedDisks),
101
+ useNodesEndpointInDiagnostics: JSON.parse(useNodesEndpointInDiagnostics),
72
102
  };
73
103
  };
74
104
 
@@ -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
  }
@@ -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
- getStorageInfo({tenant, filter, nodeId, type}, {concurrentId} = {}) {
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 './clusterNodes';
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,