ydb-embedded-ui 4.4.2 → 4.5.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 +7 -0
- package/dist/components/ContentWithPopup/ContentWithPopup.tsx +51 -0
- package/dist/components/ExternalLinkWithIcon/ExternalLinkWithIcon.scss +7 -0
- package/dist/components/ExternalLinkWithIcon/ExternalLinkWithIcon.tsx +24 -0
- package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +2 -2
- package/dist/components/PoolBar/PoolBar.scss +6 -1
- package/dist/components/PoolBar/PoolBar.tsx +39 -0
- package/dist/components/PoolsGraph/PoolsGraph.scss +1 -1
- package/dist/components/PoolsGraph/PoolsGraph.tsx +23 -0
- package/dist/components/Tablet/Tablet.scss +4 -1
- package/dist/components/Tablet/Tablet.tsx +11 -35
- package/dist/components/{Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip.scss → TooltipsContent/NodeEndpointsTooltipContent/NodeEndpointsTooltipContent.scss} +1 -1
- package/dist/components/{Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip.tsx → TooltipsContent/NodeEndpointsTooltipContent/NodeEndpointsTooltipContent.tsx} +3 -3
- package/dist/components/TooltipsContent/PoolTooltipContent/PoolTooltipContent.tsx +24 -0
- package/dist/components/TooltipsContent/TabletTooltipContent/TabletTooltipContent.tsx +34 -0
- package/dist/components/TooltipsContent/index.ts +3 -0
- package/dist/containers/Cluster/Cluster.tsx +14 -10
- package/dist/containers/{ClusterInfo → Cluster/ClusterInfo}/ClusterInfo.scss +8 -40
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +223 -0
- package/dist/containers/{ClusterInfo → Cluster/ClusterInfo}/utils.ts +1 -1
- package/dist/containers/Cluster/VersionsBar/VersionsBar.scss +27 -0
- package/dist/containers/Cluster/VersionsBar/VersionsBar.tsx +33 -0
- package/dist/containers/Header/Header.tsx +3 -6
- package/dist/containers/Nodes/Nodes.tsx +0 -11
- package/dist/containers/Nodes/getNodesColumns.tsx +3 -20
- package/dist/containers/Tablets/Tablets.tsx +1 -17
- package/dist/containers/TabletsFilters/TabletsFilters.js +2 -14
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +2 -12
- package/dist/containers/Tenants/Tenants.js +3 -17
- package/dist/containers/Versions/NodesTable/NodesTable.tsx +4 -34
- package/dist/types/additionalProps.ts +11 -0
- package/dist/utils/tooltip.js +8 -80
- package/package.json +1 -1
- package/dist/components/PoolBar/PoolBar.js +0 -52
- package/dist/components/PoolsGraph/PoolsGraph.js +0 -33
- package/dist/containers/ClusterInfo/ClusterInfo.tsx +0 -207
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [4.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.4.2...v4.5.0) (2023-06-01)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* **ClusterInfo:** update versions bar, rework DC and Tablets fields ([#407](https://github.com/ydb-platform/ydb-embedded-ui/issues/407)) ([4824f0d](https://github.com/ydb-platform/ydb-embedded-ui/commit/4824f0d2be9d7bec3641302c88b39a3a87f37c18))
|
9
|
+
|
3
10
|
## [4.4.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.4.1...v4.4.2) (2023-05-29)
|
4
11
|
|
5
12
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
import {ReactNode, useRef, useState} from 'react';
|
2
|
+
|
3
|
+
import {Popup, PopupProps} from '@gravity-ui/uikit';
|
4
|
+
|
5
|
+
interface ContentWithPopupProps extends PopupProps {
|
6
|
+
content: ReactNode;
|
7
|
+
className?: string;
|
8
|
+
children?: ReactNode;
|
9
|
+
}
|
10
|
+
|
11
|
+
export const ContentWithPopup = ({
|
12
|
+
children,
|
13
|
+
content,
|
14
|
+
className,
|
15
|
+
hasArrow = true,
|
16
|
+
placement = ['top', 'bottom'],
|
17
|
+
...props
|
18
|
+
}: ContentWithPopupProps) => {
|
19
|
+
const [isPopupVisible, setIsPopupVisible] = useState(false);
|
20
|
+
const anchor = useRef(null);
|
21
|
+
|
22
|
+
const showPopup = () => {
|
23
|
+
setIsPopupVisible(true);
|
24
|
+
};
|
25
|
+
|
26
|
+
const hidePopup = () => {
|
27
|
+
setIsPopupVisible(false);
|
28
|
+
};
|
29
|
+
|
30
|
+
return (
|
31
|
+
<>
|
32
|
+
<Popup
|
33
|
+
anchorRef={anchor}
|
34
|
+
open={isPopupVisible}
|
35
|
+
placement={placement}
|
36
|
+
hasArrow={hasArrow}
|
37
|
+
{...props}
|
38
|
+
>
|
39
|
+
{content}
|
40
|
+
</Popup>
|
41
|
+
<span
|
42
|
+
className={className}
|
43
|
+
ref={anchor}
|
44
|
+
onMouseEnter={showPopup}
|
45
|
+
onMouseLeave={hidePopup}
|
46
|
+
>
|
47
|
+
{children}
|
48
|
+
</span>
|
49
|
+
</>
|
50
|
+
);
|
51
|
+
};
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import block from 'bem-cn-lite';
|
2
|
+
|
3
|
+
import {Link} from '@gravity-ui/uikit';
|
4
|
+
|
5
|
+
import {IconWrapper} from '../Icon/Icon';
|
6
|
+
|
7
|
+
import './ExternalLinkWithIcon.scss';
|
8
|
+
|
9
|
+
const b = block('ydb-external-link-with-icon');
|
10
|
+
|
11
|
+
interface ExternalLinkWithIconProps {
|
12
|
+
title: string;
|
13
|
+
url: string;
|
14
|
+
}
|
15
|
+
|
16
|
+
export const ExternalLinkWithIcon = ({title, url}: ExternalLinkWithIconProps) => {
|
17
|
+
return (
|
18
|
+
<Link href={url} target="_blank" className={b()}>
|
19
|
+
{title}
|
20
|
+
{'\u00a0'}
|
21
|
+
<IconWrapper name="external" viewBox={'0 0 16 16'} width={16} height={16} />
|
22
|
+
</Link>
|
23
|
+
);
|
24
|
+
};
|
@@ -7,7 +7,7 @@ import {getDefaultNodePath} from '../../containers/Node/NodePages';
|
|
7
7
|
import {isUnavailableNode, NodeAddress} from '../../utils/nodes';
|
8
8
|
|
9
9
|
import EntityStatus from '../EntityStatus/EntityStatus';
|
10
|
-
import {
|
10
|
+
import {NodeEndpointsTooltipContent} from '../TooltipsContent';
|
11
11
|
import {IconWrapper} from '../Icon';
|
12
12
|
|
13
13
|
import './NodeHostWrapper.scss';
|
@@ -31,7 +31,7 @@ export const NodeHostWrapper = ({node, getNodeRef}: NodeHostWrapperProps) => {
|
|
31
31
|
<div className={b()}>
|
32
32
|
<Popover
|
33
33
|
disabled={!isNodeAvailable}
|
34
|
-
content={<
|
34
|
+
content={<NodeEndpointsTooltipContent data={node} />}
|
35
35
|
placement={['top', 'bottom']}
|
36
36
|
behavior={PopoverBehavior.Immediate}
|
37
37
|
>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import block from 'bem-cn-lite';
|
2
|
+
|
3
|
+
import type {TPoolStats} from '../../types/api/nodes';
|
4
|
+
|
5
|
+
import {ContentWithPopup} from '../ContentWithPopup/ContentWithPopup';
|
6
|
+
import {PoolTooltipContent} from '../TooltipsContent';
|
7
|
+
|
8
|
+
import './PoolBar.scss';
|
9
|
+
|
10
|
+
const b = block('ydb-pool-bar');
|
11
|
+
|
12
|
+
const getBarType = (usage: number) => {
|
13
|
+
if (usage >= 75) {
|
14
|
+
return 'danger';
|
15
|
+
} else if (usage >= 50 && usage < 75) {
|
16
|
+
return 'warning';
|
17
|
+
} else {
|
18
|
+
return 'normal';
|
19
|
+
}
|
20
|
+
};
|
21
|
+
|
22
|
+
interface PoolBarProps {
|
23
|
+
data?: TPoolStats;
|
24
|
+
}
|
25
|
+
|
26
|
+
export const PoolBar = ({data = {}}: PoolBarProps) => {
|
27
|
+
const {Usage: usage = 0} = data;
|
28
|
+
const usagePercents = Math.min(usage * 100, 100);
|
29
|
+
const type = getBarType(usagePercents);
|
30
|
+
|
31
|
+
return (
|
32
|
+
<ContentWithPopup
|
33
|
+
className={b({type})}
|
34
|
+
content={<PoolTooltipContent data={data} className={b('popup-content')} />}
|
35
|
+
>
|
36
|
+
<div style={{height: `${usagePercents}%`}} className={b('value', {type})} />
|
37
|
+
</ContentWithPopup>
|
38
|
+
);
|
39
|
+
};
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import block from 'bem-cn-lite';
|
2
|
+
|
3
|
+
import type {TPoolStats} from '../../types/api/nodes';
|
4
|
+
|
5
|
+
import {PoolBar} from '../PoolBar/PoolBar';
|
6
|
+
|
7
|
+
import './PoolsGraph.scss';
|
8
|
+
|
9
|
+
const b = block('ydb-pools-graph');
|
10
|
+
|
11
|
+
interface PoolsGraphProps {
|
12
|
+
pools?: TPoolStats[];
|
13
|
+
}
|
14
|
+
|
15
|
+
export const PoolsGraph = ({pools = []}: PoolsGraphProps) => {
|
16
|
+
return (
|
17
|
+
<div className={b()}>
|
18
|
+
{pools.map((item, index) => (
|
19
|
+
<PoolBar key={index} data={item} />
|
20
|
+
))}
|
21
|
+
</div>
|
22
|
+
);
|
23
|
+
};
|
@@ -1,12 +1,12 @@
|
|
1
|
-
import {useRef} from 'react';
|
2
1
|
import cn from 'bem-cn-lite';
|
3
2
|
|
4
3
|
import type {TTabletStateInfo} from '../../types/api/tablet';
|
5
|
-
import type {ShowTooltipFunction} from '../../types/store/tooltip';
|
6
4
|
import {getTabletLabel} from '../../utils/constants';
|
7
5
|
import routes, {createHref} from '../../routes';
|
8
6
|
|
7
|
+
import {ContentWithPopup} from '../ContentWithPopup/ContentWithPopup';
|
9
8
|
import {InternalLink} from '../InternalLink';
|
9
|
+
import {TabletTooltipContent} from '../TooltipsContent';
|
10
10
|
|
11
11
|
import './Tablet.scss';
|
12
12
|
|
@@ -14,46 +14,22 @@ const b = cn('tablet');
|
|
14
14
|
|
15
15
|
interface TabletProps {
|
16
16
|
tablet?: TTabletStateInfo;
|
17
|
-
onMouseEnter?: (...args: Parameters<ShowTooltipFunction>) => void;
|
18
|
-
onMouseLeave?: VoidFunction;
|
19
17
|
}
|
20
18
|
|
21
|
-
export const Tablet = ({
|
22
|
-
tablet = {},
|
23
|
-
onMouseEnter = () => {},
|
24
|
-
onMouseLeave = () => {},
|
25
|
-
}: TabletProps) => {
|
26
|
-
const ref = useRef(null);
|
27
|
-
|
28
|
-
const _onTabletMouseEnter = () => {
|
29
|
-
onMouseEnter(ref.current, tablet, 'tablet');
|
30
|
-
};
|
31
|
-
|
32
|
-
const _onTabletClick = () => {
|
33
|
-
const {TabletId: id} = tablet;
|
34
|
-
|
35
|
-
if (id) {
|
36
|
-
onMouseLeave();
|
37
|
-
}
|
38
|
-
};
|
39
|
-
|
19
|
+
export const Tablet = ({tablet = {}}: TabletProps) => {
|
40
20
|
const {TabletId: id} = tablet;
|
41
21
|
const status = tablet.Overall?.toLowerCase();
|
42
22
|
|
43
23
|
return (
|
44
|
-
<
|
45
|
-
onClick={_onTabletClick}
|
46
|
-
to={id && createHref(routes.tablet, {id})}
|
24
|
+
<ContentWithPopup
|
47
25
|
className={b('wrapper')}
|
26
|
+
content={<TabletTooltipContent data={tablet} className={b('popup-content')} />}
|
48
27
|
>
|
49
|
-
<
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
<div className={b('type')}>{[getTabletLabel(tablet.Type)]}</div>
|
56
|
-
</div>
|
57
|
-
</InternalLink>
|
28
|
+
<InternalLink to={id && createHref(routes.tablet, {id})}>
|
29
|
+
<div className={b({status})}>
|
30
|
+
<div className={b('type')}>{[getTabletLabel(tablet.Type)]}</div>
|
31
|
+
</div>
|
32
|
+
</InternalLink>
|
33
|
+
</ContentWithPopup>
|
58
34
|
);
|
59
35
|
};
|
@@ -4,15 +4,15 @@ import type {TSystemStateInfo} from '../../../types/api/nodes';
|
|
4
4
|
|
5
5
|
import {InfoViewer, InfoViewerItem} from '../../InfoViewer';
|
6
6
|
|
7
|
-
import './
|
7
|
+
import './NodeEndpointsTooltipContent.scss';
|
8
8
|
|
9
|
-
const b = block('ydb-node-endpoints-tooltip');
|
9
|
+
const b = block('ydb-node-endpoints-tooltip-content');
|
10
10
|
|
11
11
|
interface NodeEdpointsTooltipProps {
|
12
12
|
data?: TSystemStateInfo;
|
13
13
|
}
|
14
14
|
|
15
|
-
export const
|
15
|
+
export const NodeEndpointsTooltipContent = ({data}: NodeEdpointsTooltipProps) => {
|
16
16
|
const info: InfoViewerItem[] = [];
|
17
17
|
|
18
18
|
if (data?.Rack) {
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import type {TPoolStats} from '../../../types/api/nodes';
|
2
|
+
|
3
|
+
import {InfoViewer, createInfoFormatter, formatObject} from '../../InfoViewer';
|
4
|
+
|
5
|
+
const formatPool = createInfoFormatter<TPoolStats>({
|
6
|
+
values: {
|
7
|
+
Usage: (value) => value && `${(Number(value) * 100).toFixed(2)} %`,
|
8
|
+
},
|
9
|
+
labels: {
|
10
|
+
Name: 'Pool',
|
11
|
+
},
|
12
|
+
defaultValueFormatter: (value) => value && String(value),
|
13
|
+
});
|
14
|
+
|
15
|
+
interface PoolTooltipContentProps {
|
16
|
+
data?: TPoolStats;
|
17
|
+
className?: string;
|
18
|
+
}
|
19
|
+
|
20
|
+
export const PoolTooltipContent = ({data = {}, className}: PoolTooltipContentProps) => {
|
21
|
+
const info = formatObject(formatPool, data);
|
22
|
+
|
23
|
+
return <InfoViewer className={className} info={info} dots={false} size={'s'} />;
|
24
|
+
};
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import type {TTabletStateInfo} from '../../../types/api/tablet';
|
2
|
+
|
3
|
+
import {calcUptime} from '../../../utils';
|
4
|
+
import {InfoViewer, createInfoFormatter, formatObject} from '../../InfoViewer';
|
5
|
+
|
6
|
+
const formatTablet = createInfoFormatter<TTabletStateInfo>({
|
7
|
+
values: {
|
8
|
+
ChangeTime: (value) => calcUptime(value),
|
9
|
+
},
|
10
|
+
labels: {
|
11
|
+
TabletId: 'Tablet',
|
12
|
+
},
|
13
|
+
defaultValueFormatter: (value) => value && String(value),
|
14
|
+
});
|
15
|
+
|
16
|
+
interface TabletTooltipContentProps {
|
17
|
+
data?: TTabletStateInfo;
|
18
|
+
className?: string;
|
19
|
+
}
|
20
|
+
|
21
|
+
export const TabletTooltipContent = ({data = {}, className}: TabletTooltipContentProps) => {
|
22
|
+
const {TabletId, NodeId, State, Type, ChangeTime, Generation} = data;
|
23
|
+
|
24
|
+
const info = formatObject(formatTablet, {
|
25
|
+
TabletId,
|
26
|
+
NodeId,
|
27
|
+
State,
|
28
|
+
Type,
|
29
|
+
ChangeTime,
|
30
|
+
Generation,
|
31
|
+
});
|
32
|
+
|
33
|
+
return <InfoViewer className={className} info={info} dots={false} size={'s'} />;
|
34
|
+
};
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import {useRouteMatch} from 'react-router';
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
|
4
|
-
import type {AdditionalVersionsProps} from '../../types/additionalProps';
|
4
|
+
import type {AdditionalClusterProps, AdditionalVersionsProps} from '../../types/additionalProps';
|
5
5
|
import routes, {CLUSTER_PAGES} from '../../routes';
|
6
6
|
|
7
|
-
import {ClusterInfo} from '
|
7
|
+
import {ClusterInfo} from './ClusterInfo/ClusterInfo';
|
8
8
|
import Tenants from '../Tenants/Tenants';
|
9
9
|
import {Nodes} from '../Nodes/Nodes';
|
10
10
|
import Storage from '../Storage/Storage';
|
@@ -14,32 +14,36 @@ import './Cluster.scss';
|
|
14
14
|
const b = cn('cluster');
|
15
15
|
|
16
16
|
interface ClusterProps {
|
17
|
-
additionalClusterInfo?: any;
|
18
17
|
additionalTenantsInfo?: any;
|
19
18
|
additionalNodesInfo?: any;
|
19
|
+
additionalClusterProps?: AdditionalClusterProps;
|
20
20
|
additionalVersionsProps?: AdditionalVersionsProps;
|
21
21
|
}
|
22
22
|
|
23
|
-
function Cluster(
|
23
|
+
function Cluster({
|
24
|
+
additionalTenantsInfo,
|
25
|
+
additionalNodesInfo,
|
26
|
+
additionalClusterProps,
|
27
|
+
additionalVersionsProps,
|
28
|
+
}: ClusterProps) {
|
24
29
|
const match = useRouteMatch<{activeTab?: string}>(routes.cluster);
|
25
30
|
const activeTab = match?.params?.activeTab ?? CLUSTER_PAGES.tenants.id;
|
26
31
|
const renderRoutes = () => {
|
27
32
|
switch (activeTab) {
|
28
33
|
case CLUSTER_PAGES.tenants.id: {
|
29
|
-
return <Tenants {
|
34
|
+
return <Tenants additionalTenantsInfo={additionalTenantsInfo} />;
|
30
35
|
}
|
31
36
|
case CLUSTER_PAGES.nodes.id: {
|
32
|
-
return <Nodes additionalNodesInfo={
|
37
|
+
return <Nodes additionalNodesInfo={additionalNodesInfo} />;
|
33
38
|
}
|
34
39
|
case CLUSTER_PAGES.storage.id: {
|
35
|
-
|
36
|
-
return <Storage {...props} />;
|
40
|
+
return <Storage additionalNodesInfo={additionalNodesInfo} />;
|
37
41
|
}
|
38
42
|
case CLUSTER_PAGES.cluster.id: {
|
39
43
|
return (
|
40
44
|
<ClusterInfo
|
41
|
-
|
42
|
-
additionalVersionsProps={
|
45
|
+
additionalClusterProps={additionalClusterProps}
|
46
|
+
additionalVersionsProps={additionalVersionsProps}
|
43
47
|
/>
|
44
48
|
);
|
45
49
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
@import '
|
1
|
+
@import '../../../styles/mixins';
|
2
2
|
|
3
3
|
.cluster-info {
|
4
4
|
$_: &;
|
@@ -20,14 +20,7 @@
|
|
20
20
|
background: var(--yc-color-base-background);
|
21
21
|
}
|
22
22
|
|
23
|
-
&
|
24
|
-
display: flex;
|
25
|
-
justify-content: center;
|
26
|
-
|
27
|
-
margin-top: 16px;
|
28
|
-
}
|
29
|
-
|
30
|
-
&__common {
|
23
|
+
&__title {
|
31
24
|
display: flex;
|
32
25
|
align-items: center;
|
33
26
|
|
@@ -35,16 +28,6 @@
|
|
35
28
|
margin-bottom: 20px;
|
36
29
|
}
|
37
30
|
|
38
|
-
&__title {
|
39
|
-
margin-bottom: 15px;
|
40
|
-
|
41
|
-
font-weight: 600;
|
42
|
-
}
|
43
|
-
|
44
|
-
&__url {
|
45
|
-
margin-right: 14px;
|
46
|
-
}
|
47
|
-
|
48
31
|
&__metric-field {
|
49
32
|
margin-top: -8px;
|
50
33
|
}
|
@@ -54,8 +37,6 @@
|
|
54
37
|
flex-wrap: wrap;
|
55
38
|
align-items: center;
|
56
39
|
|
57
|
-
margin-left: 15px;
|
58
|
-
|
59
40
|
& .tablet {
|
60
41
|
margin-bottom: 2px;
|
61
42
|
}
|
@@ -81,31 +62,18 @@
|
|
81
62
|
margin-left: 15px;
|
82
63
|
padding: 0 !important;
|
83
64
|
}
|
84
|
-
&__clipboard-button {
|
85
|
-
display: flex;
|
86
|
-
align-items: center;
|
87
65
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
margin: 0 10px 0 0;
|
66
|
+
&__links {
|
67
|
+
display: flex;
|
68
|
+
flex-flow: row wrap;
|
92
69
|
|
93
|
-
|
70
|
+
gap: 12px;
|
94
71
|
}
|
95
72
|
|
96
|
-
&
|
73
|
+
&__clipboard-button {
|
97
74
|
display: flex;
|
98
75
|
align-items: center;
|
99
76
|
|
100
|
-
|
101
|
-
margin-top: 20px;
|
102
|
-
|
103
|
-
& .yc-progress {
|
104
|
-
width: $progress_width;
|
105
|
-
}
|
106
|
-
}
|
107
|
-
|
108
|
-
& .yc-progress__stack {
|
109
|
-
cursor: pointer;
|
77
|
+
margin-left: 5px;
|
110
78
|
}
|
111
79
|
}
|