ydb-embedded-ui 4.16.2 → 4.17.0

Sign up to get free protection for your applications and to get access to all the features.
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>;