ydb-embedded-ui 1.8.7 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +56 -0
- package/dist/components/BasicNodeViewer/BasicNodeViewer.scss +43 -0
- package/dist/components/BasicNodeViewer/BasicNodeViewer.tsx +53 -0
- package/dist/components/BasicNodeViewer/index.ts +1 -0
- package/dist/components/EntityStatus/EntityStatus.js +15 -3
- package/dist/components/FullNodeViewer/FullNodeViewer.js +29 -48
- package/dist/components/FullNodeViewer/FullNodeViewer.scss +0 -45
- package/dist/components/IndexInfoViewer/IndexInfoViewer.tsx +52 -0
- package/dist/components/InfoViewer/index.ts +4 -0
- package/dist/components/InfoViewer/utils.ts +32 -0
- package/dist/components/ProgressViewer/ProgressViewer.js +1 -1
- package/dist/components/TabletsOverall/TabletsOverall.tsx +1 -1
- package/dist/containers/Node/Node.scss +5 -1
- package/dist/containers/Node/Node.tsx +7 -1
- package/dist/containers/Node/NodeOverview/NodeOverview.tsx +1 -3
- package/dist/containers/Node/NodeStructure/NodeStructure.scss +30 -1
- package/dist/containers/Node/NodeStructure/PDiskTitleBadge.tsx +25 -0
- package/dist/containers/Node/NodeStructure/Pdisk.tsx +24 -2
- package/dist/containers/Nodes/Nodes.js +1 -0
- package/dist/containers/ReduxTooltip/ReduxTooltip.js +1 -1
- package/dist/containers/Storage/Pdisk/Pdisk.tsx +25 -33
- package/dist/containers/Storage/Vdisk/Vdisk.js +2 -0
- package/dist/containers/Tablet/Tablet.js +2 -2
- package/dist/containers/Tablets/Tablets.js +1 -1
- package/dist/containers/Tablets/Tablets.scss +0 -6
- package/dist/containers/TabletsFilters/TabletsFilters.scss +0 -7
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +6 -2
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +24 -14
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.js +6 -2
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +6 -2
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +3 -3
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +24 -3
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +15 -13
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +22 -6
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +80 -10
- package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.js +20 -16
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +1 -0
- package/dist/containers/Tenant/utils/schema.ts +73 -28
- package/dist/containers/Tenant/utils/schemaActions.ts +42 -32
- package/dist/services/api.js +13 -8
- package/dist/store/reducers/executeQuery.js +1 -1
- package/dist/store/reducers/executeTopQueries.js +1 -1
- package/dist/store/reducers/olapStats.js +5 -1
- package/dist/store/reducers/preview.js +1 -1
- package/dist/store/reducers/shardsWorkload.js +32 -4
- package/dist/types/api/schema.ts +43 -1
- package/dist/types/api/storage.ts +54 -0
- package/dist/utils/getNodesColumns.js +2 -0
- package/dist/utils/pdisk.ts +74 -0
- package/dist/utils/tooltip.js +27 -0
- package/package.json +2 -2
@@ -14,9 +14,11 @@ import {Vdisk} from './Vdisk';
|
|
14
14
|
|
15
15
|
import {bytesToGB, pad9} from '../../../utils/utils';
|
16
16
|
import {formatStorageValuesToGb} from '../../../utils';
|
17
|
+
import {getPDiskType} from '../../../utils/pdisk';
|
17
18
|
|
18
19
|
import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
|
19
20
|
import {valueIsDefined} from './NodeStructure';
|
21
|
+
import {PDiskTitleBadge} from './PDiskTitleBadge';
|
20
22
|
|
21
23
|
const b = cn('kv-node-structure');
|
22
24
|
|
@@ -230,6 +232,7 @@ export function PDisk(props: PDiskProps) {
|
|
230
232
|
}
|
231
233
|
if (valueIsDefined(Category)) {
|
232
234
|
pdiskInfo.push({label: 'Category', value: Category});
|
235
|
+
pdiskInfo.push({label: 'Type', value: getPDiskType(data)});
|
233
236
|
}
|
234
237
|
pdiskInfo.push({
|
235
238
|
label: 'Allocated Size',
|
@@ -286,8 +289,27 @@ export function PDisk(props: PDiskProps) {
|
|
286
289
|
<div className={b('pdisk')} id={props.id}>
|
287
290
|
<div className={b('pdisk-header')}>
|
288
291
|
<div className={b('pdisk-title-wrapper')}>
|
289
|
-
<
|
290
|
-
<
|
292
|
+
<EntityStatus status={data.Device} />
|
293
|
+
<PDiskTitleBadge
|
294
|
+
label="PDiskID"
|
295
|
+
value={data.PDiskId}
|
296
|
+
className={b('pdisk-title-id')}
|
297
|
+
/>
|
298
|
+
<PDiskTitleBadge
|
299
|
+
value={getPDiskType(data)}
|
300
|
+
className={b('pdisk-title-type')}
|
301
|
+
/>
|
302
|
+
<ProgressViewer
|
303
|
+
value={data.TotalSize - data.AvailableSize}
|
304
|
+
capacity={data.TotalSize}
|
305
|
+
formatValues={formatStorageValuesToGb}
|
306
|
+
colorizeProgress={true}
|
307
|
+
className={b('pdisk-title-size')}
|
308
|
+
/>
|
309
|
+
<PDiskTitleBadge
|
310
|
+
label="VDisks"
|
311
|
+
value={data.vDisks.length}
|
312
|
+
/>
|
291
313
|
</div>
|
292
314
|
<Button onClick={unfolded ? onClosePDiskDetails : onOpenPDiskDetails} view="flat-secondary">
|
293
315
|
<ArrowToggle direction={unfolded ? 'top' : 'bottom'} />
|
@@ -8,6 +8,8 @@ import {bytesToGB} from '../../../utils/utils';
|
|
8
8
|
import routes, {createHref} from '../../../routes';
|
9
9
|
//@ts-ignore
|
10
10
|
import {getPDiskId} from '../../../utils';
|
11
|
+
import {getPDiskType} from '../../../utils/pdisk';
|
12
|
+
import {TPDiskStateInfo, TPDiskState} from '../../../types/api/storage';
|
11
13
|
import DiskStateProgressBar, {
|
12
14
|
diskProgressColors,
|
13
15
|
} from '../DiskStateProgressBar/DiskStateProgressBar';
|
@@ -20,38 +22,29 @@ import './Pdisk.scss';
|
|
20
22
|
const b = cn('pdisk-storage');
|
21
23
|
|
22
24
|
const stateSeverity = {
|
23
|
-
Initial: 0,
|
24
|
-
Normal: 1,
|
25
|
-
InitialFormatRead: 3,
|
26
|
-
InitialSysLogRead: 3,
|
27
|
-
InitialCommonLogRead: 3,
|
28
|
-
InitialFormatReadError: 5,
|
29
|
-
InitialSysLogReadError: 5,
|
30
|
-
InitialSysLogParseError: 5,
|
31
|
-
InitialCommonLogReadError: 5,
|
32
|
-
InitialCommonLogParseError: 5,
|
33
|
-
CommonLoggerInitError: 5,
|
34
|
-
OpenFileError: 5,
|
35
|
-
ChunkQuotaError: 5,
|
36
|
-
DeviceIoError: 5,
|
25
|
+
[TPDiskState.Initial]: 0,
|
26
|
+
[TPDiskState.Normal]: 1,
|
27
|
+
[TPDiskState.InitialFormatRead]: 3,
|
28
|
+
[TPDiskState.InitialSysLogRead]: 3,
|
29
|
+
[TPDiskState.InitialCommonLogRead]: 3,
|
30
|
+
[TPDiskState.InitialFormatReadError]: 5,
|
31
|
+
[TPDiskState.InitialSysLogReadError]: 5,
|
32
|
+
[TPDiskState.InitialSysLogParseError]: 5,
|
33
|
+
[TPDiskState.InitialCommonLogReadError]: 5,
|
34
|
+
[TPDiskState.InitialCommonLogParseError]: 5,
|
35
|
+
[TPDiskState.CommonLoggerInitError]: 5,
|
36
|
+
[TPDiskState.OpenFileError]: 5,
|
37
|
+
[TPDiskState.ChunkQuotaError]: 5,
|
38
|
+
[TPDiskState.DeviceIoError]: 5,
|
37
39
|
};
|
38
40
|
|
39
|
-
type
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
Host?: string;
|
44
|
-
Path?: string;
|
45
|
-
Realtime?: string;
|
46
|
-
Device?: string;
|
47
|
-
AvailableSize?: string;
|
48
|
-
TotalSize?: string;
|
49
|
-
State?: PDiskState;
|
50
|
-
PDiskId: number;
|
51
|
-
}
|
41
|
+
type PDiskProps = TPDiskStateInfo;
|
42
|
+
|
43
|
+
const isSeverityKey = (key?: TPDiskState): key is keyof typeof stateSeverity =>
|
44
|
+
key !== undefined && key in stateSeverity;
|
52
45
|
|
53
|
-
const getStateSeverity = (pDiskState?:
|
54
|
-
return pDiskState ? stateSeverity[pDiskState] : NOT_AVAILABLE_SEVERITY;
|
46
|
+
const getStateSeverity = (pDiskState?: TPDiskState) => {
|
47
|
+
return isSeverityKey(pDiskState) ? stateSeverity[pDiskState] : NOT_AVAILABLE_SEVERITY;
|
55
48
|
};
|
56
49
|
|
57
50
|
function Pdisk(props: PDiskProps) {
|
@@ -76,8 +69,7 @@ function Pdisk(props: PDiskProps) {
|
|
76
69
|
};
|
77
70
|
/* eslint-disable */
|
78
71
|
const preparePdiskData = () => {
|
79
|
-
const {AvailableSize, TotalSize, State, PDiskId, NodeId,
|
80
|
-
props;
|
72
|
+
const {AvailableSize, TotalSize, State, PDiskId, NodeId, Path, Realtime, Device} = props;
|
81
73
|
const errorColors = [
|
82
74
|
diskProgressColors[colorSeverity.Orange as keyof typeof diskProgressColors],
|
83
75
|
diskProgressColors[colorSeverity.Red as keyof typeof diskProgressColors],
|
@@ -89,9 +81,9 @@ function Pdisk(props: PDiskProps) {
|
|
89
81
|
];
|
90
82
|
|
91
83
|
pdiskData.push({property: 'State', value: State || 'not available'});
|
84
|
+
pdiskData.push({property: 'Type', value: getPDiskType(props) || 'unknown'});
|
92
85
|
NodeId && pdiskData.push({property: 'Node Id', value: NodeId});
|
93
86
|
|
94
|
-
Host && pdiskData.push({property: 'Host', value: Host});
|
95
87
|
Path && pdiskData.push({property: 'Path', value: Path});
|
96
88
|
pdiskData.push({
|
97
89
|
property: 'Available',
|
@@ -151,7 +143,7 @@ function Pdisk(props: PDiskProps) {
|
|
151
143
|
href={createHref(
|
152
144
|
routes.node,
|
153
145
|
{id: props.NodeId, activeTab: STRUCTURE},
|
154
|
-
{pdiskId: props.PDiskId},
|
146
|
+
{pdiskId: props.PDiskId || ''},
|
155
147
|
)}
|
156
148
|
/>
|
157
149
|
</div>
|
@@ -7,6 +7,7 @@ import {Popup} from '@yandex-cloud/uikit';
|
|
7
7
|
import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
|
8
8
|
import routes, {createHref} from '../../../routes';
|
9
9
|
import {stringifyVdiskId, getPDiskId} from '../../../utils';
|
10
|
+
import {getPDiskType} from '../../../utils/pdisk';
|
10
11
|
import DiskStateProgressBar, {
|
11
12
|
diskProgressColors,
|
12
13
|
} from '../DiskStateProgressBar/DiskStateProgressBar';
|
@@ -169,6 +170,7 @@ function Vdisk(props) {
|
|
169
170
|
property: 'State',
|
170
171
|
value: PDisk.State || 'not available',
|
171
172
|
});
|
173
|
+
pdiskData.push({property: 'Type', value: getPDiskType(PDisk) || 'unknown'});
|
172
174
|
PDisk.NodeId && pdiskData.push({property: 'Node Id', value: PDisk.NodeId});
|
173
175
|
PDisk.NodeId &&
|
174
176
|
nodes[PDisk.NodeId] &&
|
@@ -199,7 +199,7 @@ class Tablet extends React.Component {
|
|
199
199
|
return (
|
200
200
|
<CriticalActionDialog
|
201
201
|
visible={dialogVisible}
|
202
|
-
text="The tablet will be
|
202
|
+
text="The tablet will be restarted. Do you want to proceed?"
|
203
203
|
onClose={this.hideDialog}
|
204
204
|
onConfirm={this._onKillClick}
|
205
205
|
/>
|
@@ -363,7 +363,7 @@ class Tablet extends React.Component {
|
|
363
363
|
disabled={this.isDisabledKill()}
|
364
364
|
className={b('control')}
|
365
365
|
>
|
366
|
-
|
366
|
+
Restart
|
367
367
|
</Button>
|
368
368
|
{this.hasHiveId() ? (
|
369
369
|
<React.Fragment>
|
@@ -150,7 +150,7 @@ class Tablets extends React.Component {
|
|
150
150
|
const {stateFilter, typeFilter, className} = this.props;
|
151
151
|
|
152
152
|
return (
|
153
|
-
<div className={
|
153
|
+
<div className={b(null, className)}>
|
154
154
|
<div className={b('header')}>
|
155
155
|
<Select
|
156
156
|
className={b('filter-control')}
|
@@ -3,7 +3,6 @@
|
|
3
3
|
.tablets-filters {
|
4
4
|
overflow: auto;
|
5
5
|
|
6
|
-
max-height: 400px;
|
7
6
|
@include flex-container();
|
8
7
|
|
9
8
|
&__node {
|
@@ -19,18 +18,12 @@
|
|
19
18
|
}
|
20
19
|
|
21
20
|
&__items {
|
22
|
-
display: flex;
|
23
21
|
overflow: auto;
|
24
22
|
flex: 1 1 auto;
|
25
|
-
flex-wrap: wrap;
|
26
23
|
|
27
24
|
padding: 5px 20px;
|
28
25
|
}
|
29
26
|
|
30
|
-
&__items-wrapper {
|
31
|
-
overflow: auto;
|
32
|
-
}
|
33
|
-
|
34
27
|
&__filters {
|
35
28
|
display: flex;
|
36
29
|
align-items: center;
|
@@ -1,9 +1,13 @@
|
|
1
|
+
$section-title-margin: 20px;
|
2
|
+
$section-title-line-height: 24px;
|
3
|
+
|
1
4
|
.kv-detailed-overview {
|
2
5
|
display: flex;
|
3
|
-
gap:
|
6
|
+
gap: 20px;
|
4
7
|
&__section {
|
5
8
|
display: flex;
|
6
|
-
|
9
|
+
overflow-x: hidden;
|
10
|
+
flex: 0 0 calc(50% - 10px);
|
7
11
|
flex-direction: column;
|
8
12
|
}
|
9
13
|
|
@@ -13,6 +13,11 @@ export enum GeneralPagesIds {
|
|
13
13
|
'graph' = 'graph',
|
14
14
|
}
|
15
15
|
|
16
|
+
type Page = {
|
17
|
+
id: GeneralPagesIds,
|
18
|
+
title: string,
|
19
|
+
};
|
20
|
+
|
16
21
|
const overview = {
|
17
22
|
id: GeneralPagesIds.overview,
|
18
23
|
title: 'Overview',
|
@@ -76,17 +81,22 @@ export const TABLE_PAGES = [overview, topShards, graph, tablets, hotKeys, descri
|
|
76
81
|
|
77
82
|
export const DIR_PAGES = [overview, topShards, describe];
|
78
83
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
84
|
+
// verbose mapping to guarantee correct tabs for new path types
|
85
|
+
// TS will error when a new type is added but not mapped here
|
86
|
+
const pathTypeToPages: Record<EPathType, Page[] | undefined> = {
|
87
|
+
[EPathType.EPathTypeInvalid]: undefined,
|
88
|
+
|
89
|
+
[EPathType.EPathTypeSubDomain]: DATABASE_PAGES,
|
90
|
+
[EPathType.EPathTypeExtSubDomain]: DATABASE_PAGES,
|
91
|
+
[EPathType.EPathTypeColumnStore]: DATABASE_PAGES,
|
92
|
+
|
93
|
+
[EPathType.EPathTypeTable]: TABLE_PAGES,
|
94
|
+
[EPathType.EPathTypeColumnTable]: TABLE_PAGES,
|
95
|
+
|
96
|
+
[EPathType.EPathTypeDir]: DIR_PAGES,
|
97
|
+
[EPathType.EPathTypeTableIndex]: DIR_PAGES,
|
98
|
+
[EPathType.EPathTypeCdcStream]: DIR_PAGES,
|
99
|
+
};
|
100
|
+
|
101
|
+
export const getPagesByType = (type?: EPathType) =>
|
102
|
+
(type && pathTypeToPages[type]) || DIR_PAGES;
|
@@ -97,10 +97,14 @@ class Healthcheck extends React.Component {
|
|
97
97
|
</div>
|
98
98
|
{this.renderUpdateButton()}
|
99
99
|
</div>
|
100
|
-
<div>
|
100
|
+
<div className={b('preview-content')}>
|
101
101
|
{text}
|
102
102
|
{!statusOk && (
|
103
|
-
<Button
|
103
|
+
<Button
|
104
|
+
view="flat-info"
|
105
|
+
onClick={showMoreHandler}
|
106
|
+
size="s"
|
107
|
+
>
|
104
108
|
Show details
|
105
109
|
</Button>
|
106
110
|
)}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
@use '../DetailedOverview/DetailedOverview.scss' as detailedOverview;
|
1
2
|
@import '../../../../styles/mixins.scss';
|
2
3
|
|
3
4
|
.healthcheck {
|
@@ -37,14 +38,17 @@
|
|
37
38
|
|
38
39
|
&__status-wrapper {
|
39
40
|
display: flex;
|
40
|
-
align-items: baseline;
|
41
41
|
|
42
|
-
margin-bottom:
|
42
|
+
margin-bottom: detailedOverview.$section-title-margin;
|
43
43
|
gap: 8px;
|
44
44
|
}
|
45
45
|
|
46
46
|
&__preview-title {
|
47
47
|
font-weight: 600;
|
48
|
+
line-height: detailedOverview.$section-title-line-height;
|
49
|
+
}
|
50
|
+
|
51
|
+
&__preview-content {
|
48
52
|
line-height: 24px;
|
49
53
|
}
|
50
54
|
|
@@ -8,9 +8,10 @@ import Icon from '../../../../components/Icon/Icon';
|
|
8
8
|
|
9
9
|
import {AutoFetcher} from '../../../../utils/autofetcher';
|
10
10
|
import {getHotKeys, setHotKeysOptions} from '../../../../store/reducers/hotKeys';
|
11
|
-
import {EPathType} from '../../../../types/api/schema';
|
12
11
|
import {prepareQueryError} from '../../../../utils';
|
13
12
|
|
13
|
+
import {isColumnEntityType, isTableType} from '../../utils/schema';
|
14
|
+
|
14
15
|
import './HotKeys.scss';
|
15
16
|
|
16
17
|
const b = cn('hot-keys');
|
@@ -42,8 +43,7 @@ function HotKeys({
|
|
42
43
|
type,
|
43
44
|
}) {
|
44
45
|
const fetchData = () => {
|
45
|
-
|
46
|
-
if (type === EPathType.EPathTypeTable) {
|
46
|
+
if (isTableType(type) && !isColumnEntityType(type)) {
|
47
47
|
getHotKeys(currentSchemaPath);
|
48
48
|
}
|
49
49
|
};
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {useEffect, useMemo} from 'react';
|
1
|
+
import {ReactNode, useEffect, useMemo} from 'react';
|
2
2
|
import {useDispatch, useSelector} from 'react-redux';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
4
|
|
@@ -6,8 +6,9 @@ import {Loader} from '@yandex-cloud/uikit';
|
|
6
6
|
|
7
7
|
//@ts-ignore
|
8
8
|
import SchemaInfoViewer from '../../Schema/SchemaInfoViewer/SchemaInfoViewer';
|
9
|
+
import {IndexInfoViewer} from '../../../../components/IndexInfoViewer/IndexInfoViewer';
|
9
10
|
|
10
|
-
import
|
11
|
+
import {EPathType} from '../../../../types/api/schema';
|
11
12
|
import {isColumnEntityType, isTableType} from '../../utils/schema';
|
12
13
|
import {AutoFetcher} from '../../../../utils/autofetcher';
|
13
14
|
//@ts-ignore
|
@@ -112,11 +113,31 @@ function Overview(props: OverviewProps) {
|
|
112
113
|
);
|
113
114
|
};
|
114
115
|
|
116
|
+
const renderContent = () => {
|
117
|
+
// verbose mapping to guarantee a correct render for new path types
|
118
|
+
// TS will error when a new type is added but not mapped here
|
119
|
+
const pathTypeToComponent: Record<EPathType, (() => ReactNode) | undefined> = {
|
120
|
+
[EPathType.EPathTypeInvalid]: undefined,
|
121
|
+
[EPathType.EPathTypeDir]: undefined,
|
122
|
+
[EPathType.EPathTypeTable]: undefined,
|
123
|
+
[EPathType.EPathTypeSubDomain]: undefined,
|
124
|
+
[EPathType.EPathTypeTableIndex]: () => <IndexInfoViewer data={schemaData} />,
|
125
|
+
[EPathType.EPathTypeExtSubDomain]: undefined,
|
126
|
+
[EPathType.EPathTypeColumnStore]: undefined,
|
127
|
+
[EPathType.EPathTypeColumnTable]: undefined,
|
128
|
+
[EPathType.EPathTypeCdcStream]: undefined,
|
129
|
+
};
|
130
|
+
|
131
|
+
return (props.type && pathTypeToComponent[props.type]?.()) || (
|
132
|
+
<SchemaInfoViewer fullPath={currentItem.Path} data={schemaData} />
|
133
|
+
);
|
134
|
+
}
|
135
|
+
|
115
136
|
return loading && !wasLoaded ? (
|
116
137
|
renderLoader()
|
117
138
|
) : (
|
118
139
|
<div className={props.className}>
|
119
|
-
|
140
|
+
{renderContent()}
|
120
141
|
</div>
|
121
142
|
);
|
122
143
|
}
|
@@ -25,9 +25,11 @@ const renderName = (tenant) => {
|
|
25
25
|
if (tenant) {
|
26
26
|
const {Name} = tenant;
|
27
27
|
return (
|
28
|
-
<div className={b('tenant-name')}>
|
28
|
+
<div className={b('tenant-name-wrapper')}>
|
29
29
|
<EntityStatus status={tenant.State} />
|
30
|
-
<span
|
30
|
+
<span className={b('tenant-name-trim')}>
|
31
|
+
<span className={b('tenant-name')}>{Name}</span>
|
32
|
+
</span>
|
31
33
|
</div>
|
32
34
|
);
|
33
35
|
}
|
@@ -139,17 +141,17 @@ class TenantOverview extends React.Component {
|
|
139
141
|
this.props.tenant.Name,
|
140
142
|
this.props.tenant.Type,
|
141
143
|
)}
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
144
|
+
</div>
|
145
|
+
<div className={b('system-tablets')}>
|
146
|
+
{SystemTablets &&
|
147
|
+
SystemTablets.map((tablet, tabletIndex) => (
|
148
|
+
<Tablet
|
149
|
+
onMouseEnter={showTooltip}
|
150
|
+
onMouseLeave={hideTooltip}
|
151
|
+
key={tabletIndex}
|
152
|
+
tablet={tablet}
|
153
|
+
/>
|
154
|
+
))}
|
153
155
|
</div>
|
154
156
|
<div className={b('common-info')}>
|
155
157
|
{PoolStats ? (
|
@@ -1,30 +1,46 @@
|
|
1
|
+
@use '../DetailedOverview/DetailedOverview.scss' as detailedOverview;
|
2
|
+
|
1
3
|
.tenant-overview {
|
2
4
|
padding-bottom: 20px;
|
3
5
|
&__loader {
|
4
6
|
display: flex;
|
5
7
|
justify-content: center;
|
6
8
|
}
|
7
|
-
&__tenant-name {
|
9
|
+
&__tenant-name-wrapper {
|
8
10
|
display: flex;
|
11
|
+
overflow: hidden;
|
9
12
|
align-items: center;
|
10
13
|
|
11
14
|
& .yc-link {
|
12
15
|
display: flex;
|
13
16
|
}
|
14
17
|
}
|
18
|
+
&__tenant-name-trim {
|
19
|
+
overflow: hidden;
|
20
|
+
|
21
|
+
white-space: nowrap;
|
22
|
+
text-overflow: ellipsis;
|
23
|
+
direction: rtl;
|
24
|
+
}
|
25
|
+
|
26
|
+
&__tenant-name {
|
27
|
+
unicode-bidi: plaintext;
|
28
|
+
}
|
15
29
|
|
16
30
|
&__top {
|
17
31
|
display: flex;
|
18
32
|
align-items: center;
|
19
33
|
|
20
|
-
margin-bottom:
|
34
|
+
margin-bottom: 10px;
|
35
|
+
|
36
|
+
line-height: 24px;
|
21
37
|
}
|
22
38
|
|
23
39
|
&__top-label {
|
24
|
-
margin-bottom:
|
40
|
+
margin-bottom: detailedOverview.$section-title-margin;
|
25
41
|
|
26
42
|
font-weight: 600;
|
27
|
-
line-height:
|
43
|
+
line-height: detailedOverview.$section-title-line-height;
|
28
44
|
gap: 10px;
|
29
45
|
}
|
30
46
|
|
@@ -42,7 +58,7 @@
|
|
42
58
|
flex-wrap: wrap;
|
43
59
|
align-items: center;
|
44
60
|
|
45
|
-
margin-
|
61
|
+
margin-bottom: 35px;
|
46
62
|
}
|
47
63
|
|
48
64
|
&__collapse-title {
|
@@ -76,7 +92,7 @@
|
|
76
92
|
margin-bottom: 20px;
|
77
93
|
|
78
94
|
font-size: var(--yc-text-body-2-font-size);
|
79
|
-
font-weight:
|
95
|
+
font-weight: 600;
|
80
96
|
line-height: var(--yc-text-body-2-line-height);
|
81
97
|
}
|
82
98
|
}
|