Skip to content

Commit 4f4ed43

Browse files
committed
fixup! refactor: migrate TenantOverview to ts
1 parent 59760e8 commit 4f4ed43

File tree

11 files changed

+89
-56
lines changed

11 files changed

+89
-56
lines changed

src/components/InfoViewer/InfoViewer.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import cn from 'bem-cn-lite';
44
import './InfoViewer.scss';
55

66
export interface InfoViewerItem {
7-
label?: ReactNode;
8-
value?: ReactNode;
7+
label: ReactNode;
8+
value: ReactNode;
99
}
1010

1111
interface InfoViewerProps {

src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ import {InfoViewer} from '../../../../components/InfoViewer';
88
import {PoolUsage} from '../../../../components/PoolUsage/PoolUsage';
99
import {Tablet} from '../../../../components/Tablet';
1010
import EntityStatus from '../../../../components/EntityStatus/EntityStatus';
11-
import type {TTenant} from '../../../../types/api/tenant';
1211
import {formatCPU} from '../../../../utils';
1312
import {TABLET_STATES, TENANT_DEFAULT_TITLE} from '../../../../utils/constants';
1413
import {bytesToGB} from '../../../../utils/utils';
1514
import {mapDatabaseTypeToDBName} from '../../utils/schema';
1615
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
16+
import {ETabletVolatileState} from '../../../../types/api/tenant';
1717
import {getTenantInfo, setDataWasNotLoaded} from '../../../../store/reducers/tenant/tenant';
1818

19+
import i18n from './i18n';
1920
import './TenantOverview.scss';
2021

2122
const b = cn('tenant-overview');
@@ -39,20 +40,15 @@ export function TenantOverview({tenantName, additionalTenantInfo}: TenantOvervie
3940
[dispatch, tenantName],
4041
);
4142

42-
useAutofetcher(
43-
(isBackground) => {
44-
fetchTenant(isBackground);
45-
},
46-
[fetchTenant],
47-
autorefresh,
48-
);
43+
useAutofetcher(fetchTenant, [fetchTenant], autorefresh);
4944

5045
const {
5146
Metrics = {},
5247
PoolStats,
5348
StateStats = [],
5449
MemoryUsed,
5550
Name,
51+
State,
5652
CoresUsed,
5753
StorageGroups,
5854
StorageAllocatedSize,
@@ -63,14 +59,15 @@ export function TenantOverview({tenantName, additionalTenantInfo}: TenantOvervie
6359
const tenantType = mapDatabaseTypeToDBName(Type);
6460
const memoryRaw = MemoryUsed ?? Metrics.Memory;
6561

66-
const memory = (memoryRaw && bytesToGB(memoryRaw)) || 'no data';
67-
const storage = (Metrics.Storage && bytesToGB(Metrics.Storage)) || 'no data';
68-
const storageGroups = StorageGroups ?? 'no data';
69-
const blobStorage = (StorageAllocatedSize && bytesToGB(StorageAllocatedSize)) || 'no data';
62+
const memory = (memoryRaw && bytesToGB(memoryRaw)) || i18n('no-data');
63+
const storage = (Metrics.Storage && bytesToGB(Metrics.Storage)) || i18n('no-data');
64+
const storageGroups = StorageGroups ?? i18n('no-data');
65+
const blobStorage =
66+
(StorageAllocatedSize && bytesToGB(StorageAllocatedSize)) || i18n('no-data');
7067
const storageEfficiency =
7168
Metrics.Storage && StorageAllocatedSize
7269
? `${((parseInt(Metrics.Storage) * 100) / parseInt(StorageAllocatedSize)).toFixed(2)}%`
73-
: 'no data';
70+
: i18n('no-data');
7471

7572
const cpuRaw = CoresUsed !== undefined ? Number(CoresUsed) * 1_000_000 : Metrics.CPU;
7673

@@ -86,21 +83,22 @@ export function TenantOverview({tenantName, additionalTenantInfo}: TenantOvervie
8683
{label: 'Storage efficiency', value: storageEfficiency},
8784
];
8885

89-
const tabletsInfo = StateStats.map((info) => {
90-
if (info.VolatileState)
91-
return {label: TABLET_STATES[info.VolatileState], value: info.Count};
92-
return {};
86+
const tabletsInfo = StateStats.filter(
87+
(item): item is {VolatileState: ETabletVolatileState; Count: number} => {
88+
return item.VolatileState !== undefined && item.Count !== undefined;
89+
},
90+
).map((info) => {
91+
return {label: TABLET_STATES[info.VolatileState], value: info.Count};
9392
});
9493

95-
const renderName = (tenant?: TTenant) => {
96-
const {Name = TENANT_DEFAULT_TITLE, State} = tenant || {};
94+
const renderName = () => {
9795
return (
9896
<div className={b('tenant-name-wrapper')}>
9997
<EntityStatus
10098
status={State}
101-
name={Name}
99+
name={Name || TENANT_DEFAULT_TITLE}
102100
withLeftTrim
103-
hasClipboardButton={tenant}
101+
hasClipboardButton={!!tenant}
104102
clipboardButtonAlwaysVisible
105103
/>
106104
</div>
@@ -119,7 +117,7 @@ export function TenantOverview({tenantName, additionalTenantInfo}: TenantOvervie
119117
<div className={b()}>
120118
<div className={b('top-label')}>{tenantType}</div>
121119
<div className={b('top')}>
122-
{renderName(tenant)}
120+
{renderName()}
123121
{tenant && additionalTenantInfo && additionalTenantInfo(tenant.Name, tenant.Type)}
124122
</div>
125123
<div className={b('system-tablets')}>
@@ -130,19 +128,19 @@ export function TenantOverview({tenantName, additionalTenantInfo}: TenantOvervie
130128
</div>
131129
<div className={b('common-info')}>
132130
<div>
133-
<div className={b('section-title')}>Pools</div>
131+
<div className={b('section-title')}>{i18n('title.pools')}</div>
134132
{PoolStats ? (
135133
<div className={b('section', {pools: true})}>
136134
{PoolStats.map((pool, poolIndex) => (
137135
<PoolUsage key={poolIndex} data={pool} />
138136
))}
139137
</div>
140138
) : (
141-
<div className="error">no pools data</div>
139+
<div className="error">{i18n('no-pools-data')}</div>
142140
)}
143141
</div>
144142
<InfoViewer
145-
title="Metrics"
143+
title={i18n('title.metrics')}
146144
className={b('section', {metrics: true})}
147145
info={metricsInfo}
148146
/>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"no-data": "No data",
3+
"no-pools-data": "No pools data",
4+
5+
"title.pools": "Pools",
6+
"title.metrics": "Metrics"
7+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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-tenant-overview';
7+
8+
i18n.registerKeyset(Lang.En, COMPONENT, en);
9+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
10+
11+
export default i18n.keyset(COMPONENT);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"no-data": "Нет данных",
3+
"no-pools-data": "Нет данных о пулах",
4+
5+
"title.pools": "Пулы",
6+
"title.metrics": "Метрики"
7+
}

src/containers/Tenants/Tenants.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ export const Tenants = ({additionalTenantsProps}: TenantsProps) => {
106106
backend,
107107
})}
108108
/>
109-
{additionalTenantsProps?.getMonitoringLink?.(row.Name, row.Type)}
109+
{row.Name &&
110+
row.Type &&
111+
additionalTenantsProps?.getMonitoringLink?.(row.Name, row.Type)}
110112
</div>
111113
);
112114
},

src/services/api.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,16 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
7676
cluster_name: clusterName,
7777
});
7878
}
79-
getTenantInfo({path}: {path: string}) {
80-
return this.get<TTenantInfo>(this.getPath('/viewer/json/tenantinfo'), {
81-
path,
82-
tablets: true,
83-
storage: true,
84-
});
79+
getTenantInfo({path}: {path: string}, {concurrentId}: AxiosOptions = {}) {
80+
return this.get<TTenantInfo>(
81+
this.getPath('/viewer/json/tenantinfo'),
82+
{
83+
path,
84+
tablets: true,
85+
storage: true,
86+
},
87+
{concurrentId: concurrentId || `getTenantInfo|${path}`},
88+
);
8589
}
8690
getNodes(
8791
{

src/store/reducers/tenant/tenant.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ const tenantReducer: Reducer<TenantState, TenantAction> = (state = initialState,
4444
}
4545

4646
case FETCH_TENANT.FAILURE: {
47+
if (action.error?.isCancelled) {
48+
return state;
49+
}
50+
4751
return {
4852
...state,
4953
error: action.error,
@@ -99,7 +103,7 @@ const tenantReducer: Reducer<TenantState, TenantAction> = (state = initialState,
99103

100104
export const getTenantInfo = ({path}: {path: string}) => {
101105
return createApiRequest({
102-
request: window.api.getTenantInfo({path}),
106+
request: window.api.getTenantInfo({path}, {concurrentId: 'getTenantInfo'}),
103107
actions: FETCH_TENANT,
104108
dataHandler: (tenantData): TTenant | undefined => {
105109
return tenantData.TenantInfo?.[0];

src/store/reducers/tenants/selectors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const filterTenantsByProblems = (tenants: PreparedTenant[], problemFilter: Probl
2424
const filteredTenantsBySearch = (tenants: PreparedTenant[], searchQuery: string) => {
2525
return tenants.filter((item) => {
2626
const re = new RegExp(escapeRegExp(searchQuery), 'i');
27-
return re.test(item.Name) || re.test(item.controlPlaneName);
27+
return re.test(item.Name || '') || re.test(item.controlPlaneName);
2828
});
2929
};
3030

src/store/reducers/tenants/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type {TTenant} from '../../../types/api/tenant';
22
import {isNumeric} from '../../../utils/utils';
33

44
const getControlPlaneValue = (tenant: TTenant) => {
5-
const parts = tenant.Name.split('/');
5+
const parts = tenant.Name ? tenant.Name.split('/') : [];
66
const defaultValue = parts.length ? parts[parts.length - 1] : '—';
77
const controlPlaneName = tenant.ControlPlane?.name;
88

src/types/api/tenant.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,38 +22,38 @@ export interface TTenantInfo {
2222
}
2323

2424
export interface TTenant {
25-
Name: string;
26-
Id: string;
27-
Type: ETenantType;
28-
State: State;
25+
Name?: string;
26+
Id?: string;
27+
Type?: ETenantType;
28+
State?: State;
2929
StateStats?: THiveDomainStatsStateCount[];
30-
Metrics: TMetrics;
30+
Metrics?: TMetrics;
3131
NodeIds?: number[];
32-
AliveNodes: number;
33-
Resources: TTenantResources;
32+
AliveNodes?: number;
33+
Resources?: TTenantResources;
3434
/** uint64 */
35-
CreateTime: string;
36-
Owner: string;
35+
CreateTime?: string;
36+
Owner?: string;
3737
Users?: string[];
3838
PoolStats?: TPoolStats[];
39-
UserAttributes: Record<string, string>;
40-
Overall: EFlag;
39+
UserAttributes?: Record<string, string>;
40+
Overall?: EFlag;
4141
SystemTablets?: TTabletStateInfo[];
42-
ResourceId: string;
42+
ResourceId?: string;
4343
Tablets?: TTabletStateInfo[];
4444
/** uint64 */
45-
StorageAllocatedSize: string;
45+
StorageAllocatedSize?: string;
4646
/** uint64 */
47-
StorageMinAvailableSize: string;
47+
StorageMinAvailableSize?: string;
4848
Nodes?: TSystemStateInfo[];
4949
/** uint64 */
50-
MemoryUsed: string;
50+
MemoryUsed?: string;
5151
/** uint64 */
52-
MemoryLimit: string;
52+
MemoryLimit?: string;
5353
/** double */
54-
CoresUsed: number;
54+
CoresUsed?: number;
5555
/** uint64 */
56-
StorageGroups: string;
56+
StorageGroups?: string;
5757

5858
MonitoringEndpoint?: string; // additional
5959
ControlPlane?: ControlPlane; // additional
@@ -139,7 +139,7 @@ enum State {
139139
'CONFIGURING' = 'CONFIGURING',
140140
}
141141

142-
enum ETabletVolatileState {
142+
export enum ETabletVolatileState {
143143
'TABLET_VOLATILE_STATE_UNKNOWN' = 'TABLET_VOLATILE_STATE_UNKNOWN',
144144
'TABLET_VOLATILE_STATE_STOPPED' = 'TABLET_VOLATILE_STATE_STOPPED',
145145
'TABLET_VOLATILE_STATE_BOOTING' = 'TABLET_VOLATILE_STATE_BOOTING',

0 commit comments

Comments
 (0)