ydb-embedded-ui 4.16.1 → 4.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/components/BasicNodeViewer/BasicNodeViewer.tsx +4 -4
  3. package/dist/components/CircularProgressBar/CircularProgressBar.scss +42 -0
  4. package/dist/components/CircularProgressBar/CircularProgressBar.tsx +59 -0
  5. package/dist/components/DiagnosticCard/DiagnosticCard.scss +20 -3
  6. package/dist/components/DiagnosticCard/DiagnosticCard.tsx +5 -6
  7. package/dist/containers/Cluster/Cluster.tsx +4 -4
  8. package/dist/containers/Node/Node.tsx +4 -4
  9. package/dist/containers/Node/NodeStructure/NodeStructure.tsx +5 -5
  10. package/dist/containers/Nodes/Nodes.tsx +3 -3
  11. package/dist/containers/Storage/Storage.tsx +3 -3
  12. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +3 -3
  13. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +1 -5
  14. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +41 -18
  15. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +4 -4
  16. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Details/Details.tsx +3 -3
  17. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Healthcheck.scss +27 -14
  18. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Healthcheck.tsx +6 -6
  19. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Preview/Preview.tsx +15 -16
  20. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/Healthcheck.scss +108 -0
  21. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckDetails.tsx +45 -0
  22. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +83 -0
  23. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTree.scss +1 -3
  24. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTree.tsx +1 -1
  25. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx +1 -1
  26. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/en.json +2 -1
  27. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/index.ts +1 -1
  28. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/ru.json +2 -1
  29. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.scss +52 -0
  30. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.tsx +48 -0
  31. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.scss +12 -0
  32. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +134 -0
  33. package/dist/containers/Tenant/Diagnostics/TenantOverview/OldTenantOverview.tsx +155 -0
  34. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +3 -5
  35. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +79 -89
  36. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +3 -1
  37. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +3 -1
  38. package/dist/containers/Tenant/Diagnostics/TenantOverview/useHealthcheck.ts +53 -0
  39. package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +5 -5
  40. package/dist/containers/Tenant/Tenant.tsx +4 -4
  41. package/dist/containers/Tenant/TenantPages.tsx +1 -0
  42. package/dist/containers/Tenant/utils/queryTemplates.ts +23 -23
  43. package/dist/containers/UserSettings/i18n/en.json +4 -1
  44. package/dist/containers/UserSettings/i18n/ru.json +4 -1
  45. package/dist/containers/UserSettings/settings.ts +7 -0
  46. package/dist/services/api.ts +6 -4
  47. package/dist/store/reducers/healthcheckInfo.ts +20 -12
  48. package/dist/store/reducers/settings/settings.ts +5 -0
  49. package/dist/store/reducers/tenant/constants.ts +7 -0
  50. package/dist/store/reducers/tenant/tenant.ts +15 -0
  51. package/dist/store/reducers/tenant/types.ts +5 -0
  52. package/dist/store/reducers/tenants/contants.ts +6 -0
  53. package/dist/store/reducers/tenants/types.ts +4 -0
  54. package/dist/store/reducers/tenants/utils.ts +114 -7
  55. package/dist/store/state-url-mapping.js +3 -0
  56. package/dist/styles/constants.scss +2 -0
  57. package/dist/types/api/tenant.ts +3 -0
  58. package/dist/utils/constants.ts +1 -0
  59. package/dist/utils/formatCPU/formatCPU.ts +20 -0
  60. package/dist/utils/formatCPU/i18n/en.json +3 -0
  61. package/dist/utils/formatCPU/i18n/index.ts +11 -0
  62. package/dist/utils/formatCPU/i18n/ru.json +3 -0
  63. package/package.json +1 -1
  64. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Details/index.ts +0 -0
  65. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Preview/index.ts +0 -0
  66. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/index.ts +0 -0
  67. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/IssueTreeItem.scss +0 -0
  68. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/index.ts +0 -0
@@ -0,0 +1,155 @@
1
+ import cn from 'bem-cn-lite';
2
+ import {useCallback} from 'react';
3
+ import {useDispatch} from 'react-redux';
4
+
5
+ import {Loader} from '@gravity-ui/uikit';
6
+
7
+ import {InfoViewer} from '../../../../components/InfoViewer';
8
+ import {PoolUsage} from '../../../../components/PoolUsage/PoolUsage';
9
+ import {Tablet} from '../../../../components/Tablet';
10
+ import EntityStatus from '../../../../components/EntityStatus/EntityStatus';
11
+ import {formatCPU} from '../../../../utils';
12
+ import {TABLET_STATES, TENANT_DEFAULT_TITLE} from '../../../../utils/constants';
13
+ import {bytesToGB} from '../../../../utils/utils';
14
+ import {mapDatabaseTypeToDBName} from '../../utils/schema';
15
+ import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
16
+ import type {ETabletVolatileState} from '../../../../types/api/tenant';
17
+ import type {AdditionalTenantsProps} from '../../../../types/additionalProps';
18
+ import {getTenantInfo, setDataWasNotLoaded} from '../../../../store/reducers/tenant/tenant';
19
+
20
+ import i18n from './i18n';
21
+ import './TenantOverview.scss';
22
+
23
+ const b = cn('tenant-overview');
24
+
25
+ interface OldTenantOverviewProps {
26
+ tenantName: string;
27
+ additionalTenantProps?: AdditionalTenantsProps;
28
+ }
29
+
30
+ export function OldTenantOverview({tenantName, additionalTenantProps}: OldTenantOverviewProps) {
31
+ const {tenant, loading, wasLoaded} = useTypedSelector((state) => state.tenant);
32
+ const {autorefresh} = useTypedSelector((state) => state.schema);
33
+ const dispatch = useDispatch();
34
+ const fetchTenant = useCallback(
35
+ (isBackground = true) => {
36
+ if (!isBackground) {
37
+ dispatch(setDataWasNotLoaded());
38
+ }
39
+ dispatch(getTenantInfo({path: tenantName}));
40
+ },
41
+ [dispatch, tenantName],
42
+ );
43
+
44
+ useAutofetcher(fetchTenant, [fetchTenant], autorefresh);
45
+
46
+ const {
47
+ Metrics = {},
48
+ PoolStats,
49
+ StateStats = [],
50
+ MemoryUsed,
51
+ Name,
52
+ State,
53
+ CoresUsed,
54
+ StorageGroups,
55
+ StorageAllocatedSize,
56
+ Type,
57
+ SystemTablets,
58
+ } = tenant || {};
59
+
60
+ const tenantType = mapDatabaseTypeToDBName(Type);
61
+ const memoryRaw = MemoryUsed ?? Metrics.Memory;
62
+
63
+ const memory = (memoryRaw && bytesToGB(memoryRaw)) || i18n('no-data');
64
+ const storage = (Metrics.Storage && bytesToGB(Metrics.Storage)) || i18n('no-data');
65
+ const storageGroups = StorageGroups ?? i18n('no-data');
66
+ const blobStorage =
67
+ (StorageAllocatedSize && bytesToGB(StorageAllocatedSize)) || i18n('no-data');
68
+ const storageEfficiency =
69
+ Metrics.Storage && StorageAllocatedSize
70
+ ? `${((parseInt(Metrics.Storage) * 100) / parseInt(StorageAllocatedSize)).toFixed(2)}%`
71
+ : i18n('no-data');
72
+
73
+ const cpuRaw = CoresUsed !== undefined ? Number(CoresUsed) * 1_000_000 : Metrics.CPU;
74
+
75
+ const cpu = formatCPU(cpuRaw);
76
+
77
+ const metricsInfo = [
78
+ {label: 'Type', value: Type},
79
+ {label: 'Memory', value: memory},
80
+ {label: 'CPU', value: cpu},
81
+ {label: 'Tablet storage', value: storage},
82
+ {label: 'Storage groups', value: storageGroups},
83
+ {label: 'Blob storage', value: blobStorage},
84
+ {label: 'Storage efficiency', value: storageEfficiency},
85
+ ];
86
+
87
+ const tabletsInfo = StateStats.filter(
88
+ (item): item is {VolatileState: ETabletVolatileState; Count: number} => {
89
+ return item.VolatileState !== undefined && item.Count !== undefined;
90
+ },
91
+ ).map((info) => {
92
+ return {label: TABLET_STATES[info.VolatileState], value: info.Count};
93
+ });
94
+
95
+ const renderName = () => {
96
+ return (
97
+ <div className={b('tenant-name-wrapper')}>
98
+ <EntityStatus
99
+ status={State}
100
+ name={Name || TENANT_DEFAULT_TITLE}
101
+ withLeftTrim
102
+ hasClipboardButton={Boolean(tenant)}
103
+ clipboardButtonAlwaysVisible
104
+ />
105
+ </div>
106
+ );
107
+ };
108
+
109
+ if (loading && !wasLoaded) {
110
+ return (
111
+ <div className={b('loader')}>
112
+ <Loader size="m" />
113
+ </div>
114
+ );
115
+ }
116
+
117
+ return (
118
+ <div className={b()}>
119
+ <div className={b('top-label')}>{tenantType}</div>
120
+ <div className={b('top')}>
121
+ {renderName()}
122
+ {additionalTenantProps?.getMonitoringLink?.(Name, Type)}
123
+ </div>
124
+ <div className={b('system-tablets')}>
125
+ {SystemTablets &&
126
+ SystemTablets.map((tablet, tabletIndex) => (
127
+ <Tablet key={tabletIndex} tablet={tablet} tenantName={Name} />
128
+ ))}
129
+ </div>
130
+ <div className={b('common-info')}>
131
+ <div>
132
+ <div className={b('section-title')}>{i18n('title.pools')}</div>
133
+ {PoolStats ? (
134
+ <div className={b('section', {pools: true})}>
135
+ {PoolStats.map((pool, poolIndex) => (
136
+ <PoolUsage key={poolIndex} data={pool} />
137
+ ))}
138
+ </div>
139
+ ) : (
140
+ <div className="error">{i18n('no-pools-data')}</div>
141
+ )}
142
+ </div>
143
+ <InfoViewer
144
+ title={i18n('title.metrics')}
145
+ className={b('section', {metrics: true})}
146
+ info={metricsInfo}
147
+ />
148
+
149
+ <div className={b('section')}>
150
+ <InfoViewer info={tabletsInfo} title="Tablets" />
151
+ </div>
152
+ </div>
153
+ </div>
154
+ );
155
+ }
@@ -1,7 +1,6 @@
1
- @use '../DetailedOverview/DetailedOverview.scss' as detailedOverview;
2
-
3
1
  .tenant-overview {
4
2
  padding-bottom: 20px;
3
+
5
4
  &__loader {
6
5
  display: flex;
7
6
  justify-content: center;
@@ -22,10 +21,10 @@
22
21
  }
23
22
 
24
23
  &__top-label {
25
- margin-bottom: detailedOverview.$section-title-margin;
24
+ margin-bottom: var(--diagnostics-section-title-margin);
26
25
 
27
26
  font-weight: 600;
28
- line-height: detailedOverview.$section-title-line-height;
27
+ line-height: 24px;
29
28
  gap: 10px;
30
29
  }
31
30
 
@@ -50,7 +49,6 @@
50
49
  font-size: var(--yc-text-body-2-font-size);
51
50
  font-weight: 500;
52
51
  line-height: var(--yc-text-body-2-line-height);
53
- //text-transform: uppercase;
54
52
  }
55
53
 
56
54
  &__section {
@@ -4,18 +4,17 @@ import {useDispatch} from 'react-redux';
4
4
 
5
5
  import {Loader} from '@gravity-ui/uikit';
6
6
 
7
- import {InfoViewer} from '../../../../components/InfoViewer';
8
- import {PoolUsage} from '../../../../components/PoolUsage/PoolUsage';
9
- import {Tablet} from '../../../../components/Tablet';
10
7
  import EntityStatus from '../../../../components/EntityStatus/EntityStatus';
11
- import {formatCPU} from '../../../../utils';
12
- import {TABLET_STATES, TENANT_DEFAULT_TITLE} from '../../../../utils/constants';
13
- import {bytesToGB} from '../../../../utils/utils';
8
+ import {TENANT_DEFAULT_TITLE} from '../../../../utils/constants';
9
+ import {TENANT_METRICS_TABS_IDS} from '../../../../store/reducers/tenant/constants';
14
10
  import {mapDatabaseTypeToDBName} from '../../utils/schema';
15
11
  import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
16
- import type {ETabletVolatileState} from '../../../../types/api/tenant';
17
12
  import type {AdditionalTenantsProps} from '../../../../types/additionalProps';
18
13
  import {getTenantInfo, setDataWasNotLoaded} from '../../../../store/reducers/tenant/tenant';
14
+ import {calculateTenantMetrics} from '../../../../store/reducers/tenants/utils';
15
+ import {HealthcheckDetails} from './Healthcheck/HealthcheckDetails';
16
+ import {MetricsCards, type TenantMetrics} from './MetricsCards/MetricsCards';
17
+ import {useHealthcheck} from './useHealthcheck';
19
18
 
20
19
  import i18n from './i18n';
21
20
  import './TenantOverview.scss';
@@ -24,13 +23,30 @@ const b = cn('tenant-overview');
24
23
 
25
24
  interface TenantOverviewProps {
26
25
  tenantName: string;
27
- additionalTenantInfo?: AdditionalTenantsProps;
26
+ additionalTenantProps?: AdditionalTenantsProps;
28
27
  }
29
28
 
30
- export function TenantOverview({tenantName, additionalTenantInfo}: TenantOverviewProps) {
31
- const {tenant, loading, wasLoaded} = useTypedSelector((state) => state.tenant);
32
- const {autorefresh} = useTypedSelector((state) => state.schema);
29
+ export function TenantOverview({tenantName, additionalTenantProps}: TenantOverviewProps) {
33
30
  const dispatch = useDispatch();
31
+
32
+ const {
33
+ tenant,
34
+ loading: tenantLoading,
35
+ wasLoaded: tenantWasLoaded,
36
+ metricsTab,
37
+ } = useTypedSelector((state) => state.tenant);
38
+ const {autorefresh} = useTypedSelector((state) => state.schema);
39
+
40
+ const {
41
+ issueTrees,
42
+ issuesStatistics,
43
+ selfCheckResult,
44
+ fetchHealthcheck,
45
+ loading: healthcheckLoading,
46
+ wasLoaded: healthCheckWasLoaded,
47
+ error: healthcheckError,
48
+ } = useHealthcheck(tenantName);
49
+
34
50
  const fetchTenant = useCallback(
35
51
  (isBackground = true) => {
36
52
  if (!isBackground) {
@@ -41,56 +57,30 @@ export function TenantOverview({tenantName, additionalTenantInfo}: TenantOvervie
41
57
  [dispatch, tenantName],
42
58
  );
43
59
 
44
- useAutofetcher(fetchTenant, [fetchTenant], autorefresh);
60
+ useAutofetcher(
61
+ (isBackground) => {
62
+ fetchTenant(isBackground);
63
+ fetchHealthcheck(isBackground);
64
+ },
65
+ [fetchTenant, fetchHealthcheck],
66
+ autorefresh,
67
+ );
45
68
 
46
- const {
47
- Metrics = {},
48
- PoolStats,
49
- StateStats = [],
50
- MemoryUsed,
51
- Name,
52
- State,
53
- CoresUsed,
54
- StorageGroups,
55
- StorageAllocatedSize,
56
- Type,
57
- SystemTablets,
58
- } = tenant || {};
69
+ const {Name, State, Type} = tenant || {};
59
70
 
60
71
  const tenantType = mapDatabaseTypeToDBName(Type);
61
- const memoryRaw = MemoryUsed ?? Metrics.Memory;
62
-
63
- const memory = (memoryRaw && bytesToGB(memoryRaw)) || i18n('no-data');
64
- const storage = (Metrics.Storage && bytesToGB(Metrics.Storage)) || i18n('no-data');
65
- const storageGroups = StorageGroups ?? i18n('no-data');
66
- const blobStorage =
67
- (StorageAllocatedSize && bytesToGB(StorageAllocatedSize)) || i18n('no-data');
68
- const storageEfficiency =
69
- Metrics.Storage && StorageAllocatedSize
70
- ? `${((parseInt(Metrics.Storage) * 100) / parseInt(StorageAllocatedSize)).toFixed(2)}%`
71
- : i18n('no-data');
72
-
73
- const cpuRaw = CoresUsed !== undefined ? Number(CoresUsed) * 1_000_000 : Metrics.CPU;
74
-
75
- const cpu = formatCPU(cpuRaw);
76
-
77
- const metricsInfo = [
78
- {label: 'Type', value: Type},
79
- {label: 'Memory', value: memory},
80
- {label: 'CPU', value: cpu},
81
- {label: 'Tablet storage', value: storage},
82
- {label: 'Storage groups', value: storageGroups},
83
- {label: 'Blob storage', value: blobStorage},
84
- {label: 'Storage efficiency', value: storageEfficiency},
85
- ];
86
-
87
- const tabletsInfo = StateStats.filter(
88
- (item): item is {VolatileState: ETabletVolatileState; Count: number} => {
89
- return item.VolatileState !== undefined && item.Count !== undefined;
90
- },
91
- ).map((info) => {
92
- return {label: TABLET_STATES[info.VolatileState], value: info.Count};
93
- });
72
+
73
+ const {cpu, storage, memory, cpuLimit, storageLimit, memoryLimit} =
74
+ calculateTenantMetrics(tenant);
75
+
76
+ const calculatedMetrics: TenantMetrics = {
77
+ memoryUsed: memory,
78
+ memoryLimit,
79
+ cpuUsed: cpu,
80
+ cpuLimit,
81
+ storageUsed: storage,
82
+ storageLimit,
83
+ };
94
84
 
95
85
  const renderName = () => {
96
86
  return (
@@ -106,7 +96,27 @@ export function TenantOverview({tenantName, additionalTenantInfo}: TenantOvervie
106
96
  );
107
97
  };
108
98
 
109
- if (loading && !wasLoaded) {
99
+ const renderTabContent = () => {
100
+ switch (metricsTab) {
101
+ case TENANT_METRICS_TABS_IDS.cpu: {
102
+ return i18n('label.under-development');
103
+ }
104
+ case TENANT_METRICS_TABS_IDS.storage: {
105
+ return i18n('label.under-development');
106
+ }
107
+ case TENANT_METRICS_TABS_IDS.memory: {
108
+ return i18n('label.under-development');
109
+ }
110
+ case TENANT_METRICS_TABS_IDS.healthcheck: {
111
+ return <HealthcheckDetails issueTrees={issueTrees} error={healthcheckError} />;
112
+ }
113
+ default: {
114
+ return undefined;
115
+ }
116
+ }
117
+ };
118
+
119
+ if ((tenantLoading && !tenantWasLoaded) || (healthcheckLoading && !healthCheckWasLoaded)) {
110
120
  return (
111
121
  <div className={b('loader')}>
112
122
  <Loader size="m" />
@@ -119,37 +129,17 @@ export function TenantOverview({tenantName, additionalTenantInfo}: TenantOvervie
119
129
  <div className={b('top-label')}>{tenantType}</div>
120
130
  <div className={b('top')}>
121
131
  {renderName()}
122
- {additionalTenantInfo?.getMonitoringLink?.(Name, Type)}
123
- </div>
124
- <div className={b('system-tablets')}>
125
- {SystemTablets &&
126
- SystemTablets.map((tablet, tabletIndex) => (
127
- <Tablet key={tabletIndex} tablet={tablet} tenantName={Name} />
128
- ))}
129
- </div>
130
- <div className={b('common-info')}>
131
- <div>
132
- <div className={b('section-title')}>{i18n('title.pools')}</div>
133
- {PoolStats ? (
134
- <div className={b('section', {pools: true})}>
135
- {PoolStats.map((pool, poolIndex) => (
136
- <PoolUsage key={poolIndex} data={pool} />
137
- ))}
138
- </div>
139
- ) : (
140
- <div className="error">{i18n('no-pools-data')}</div>
141
- )}
142
- </div>
143
- <InfoViewer
144
- title={i18n('title.metrics')}
145
- className={b('section', {metrics: true})}
146
- info={metricsInfo}
147
- />
148
-
149
- <div className={b('section')}>
150
- <InfoViewer info={tabletsInfo} title="Tablets" />
151
- </div>
132
+ {additionalTenantProps?.getMonitoringLink?.(Name, Type)}
152
133
  </div>
134
+ <MetricsCards
135
+ metrics={calculatedMetrics}
136
+ issuesStatistics={issuesStatistics}
137
+ selfCheckResult={selfCheckResult}
138
+ fetchHealthcheck={fetchHealthcheck}
139
+ healthcheckLoading={healthcheckLoading}
140
+ healthcheckError={healthcheckError}
141
+ />
142
+ {renderTabContent()}
153
143
  </div>
154
144
  );
155
145
  }
@@ -3,5 +3,7 @@
3
3
  "no-pools-data": "No pools data",
4
4
 
5
5
  "title.pools": "Pools",
6
- "title.metrics": "Metrics"
6
+ "title.metrics": "Metrics",
7
+
8
+ "label.under-development": "This section is under development"
7
9
  }
@@ -3,5 +3,7 @@
3
3
  "no-pools-data": "Нет данных о пулах",
4
4
 
5
5
  "title.pools": "Пулы",
6
- "title.metrics": "Метрики"
6
+ "title.metrics": "Метрики",
7
+
8
+ "label.under-development": "Этот раздел находится в разработке"
7
9
  }
@@ -0,0 +1,53 @@
1
+ import {useCallback} from 'react';
2
+ import {useDispatch} from 'react-redux';
3
+
4
+ import {
5
+ getHealthcheckInfo,
6
+ selectIssuesStatistics,
7
+ selectIssuesTrees,
8
+ setDataWasNotLoaded,
9
+ } from '../../../../store/reducers/healthcheckInfo';
10
+ import type {IIssuesTree} from '../../../../types/store/healthcheck';
11
+ import {type StatusFlag, SelfCheckResult} from '../../../../types/api/healthcheck';
12
+ import type {IResponseError} from '../../../../types/api/error';
13
+ import {useTypedSelector} from '../../../../utils/hooks/useTypedSelector';
14
+
15
+ interface HealthcheckParams {
16
+ issueTrees: IIssuesTree[];
17
+ issuesStatistics: [StatusFlag, number][];
18
+ fetchHealthcheck: (isBackground?: boolean) => void;
19
+ loading: boolean;
20
+ wasLoaded: boolean;
21
+ error?: IResponseError;
22
+ selfCheckResult: SelfCheckResult;
23
+ }
24
+
25
+ export const useHealthcheck = (tenantName: string): HealthcheckParams => {
26
+ const dispatch = useDispatch();
27
+
28
+ const {data, loading, wasLoaded, error} = useTypedSelector((state) => state.healthcheckInfo);
29
+ const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
30
+ const issuesStatistics = useTypedSelector(selectIssuesStatistics);
31
+ const issueTrees = useTypedSelector(selectIssuesTrees);
32
+
33
+ const fetchHealthcheck = useCallback(
34
+ (isBackground = true) => {
35
+ if (!isBackground) {
36
+ dispatch(setDataWasNotLoaded());
37
+ }
38
+
39
+ dispatch(getHealthcheckInfo(tenantName));
40
+ },
41
+ [dispatch, tenantName],
42
+ );
43
+
44
+ return {
45
+ issueTrees,
46
+ issuesStatistics,
47
+ fetchHealthcheck,
48
+ loading,
49
+ wasLoaded,
50
+ error,
51
+ selfCheckResult,
52
+ };
53
+ };
@@ -19,8 +19,8 @@ const b = cn('object-general');
19
19
 
20
20
  interface ObjectGeneralProps {
21
21
  type?: EPathType;
22
- additionalTenantInfo?: AdditionalTenantsProps;
23
- additionalNodesInfo?: AdditionalNodesProps;
22
+ additionalTenantProps?: AdditionalTenantsProps;
23
+ additionalNodesProps?: AdditionalNodesProps;
24
24
  }
25
25
 
26
26
  function ObjectGeneral(props: ObjectGeneralProps) {
@@ -33,7 +33,7 @@ function ObjectGeneral(props: ObjectGeneralProps) {
33
33
  const {name: tenantName, tenantPage = initialPage} = queryParams;
34
34
 
35
35
  const renderTabContent = () => {
36
- const {type, additionalTenantInfo, additionalNodesInfo} = props;
36
+ const {type, additionalTenantProps, additionalNodesProps} = props;
37
37
  switch (tenantPage) {
38
38
  case TENANT_PAGES_IDS.query: {
39
39
  return <Query path={tenantName as string} theme={theme} type={type} />;
@@ -42,8 +42,8 @@ function ObjectGeneral(props: ObjectGeneralProps) {
42
42
  return (
43
43
  <Diagnostics
44
44
  type={type}
45
- additionalTenantInfo={additionalTenantInfo}
46
- additionalNodesInfo={additionalNodesInfo}
45
+ additionalTenantProps={additionalTenantProps}
46
+ additionalNodesProps={additionalNodesProps}
47
47
  />
48
48
  );
49
49
  }
@@ -38,8 +38,8 @@ const initialTenantSummaryState = {
38
38
  };
39
39
 
40
40
  interface TenantProps {
41
- additionalTenantInfo?: AdditionalTenantsProps;
42
- additionalNodesInfo?: AdditionalNodesProps;
41
+ additionalTenantProps?: AdditionalTenantsProps;
42
+ additionalNodesProps?: AdditionalNodesProps;
43
43
  }
44
44
 
45
45
  function Tenant(props: TenantProps) {
@@ -125,8 +125,8 @@ function Tenant(props: TenantProps) {
125
125
  />
126
126
  <ObjectGeneral
127
127
  type={preloadedPathType || currentPathType}
128
- additionalTenantInfo={props.additionalTenantInfo}
129
- additionalNodesInfo={props.additionalNodesInfo}
128
+ additionalTenantProps={props.additionalTenantProps}
129
+ additionalNodesProps={props.additionalNodesProps}
130
130
  />
131
131
  </SplitPane>
132
132
  )}
@@ -5,6 +5,7 @@ export const TenantTabsGroups = {
5
5
  summaryTab: 'summaryTab',
6
6
  queryTab: 'queryTab',
7
7
  diagnosticsTab: 'diagnosticsTab',
8
+ metricsTab: 'metricsTab',
8
9
  } as const;
9
10
 
10
11
  export const TENANT_INFO_TABS = [
@@ -69,42 +69,42 @@ export const createTopicTemplate = (path: string) => {
69
69
  return `-- docs: https://ydb.tech/en/docs/yql/reference/syntax/create_topic
70
70
  CREATE TOPIC \`${path}/my_topic\` (
71
71
  CONSUMER consumer1,
72
- CONSUMER consumer2 WITH (read_from = Datetime('2022-12-01T12:13:22Z')) -- Sets up the message write time starting from which the consumer will receive data.
72
+ CONSUMER consumer2 WITH (read_from = Datetime('1970-01-01T00:00:00Z')) -- Sets up the message write time starting from which the consumer will receive data.
73
73
  -- Value type: Datetime OR Timestamp OR integer (unix-timestamp in the numeric format).
74
74
  -- Default value: now
75
75
  ) WITH (
76
- min_active_partitions = 5, -- Minimum number of topic partitions.
77
- partition_count_limit = 10, -- Maximum number of active partitions in the topic. 0 is interpreted as unlimited.
78
- retention_period = Interval('PT12H'), -- Data retention period in the topic. Value type: Interval, default value: 18h.
79
- retention_storage_mb = 1, -- Limit on the maximum disk space occupied by the topic data.
76
+ min_active_partitions = 1, -- Minimum number of topic partitions.
77
+ partition_count_limit = 0, -- Maximum number of active partitions in the topic. 0 is interpreted as unlimited.
78
+ retention_period = Interval('PT18H'), -- Data retention period in the topic. Value type: Interval.
79
+ retention_storage_mb = 0, -- Limit on the maximum disk space occupied by the topic data.
80
80
  -- When this value is exceeded, the older data is cleared, like under a retention policy.
81
81
  -- 0 is interpreted as unlimited.
82
- partition_write_speed_bytes_per_second = 2097152, -- Maximum allowed write speed per partition.
83
- partition_write_burst_bytes = 2097152 -- Write quota allocated for write bursts.
84
- -- When set to zero, the actual write_burst value is equalled to
85
- -- the quota value (this allows write bursts of up to one second).
82
+ partition_write_speed_bytes_per_second = 1048576, -- Maximum allowed write speed per partition.
83
+ partition_write_burst_bytes = 0 -- Write quota allocated for write bursts.
84
+ -- When set to zero, the actual write_burst value is equalled to
85
+ -- the quota value (this allows write bursts of up to one second).
86
86
  );`;
87
87
  };
88
88
 
89
89
  export const alterTopicTemplate = (path: string) => {
90
90
  return `-- docs: https://ydb.tech/en/docs/yql/reference/syntax/alter_topic
91
91
  ALTER TOPIC \`${path}\`
92
- ADD CONSUMER new_consumer WITH (read_from = 0), -- Sets up the message write time starting from which the consumer will receive data.
93
- -- Value type: Datetime OR Timestamp OR integer (unix-timestamp in the numeric format).
94
- -- Default value: now
95
- ALTER CONSUMER consumer1 SET (read_from = Datetime('2023-12-01T12:13:22Z')),
92
+ ADD CONSUMER new_consumer WITH (read_from = Datetime('1970-01-01T00:00:00Z')), -- Sets up the message write time starting from which the consumer will receive data.
93
+ -- Value type: Datetime OR Timestamp OR integer (unix-timestamp in the numeric format).
94
+ -- Default value: now
95
+ ALTER CONSUMER consumer1 SET (read_from = Datetime('1970-01-01T00:00:00Z')),
96
96
  DROP CONSUMER consumer2,
97
97
  SET (
98
- min_active_partitions = 10, -- Minimum number of topic partitions.
99
- partition_count_limit = 15, -- Maximum number of active partitions in the topic. 0 is interpreted as unlimited.
100
- retention_period = Interval('PT36H'), -- Data retention period in the topic. Value type: Interval, default value: 18h.
101
- retention_storage_mb = 10, -- Limit on the maximum disk space occupied by the topic data.
102
- -- When this value is exceeded, the older data is cleared, like under a retention policy.
103
- -- 0 is interpreted as unlimited.
104
- partition_write_speed_bytes_per_second = 3145728, -- Maximum allowed write speed per partition.
105
- partition_write_burst_bytes = 1048576 -- Write quota allocated for write bursts.
106
- -- When set to zero, the actual write_burst value is equalled to
107
- -- the quota value (this allows write bursts of up to one second).
98
+ min_active_partitions = 1, -- Minimum number of topic partitions.
99
+ partition_count_limit = 0, -- Maximum number of active partitions in the topic. 0 is interpreted as unlimited.
100
+ retention_period = Interval('PT18H'), -- Data retention period in the topic. Value type: Interval.
101
+ retention_storage_mb = 0, -- Limit on the maximum disk space occupied by the topic data.
102
+ -- When this value is exceeded, the older data is cleared, like under a retention policy.
103
+ -- 0 is interpreted as unlimited.
104
+ partition_write_speed_bytes_per_second = 1048576, -- Maximum allowed write speed per partition.
105
+ partition_write_burst_bytes = 0 -- Write quota allocated for write bursts.
106
+ -- When set to zero, the actual write_burst value is equalled to
107
+ -- the quota value (this allows write bursts of up to one second).
108
108
  );`;
109
109
  };
110
110
 
@@ -23,5 +23,8 @@
23
23
  "settings.useBackendParamsForTables.popover": "Filter and sort Nodes and Storage tables with request params. May increase performance, but could causes additional fetches and longer loading time on older versions",
24
24
 
25
25
  "settings.enableAdditionalQueryModes.title": "Enable additional query modes",
26
- "settings.enableAdditionalQueryModes.popover": "Adds 'Data', 'YQL - QueryService' and 'PostgreSQL' modes. May not work on some versions"
26
+ "settings.enableAdditionalQueryModes.popover": "Adds 'Data', 'YQL - QueryService' and 'PostgreSQL' modes. May not work on some versions",
27
+
28
+ "settings.tenantDiagnostics.title": "Enable new database diagnostics design",
29
+ "settings.tenantDiagnostics.popover": "Adds indicators of database resources usage. Incomplete data may be displayed for some databases"
27
30
  }
@@ -23,5 +23,8 @@
23
23
  "settings.useBackendParamsForTables.popover": "Добавляет фильтрацию и сортировку таблиц Nodes и Storage с использованием параметров запроса. Может улушить производительность, но на старых версиях может привести к дополнительным запросам и большему времени ожидания загрузки",
24
24
 
25
25
  "settings.enableAdditionalQueryModes.title": "Включить дополнительные режимы выполнения запросов",
26
- "settings.enableAdditionalQueryModes.popover": "Добавляет режимы 'Data', 'YQL - QueryService' и 'PostgreSQL'. Может работать некорректно на некоторых версиях"
26
+ "settings.enableAdditionalQueryModes.popover": "Добавляет режимы 'Data', 'YQL - QueryService' и 'PostgreSQL'. Может работать некорректно на некоторых версиях",
27
+
28
+ "settings.tenantDiagnostics.title": "Включить новый дизайн для диагностики баз данных",
29
+ "settings.tenantDiagnostics.popover": "Добавляет индикаторы использования ресурсов базы данных. Для некоторых баз могут отображаться неполные данные"
27
30
  }
@@ -5,6 +5,7 @@ import flaskIcon from '../../assets/icons/flask.svg';
5
5
 
6
6
  import {
7
7
  ENABLE_ADDITIONAL_QUERY_MODES,
8
+ ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN,
8
9
  INVERTED_DISKS_KEY,
9
10
  LANGUAGE_KEY,
10
11
  THEME_KEY,
@@ -94,6 +95,11 @@ export const enableQueryModesForExplainSetting: SettingProps = {
94
95
  title: i18n('settings.enableAdditionalQueryModes.title'),
95
96
  helpPopoverContent: i18n('settings.enableAdditionalQueryModes.popover'),
96
97
  };
98
+ export const enableNewTenantDiagnosticsDesign: SettingProps = {
99
+ settingKey: ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN,
100
+ title: i18n('settings.tenantDiagnostics.title'),
101
+ helpPopoverContent: i18n('settings.tenantDiagnostics.popover'),
102
+ };
97
103
 
98
104
  export const generalSection: SettingsSection = {
99
105
  id: 'generalSection',
@@ -108,6 +114,7 @@ export const experimentsSection: SettingsSection = {
108
114
  useNodesEndpointSetting,
109
115
  useBackendParamsForTables,
110
116
  enableQueryModesForExplainSetting,
117
+ enableNewTenantDiagnosticsDesign,
111
118
  ],
112
119
  };
113
120