ydb-embedded-ui 4.16.2 → 4.17.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 (57) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/components/CircularProgressBar/CircularProgressBar.scss +42 -0
  3. package/dist/components/CircularProgressBar/CircularProgressBar.tsx +59 -0
  4. package/dist/components/DiagnosticCard/DiagnosticCard.scss +20 -3
  5. package/dist/components/DiagnosticCard/DiagnosticCard.tsx +5 -6
  6. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +1 -5
  7. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +40 -17
  8. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Details/Details.tsx +3 -3
  9. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Healthcheck.scss +27 -14
  10. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Healthcheck.tsx +6 -6
  11. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Preview/Preview.tsx +15 -16
  12. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/Healthcheck.scss +108 -0
  13. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckDetails.tsx +45 -0
  14. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +83 -0
  15. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTree.scss +1 -3
  16. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTree.tsx +1 -1
  17. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx +1 -1
  18. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/en.json +2 -1
  19. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/index.ts +1 -1
  20. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/ru.json +2 -1
  21. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.scss +52 -0
  22. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.tsx +48 -0
  23. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.scss +12 -0
  24. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +134 -0
  25. package/dist/containers/Tenant/Diagnostics/TenantOverview/OldTenantOverview.tsx +155 -0
  26. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +3 -5
  27. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +76 -86
  28. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +3 -1
  29. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +3 -1
  30. package/dist/containers/Tenant/Diagnostics/TenantOverview/useHealthcheck.ts +53 -0
  31. package/dist/containers/Tenant/TenantPages.tsx +1 -0
  32. package/dist/containers/UserSettings/i18n/en.json +4 -1
  33. package/dist/containers/UserSettings/i18n/ru.json +4 -1
  34. package/dist/containers/UserSettings/settings.ts +7 -0
  35. package/dist/services/api.ts +6 -4
  36. package/dist/store/reducers/healthcheckInfo.ts +20 -12
  37. package/dist/store/reducers/settings/settings.ts +5 -0
  38. package/dist/store/reducers/tenant/constants.ts +7 -0
  39. package/dist/store/reducers/tenant/tenant.ts +15 -0
  40. package/dist/store/reducers/tenant/types.ts +5 -0
  41. package/dist/store/reducers/tenants/contants.ts +6 -0
  42. package/dist/store/reducers/tenants/types.ts +4 -0
  43. package/dist/store/reducers/tenants/utils.ts +114 -7
  44. package/dist/store/state-url-mapping.js +3 -0
  45. package/dist/styles/constants.scss +2 -0
  46. package/dist/types/api/tenant.ts +3 -0
  47. package/dist/utils/constants.ts +1 -0
  48. package/dist/utils/formatCPU/formatCPU.ts +20 -0
  49. package/dist/utils/formatCPU/i18n/en.json +3 -0
  50. package/dist/utils/formatCPU/i18n/index.ts +11 -0
  51. package/dist/utils/formatCPU/i18n/ru.json +3 -0
  52. package/package.json +1 -1
  53. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Details/index.ts +0 -0
  54. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Preview/index.ts +0 -0
  55. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/index.ts +0 -0
  56. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/IssueTreeItem.scss +0 -0
  57. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/index.ts +0 -0
@@ -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';
@@ -28,9 +27,26 @@ interface TenantOverviewProps {
28
27
  }
29
28
 
30
29
  export function TenantOverview({tenantName, additionalTenantProps}: TenantOverviewProps) {
31
- const {tenant, loading, wasLoaded} = useTypedSelector((state) => state.tenant);
32
- const {autorefresh} = useTypedSelector((state) => state.schema);
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, additionalTenantProps}: TenantOvervi
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, additionalTenantProps}: TenantOvervi
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" />
@@ -121,35 +131,15 @@ export function TenantOverview({tenantName, additionalTenantProps}: TenantOvervi
121
131
  {renderName()}
122
132
  {additionalTenantProps?.getMonitoringLink?.(Name, Type)}
123
133
  </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>
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
+ };
@@ -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 = [
@@ -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
 
@@ -350,10 +350,12 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
350
350
  enable_sampling: enableSampling,
351
351
  });
352
352
  }
353
- getHealthcheckInfo(database: string) {
354
- return this.get<HealthCheckAPIResponse>(this.getPath('/viewer/json/healthcheck'), {
355
- tenant: database,
356
- });
353
+ getHealthcheckInfo(database: string, {concurrentId}: AxiosOptions = {}) {
354
+ return this.get<HealthCheckAPIResponse>(
355
+ this.getPath('/viewer/json/healthcheck'),
356
+ {tenant: database},
357
+ {concurrentId},
358
+ );
357
359
  }
358
360
  killTablet(id?: string) {
359
361
  return this.get<string>(this.getPath(`/tablets?KillTabletID=${id}`), {});
@@ -44,6 +44,10 @@ const healthcheckInfo: Reducer<IHealthcheckInfoState, IHealthCheckInfoAction> =
44
44
  };
45
45
  }
46
46
  case FETCH_HEALTHCHECK.FAILURE: {
47
+ if (action.error?.isCancelled) {
48
+ return state;
49
+ }
50
+
47
51
  return {
48
52
  ...state,
49
53
  error: action.error,
@@ -72,21 +76,25 @@ const mapStatusToPriority: Partial<Record<StatusFlag, number>> = {
72
76
  GREEN: 4,
73
77
  };
74
78
 
75
- const getReasonsForIssue = ({issue, data}: {issue: IssueLog; data: IssueLog[]}) => {
76
- return data.filter((item) => issue.reason && issue.reason.indexOf(item.id) !== -1);
77
- };
79
+ const sortIssues = (data: IssueLog[]): IssueLog[] => {
80
+ return data.sort((a, b) => {
81
+ const aPriority = mapStatusToPriority[a.status] || 0;
82
+ const bPriority = mapStatusToPriority[b.status] || 0;
78
83
 
79
- const getRoots = (data: IssueLog[]): IssueLog[] => {
80
- let roots = data.filter((item) => {
81
- return !data.find((issue) => issue.reason && issue.reason.indexOf(item.id) !== -1);
84
+ return aPriority - bPriority;
82
85
  });
86
+ };
83
87
 
84
- roots = _flow([
85
- _uniqBy((item: IssueLog) => item.id),
86
- _sortBy(({status}: {status: StatusFlag}) => mapStatusToPriority[status]),
87
- ])(roots);
88
+ const getReasonsForIssue = ({issue, data}: {issue: IssueLog; data: IssueLog[]}) => {
89
+ return sortIssues(data.filter((item) => issue.reason && issue.reason.indexOf(item.id) !== -1));
90
+ };
88
91
 
89
- return roots;
92
+ const getRoots = (data: IssueLog[]): IssueLog[] => {
93
+ return sortIssues(
94
+ data.filter((item) => {
95
+ return !data.find((issue) => issue.reason && issue.reason.indexOf(item.id) !== -1);
96
+ }),
97
+ );
90
98
  };
91
99
 
92
100
  const getInvertedConsequencesTree = ({
@@ -147,7 +155,7 @@ export const selectIssuesStatistics: Selector<
147
155
 
148
156
  export function getHealthcheckInfo(database: string) {
149
157
  return createApiRequest({
150
- request: window.api.getHealthcheckInfo(database),
158
+ request: window.api.getHealthcheckInfo(database, {concurrentId: 'getHealthcheckInfo'}),
151
159
  actions: FETCH_HEALTHCHECK,
152
160
  });
153
161
  }
@@ -15,6 +15,7 @@ import {
15
15
  LAST_USED_QUERY_ACTION_KEY,
16
16
  USE_BACKEND_PARAMS_FOR_TABLES_KEY,
17
17
  LANGUAGE_KEY,
18
+ ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN,
18
19
  } from '../../../utils/constants';
19
20
  import '../../../services/api';
20
21
  import {parseJson} from '../../../utils/utils';
@@ -55,6 +56,10 @@ export const initialState = {
55
56
  ENABLE_ADDITIONAL_QUERY_MODES,
56
57
  'false',
57
58
  ),
59
+ [ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN]: readSavedSettingsValue(
60
+ ENABLE_NEW_TENANT_DIAGNOSTICS_DESIGN,
61
+ 'false',
62
+ ),
58
63
  [SAVED_QUERIES_KEY]: readSavedSettingsValue(SAVED_QUERIES_KEY, '[]'),
59
64
  [TENANT_INITIAL_PAGE_KEY]: readSavedSettingsValue(
60
65
  TENANT_INITIAL_PAGE_KEY,
@@ -31,3 +31,10 @@ export const TENANT_SUMMARY_TABS_IDS = {
31
31
  acl: 'acl',
32
32
  schema: 'schema',
33
33
  } as const;
34
+
35
+ export const TENANT_METRICS_TABS_IDS = {
36
+ cpu: 'cpu',
37
+ storage: 'storage',
38
+ memory: 'memory',
39
+ healthcheck: 'healthcheck',
40
+ } as const;
@@ -4,6 +4,7 @@ import type {TTenant} from '../../../types/api/tenant';
4
4
  import type {
5
5
  TenantAction,
6
6
  TenantDiagnosticsTab,
7
+ TenantMetricsTab,
7
8
  TenantPage,
8
9
  TenantQueryTab,
9
10
  TenantState,
@@ -19,6 +20,7 @@ const SET_TOP_LEVEL_TAB = 'tenant/SET_TOP_LEVEL_TAB';
19
20
  const SET_QUERY_TAB = 'tenant/SET_QUERY_TAB';
20
21
  const SET_DIAGNOSTICS_TAB = 'tenant/SET_DIAGNOSTICS_TAB';
21
22
  const SET_SUMMARY_TAB = 'tenant/SET_SUMMARY_TAB';
23
+ const SET_METRICS_TAB = 'tenant/SET_METRICS_TAB';
22
24
  const CLEAR_TENANT = 'tenant/CLEAR_TENANT';
23
25
  const SET_DATA_WAS_NOT_LOADED = 'tenant/SET_DATA_WAS_NOT_LOADED';
24
26
 
@@ -88,6 +90,12 @@ const tenantReducer: Reducer<TenantState, TenantAction> = (state = initialState,
88
90
  summaryTab: action.data,
89
91
  };
90
92
  }
93
+ case SET_METRICS_TAB: {
94
+ return {
95
+ ...state,
96
+ metricsTab: action.data,
97
+ };
98
+ }
91
99
 
92
100
  case SET_DATA_WAS_NOT_LOADED: {
93
101
  return {
@@ -143,6 +151,13 @@ export function setSummaryTab(tab: TenantSummaryTab) {
143
151
  } as const;
144
152
  }
145
153
 
154
+ export function setMetricsTab(tab: TenantMetricsTab) {
155
+ return {
156
+ type: SET_METRICS_TAB,
157
+ data: tab,
158
+ } as const;
159
+ }
160
+
146
161
  export const setDataWasNotLoaded = () => {
147
162
  return {
148
163
  type: SET_DATA_WAS_NOT_LOADED,
@@ -8,6 +8,7 @@ import {
8
8
  TENANT_DIAGNOSTICS_TABS_IDS,
9
9
  TENANT_PAGES_IDS,
10
10
  TENANT_SUMMARY_TABS_IDS,
11
+ TENANT_METRICS_TABS_IDS,
11
12
  } from './constants';
12
13
  import {
13
14
  FETCH_TENANT,
@@ -15,6 +16,7 @@ import {
15
16
  setDiagnosticsTab,
16
17
  setQueryTab,
17
18
  setSummaryTab,
19
+ setMetricsTab,
18
20
  setTenantPage,
19
21
  setDataWasNotLoaded,
20
22
  } from './tenant';
@@ -24,6 +26,7 @@ export type TenantPage = ValueOf<typeof TENANT_PAGES_IDS>;
24
26
  export type TenantQueryTab = ValueOf<typeof TENANT_QUERY_TABS_ID>;
25
27
  export type TenantDiagnosticsTab = ValueOf<typeof TENANT_DIAGNOSTICS_TABS_IDS>;
26
28
  export type TenantSummaryTab = ValueOf<typeof TENANT_SUMMARY_TABS_IDS>;
29
+ export type TenantMetricsTab = ValueOf<typeof TENANT_METRICS_TABS_IDS>;
27
30
 
28
31
  export interface TenantState {
29
32
  loading: boolean;
@@ -32,6 +35,7 @@ export interface TenantState {
32
35
  queryTab?: TenantQueryTab;
33
36
  diagnosticsTab?: TenantDiagnosticsTab;
34
37
  summaryTab?: TenantSummaryTab;
38
+ metricsTab?: TenantMetricsTab;
35
39
  tenant?: TTenant;
36
40
  error?: IResponseError;
37
41
  }
@@ -43,4 +47,5 @@ export type TenantAction =
43
47
  | ReturnType<typeof setQueryTab>
44
48
  | ReturnType<typeof setDiagnosticsTab>
45
49
  | ReturnType<typeof setSummaryTab>
50
+ | ReturnType<typeof setMetricsTab>
46
51
  | ReturnType<typeof setDataWasNotLoaded>;
@@ -0,0 +1,6 @@
1
+ export const METRIC_STATUS = {
2
+ Unspecified: 'Unspecified',
3
+ Good: 'Good',
4
+ Warning: 'Warning',
5
+ Danger: 'Danger',
6
+ } as const;
@@ -1,8 +1,10 @@
1
1
  import {FETCH_TENANTS, setSearchValue} from './tenants';
2
2
 
3
+ import {ValueOf} from '../../../types/common';
3
4
  import type {TTenant} from '../../../types/api/tenant';
4
5
  import type {IResponseError} from '../../../types/api/error';
5
6
  import type {ApiRequestAction} from '../../utils';
7
+ import {METRIC_STATUS} from './contants';
6
8
 
7
9
  export interface PreparedTenant extends TTenant {
8
10
  backend: string | undefined;
@@ -30,3 +32,5 @@ export type TenantsAction =
30
32
  export interface TenantsStateSlice {
31
33
  tenants: TenantsState;
32
34
  }
35
+
36
+ export type MetricStatus = ValueOf<typeof METRIC_STATUS>;