ydb-embedded-ui 1.8.7 → 1.10.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.
- 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
|
}
|