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.
Files changed (118) 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/Consumers/Consumers.tsx +2 -1
  53. package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +2 -2
  54. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -4
  55. package/dist/containers/Tenant/Diagnostics/OverloadedShards/OverloadedShards.tsx +1 -1
  56. package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/ChangefeedInfo.tsx +69 -0
  57. package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/index.ts +1 -0
  58. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +18 -16
  59. package/dist/containers/Tenant/Diagnostics/Overview/TopicInfo/TopicInfo.tsx +37 -0
  60. package/dist/containers/Tenant/Diagnostics/Overview/TopicInfo/index.ts +1 -0
  61. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.scss +30 -0
  62. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +94 -0
  63. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/en.json +3 -0
  64. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/index.ts +11 -0
  65. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/ru.json +3 -0
  66. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/index.ts +1 -0
  67. package/dist/containers/Tenant/Diagnostics/Overview/utils/index.ts +1 -0
  68. package/dist/containers/Tenant/Diagnostics/Overview/utils/prepareTopicSchemaInfo.ts +42 -0
  69. package/dist/containers/Tenant/utils/schema.ts +19 -0
  70. package/dist/containers/Tenants/Tenants.js +2 -1
  71. package/dist/containers/UserSettings/UserSettings.tsx +18 -10
  72. package/dist/services/api.d.ts +8 -1
  73. package/dist/services/api.js +27 -8
  74. package/dist/store/reducers/index.ts +3 -1
  75. package/dist/store/reducers/nodes.ts +148 -14
  76. package/dist/store/reducers/{clusterNodes.js → nodesList.js} +0 -41
  77. package/dist/store/reducers/settings.js +10 -4
  78. package/dist/store/reducers/storage.js +24 -13
  79. package/dist/store/reducers/tenant.js +5 -4
  80. package/dist/store/reducers/tooltip.ts +1 -1
  81. package/dist/store/reducers/topic.ts +52 -0
  82. package/dist/styles/mixins.scss +19 -11
  83. package/dist/types/api/common.ts +5 -0
  84. package/dist/types/api/compute.ts +1 -1
  85. package/dist/types/api/consumer.ts +12 -10
  86. package/dist/types/api/nodes.ts +2 -0
  87. package/dist/types/api/pdisk.ts +1 -0
  88. package/dist/types/api/schema.ts +3 -3
  89. package/dist/types/api/topic.ts +5 -4
  90. package/dist/types/api/vdisk.ts +2 -1
  91. package/dist/types/store/nodes.ts +56 -6
  92. package/dist/types/store/tooltip.ts +1 -1
  93. package/dist/types/store/topic.ts +21 -0
  94. package/dist/utils/constants.ts +5 -1
  95. package/dist/utils/i18n/i18n.ts +10 -2
  96. package/dist/utils/index.js +1 -1
  97. package/dist/utils/timeParsers/__test__/formatDuration.test.ts +50 -0
  98. package/dist/utils/timeParsers/__test__/protobuf.test.ts +74 -0
  99. package/dist/utils/timeParsers/formatDuration.ts +46 -0
  100. package/dist/utils/timeParsers/i18n/en.json +7 -0
  101. package/dist/utils/timeParsers/i18n/index.ts +11 -0
  102. package/dist/utils/timeParsers/i18n/ru.json +7 -0
  103. package/dist/utils/timeParsers/index.ts +2 -0
  104. package/dist/utils/timeParsers/protobuf.ts +36 -0
  105. package/package.json +1 -1
  106. package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +0 -48
  107. package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +0 -30
  108. package/dist/components/InternalLink/InternalLink.js +0 -23
  109. package/dist/containers/Nodes/Nodes.js +0 -213
  110. package/dist/containers/NodesViewer/NodesViewer.js +0 -163
  111. package/dist/containers/NodesViewer/NodesViewer.scss +0 -66
  112. package/dist/containers/Storage/Pdisk/Pdisk.tsx +0 -153
  113. package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +0 -41
  114. package/dist/containers/Storage/Vdisk/Vdisk.js +0 -275
  115. package/dist/containers/Storage/Vdisk/Vdisk.scss +0 -22
  116. package/dist/containers/Storage/Vdisk/__tests__/colors.tsx +0 -163
  117. package/dist/containers/Tenant/Diagnostics/Compute/Compute.js +0 -139
  118. 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;
@@ -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 {INVERTED_DISKS_KEY, THEME_KEY} from '../../utils/constants';
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
 
@@ -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,