ydb-embedded-ui 3.4.4 → 3.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 +31 -0
- package/dist/components/Icon/Icon.tsx +6 -0
- package/dist/components/InfoViewer/InfoViewer.tsx +2 -2
- package/dist/components/InfoViewer/formatters/index.ts +0 -1
- package/dist/components/InfoViewer/formatters/table.ts +6 -0
- package/dist/components/LabelWithPopover/LabelWithPopover.tsx +3 -7
- package/dist/components/LagPopoverContent/LagPopoverContent.scss +13 -0
- package/dist/components/LagPopoverContent/LagPopoverContent.tsx +19 -0
- package/dist/components/LagPopoverContent/index.ts +1 -0
- package/dist/components/Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip.scss +5 -0
- package/dist/components/Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip.tsx +31 -0
- package/dist/components/TruncatedQuery/TruncatedQuery.js +1 -1
- package/dist/components/TruncatedQuery/TruncatedQuery.scss +7 -3
- package/dist/containers/Node/{NodePages.js → NodePages.ts} +1 -1
- package/dist/containers/Nodes/Nodes.tsx +2 -6
- package/dist/containers/Nodes/NodesTable.scss +11 -10
- package/dist/containers/Nodes/getNodesColumns.tsx +29 -24
- package/dist/containers/Storage/PDisk/PDisk.scss +2 -0
- package/dist/containers/Storage/PDiskPopup/PDiskPopup.tsx +6 -9
- package/dist/containers/Storage/Storage.js +12 -5
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +3 -1
- package/dist/containers/Storage/StorageNodes/StorageNodes.scss +20 -7
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +43 -7
- package/dist/containers/Storage/VDisk/VDisk.tsx +3 -2
- package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +4 -2
- package/dist/containers/Tablet/TabletControls/TabletControls.tsx +2 -2
- package/dist/containers/Tenant/Diagnostics/Consumers/Headers/Headers.scss +0 -8
- package/dist/containers/Tenant/Diagnostics/Consumers/Headers/Headers.tsx +3 -10
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/ru.json +1 -1
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +11 -43
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/TableInfo.tsx +19 -17
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +192 -37
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +51 -32
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/en.json +2 -1
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/ru.json +2 -1
- package/dist/containers/Tenant/Diagnostics/Partitions/Headers/Headers.scss +0 -8
- package/dist/containers/Tenant/Diagnostics/Partitions/Headers/Headers.tsx +7 -21
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +20 -14
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +49 -12
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +37 -18
- package/dist/containers/Tenant/QueryEditor/QueryEditor.js +1 -0
- package/dist/routes.ts +1 -1
- package/dist/services/api.d.ts +4 -0
- package/dist/services/api.js +3 -3
- package/dist/store/reducers/{executeQuery.js → executeQuery.ts} +51 -21
- package/dist/store/reducers/executeTopQueries.ts +5 -1
- package/dist/store/reducers/{nodesList.js → nodesList.ts} +19 -7
- package/dist/store/reducers/{olapStats.js → olapStats.ts} +8 -18
- package/dist/store/reducers/settings.js +1 -1
- package/dist/store/reducers/storage.js +8 -18
- package/dist/types/api/nodesList.ts +25 -0
- package/dist/types/api/query.ts +4 -1
- package/dist/types/api/schema.ts +523 -3
- package/dist/types/common.ts +1 -0
- package/dist/types/store/executeQuery.ts +42 -0
- package/dist/types/store/nodesList.ts +24 -0
- package/dist/types/store/olapStats.ts +14 -0
- package/dist/utils/index.js +9 -1
- package/dist/utils/nodes.ts +4 -0
- package/dist/utils/query.test.ts +42 -29
- package/dist/utils/query.ts +34 -22
- package/dist/utils/timeParsers/formatDuration.ts +30 -12
- package/dist/utils/timeParsers/i18n/en.json +4 -0
- package/dist/utils/timeParsers/i18n/ru.json +4 -0
- package/dist/utils/tooltip.js +2 -28
- package/package.json +1 -1
- package/dist/components/InfoViewer/formatters/topicStats.tsx +0 -29
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,36 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [3.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.4.5...v3.5.0) (2023-04-18)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* **TableInfo:** extend Table and ColumnTable info ([89e54aa](https://github.com/ydb-platform/ydb-embedded-ui/commit/89e54aa97d7bcbabfd5100daeb1dc0c03608e86e))
|
9
|
+
* **TopQueries:** add columns ([b49b98d](https://github.com/ydb-platform/ydb-embedded-ui/commit/b49b98db2da08c355b23f4a33bf05247530543db))
|
10
|
+
|
11
|
+
|
12
|
+
### Bug Fixes
|
13
|
+
|
14
|
+
* **settings:** use system theme by default ([726c9cb](https://github.com/ydb-platform/ydb-embedded-ui/commit/726c9cb14d7f87cc9248340d1ebebfc8bf0d0384))
|
15
|
+
* **Storage:** fix incorrect usage on zero available space ([2704cd7](https://github.com/ydb-platform/ydb-embedded-ui/commit/2704cd7c696d337cc8e3af68941cf444f8dfae81))
|
16
|
+
* **TableInfo:** add default format for FollowerGroup fields ([961334a](https://github.com/ydb-platform/ydb-embedded-ui/commit/961334aabe89672994f0f3440e20602e180b3394))
|
17
|
+
* **Tablet:** fix dialog type enum ([c477042](https://github.com/ydb-platform/ydb-embedded-ui/commit/c477042cacc2e777cae4bd6981381a8042c603ed))
|
18
|
+
* **TopQueries:** enable go back to TopQueries from Query tab ([bbdfe72](https://github.com/ydb-platform/ydb-embedded-ui/commit/bbdfe726c9081f01422dca787b83399ea44b3956))
|
19
|
+
* **TopShards:** fix table crash on undefined values ([604e99a](https://github.com/ydb-platform/ydb-embedded-ui/commit/604e99a9427021c61ceb8ea366e316e629032b84))
|
20
|
+
* **TruncatedQuery:** wrap message ([f41b7ff](https://github.com/ydb-platform/ydb-embedded-ui/commit/f41b7ff33ac0145446ca89aab031036247f3ddf8))
|
21
|
+
|
22
|
+
## [3.4.5](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.4.4...v3.4.5) (2023-03-30)
|
23
|
+
|
24
|
+
|
25
|
+
### Bug Fixes
|
26
|
+
|
27
|
+
* **Consumers:** fix typo ([aaa9dbd](https://github.com/ydb-platform/ydb-embedded-ui/commit/aaa9dbda1f28702917793a61bae2813f6ef018bb))
|
28
|
+
* **PDisk:** add display block to content ([130dab2](https://github.com/ydb-platform/ydb-embedded-ui/commit/130dab20ffdc9da77225c94a6e6064f0308a1c2a))
|
29
|
+
* **Storage:** get nodes hosts from /nodelist ([cc82dd9](https://github.com/ydb-platform/ydb-embedded-ui/commit/cc82dd93808133b0d1dcd21b31ee3744df4f7383))
|
30
|
+
* **StorageNodes:** make fqdn similar to nodes page ([344298a](https://github.com/ydb-platform/ydb-embedded-ui/commit/344298a9a29380f1068b002fa304cdcc221ce0d4))
|
31
|
+
* **TopicInfo:** do not display /s when speed is undefined ([2d41832](https://github.com/ydb-platform/ydb-embedded-ui/commit/2d4183247ec33acdfa45be72a93f0dbd93b716e0))
|
32
|
+
* **TopicStats:** use prepared stats, update fields ([a614a8c](https://github.com/ydb-platform/ydb-embedded-ui/commit/a614a8caa2744b844d97f23f25e5385387367d6b))
|
33
|
+
|
3
34
|
## [3.4.4](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.4.3...v3.4.4) (2023-03-22)
|
4
35
|
|
5
36
|
|
@@ -31,3 +31,9 @@ export const Icon = ({
|
|
31
31
|
/>
|
32
32
|
);
|
33
33
|
};
|
34
|
+
|
35
|
+
// When used with uikit components Icon is considered as text element and corresponding styles are applied
|
36
|
+
// IconWrapper overrides displayName to 'Icon', so it will be considered as an icon with right styles
|
37
|
+
export const IconWrapper = (props: IconProps) => <Icon {...props} />;
|
38
|
+
|
39
|
+
IconWrapper.displayName = 'Icon';
|
@@ -4,7 +4,7 @@ import cn from 'bem-cn-lite';
|
|
4
4
|
import './InfoViewer.scss';
|
5
5
|
|
6
6
|
export interface InfoViewerItem {
|
7
|
-
label:
|
7
|
+
label: ReactNode;
|
8
8
|
value: ReactNode;
|
9
9
|
}
|
10
10
|
|
@@ -39,7 +39,7 @@ const InfoViewer = ({
|
|
39
39
|
{info && info.length > 0 ? (
|
40
40
|
<div className={b('items')}>
|
41
41
|
{info.map((data, infoIndex) => (
|
42
|
-
<div className={b('row')} key={
|
42
|
+
<div className={b('row')} key={infoIndex}>
|
43
43
|
<div className={b('label')}>
|
44
44
|
<div className={b('label-text', {multiline: multilineLabels})}>
|
45
45
|
{data.label}
|
@@ -20,6 +20,12 @@ export const formatFollowerGroupItem = createInfoFormatter<TFollowerGroup>({
|
|
20
20
|
values: {
|
21
21
|
FollowerCount: formatNumber,
|
22
22
|
},
|
23
|
+
labels: {
|
24
|
+
// Make it shorter to fit label width
|
25
|
+
FollowerCountPerDataCenter: 'FollowerCountPerDC',
|
26
|
+
},
|
27
|
+
// Most of the FollowerGroup fields are arrays or boolean
|
28
|
+
defaultValueFormatter: (value) => value && String(value),
|
23
29
|
});
|
24
30
|
|
25
31
|
export const formatPartitionConfigItem = createInfoFormatter<TPartitionConfig>({
|
@@ -3,18 +3,14 @@ import type {ReactNode} from 'react';
|
|
3
3
|
import {HelpPopover} from '@gravity-ui/uikit';
|
4
4
|
|
5
5
|
interface LabelWithPopoverProps {
|
6
|
-
|
6
|
+
text: string;
|
7
7
|
popoverContent: ReactNode;
|
8
8
|
className?: string;
|
9
9
|
}
|
10
10
|
|
11
|
-
export const LabelWithPopover = ({
|
12
|
-
headerText,
|
13
|
-
popoverContent,
|
14
|
-
className,
|
15
|
-
}: LabelWithPopoverProps) => (
|
11
|
+
export const LabelWithPopover = ({text, popoverContent, className}: LabelWithPopoverProps) => (
|
16
12
|
<div className={className}>
|
17
|
-
{
|
13
|
+
{text}
|
18
14
|
<HelpPopover content={popoverContent} />
|
19
15
|
</div>
|
20
16
|
);
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import block from 'bem-cn-lite';
|
2
|
+
|
3
|
+
import {ReadLagImage, WriteLagImage} from '../LagImages';
|
4
|
+
|
5
|
+
import './LagPopoverContent.scss';
|
6
|
+
|
7
|
+
const b = block('ydb-lag-popover-content');
|
8
|
+
|
9
|
+
interface LagPopoverContentProps {
|
10
|
+
text: string;
|
11
|
+
type: 'read' | 'write';
|
12
|
+
}
|
13
|
+
|
14
|
+
export const LagPopoverContent = ({text, type}: LagPopoverContentProps) => (
|
15
|
+
<div className={b({type})}>
|
16
|
+
<div className={b('text')}>{text}</div>
|
17
|
+
<div>{type === 'read' ? <ReadLagImage /> : <WriteLagImage />}</div>
|
18
|
+
</div>
|
19
|
+
);
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './LagPopoverContent';
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import block from 'bem-cn-lite';
|
2
|
+
|
3
|
+
import type {TSystemStateInfo} from '../../../types/api/nodes';
|
4
|
+
|
5
|
+
import {InfoViewer, InfoViewerItem} from '../../InfoViewer';
|
6
|
+
|
7
|
+
import './NodeEndpointsTooltip.scss';
|
8
|
+
|
9
|
+
const b = block('ydb-node-endpoints-tooltip');
|
10
|
+
|
11
|
+
interface NodeEdpointsTooltipProps {
|
12
|
+
data?: TSystemStateInfo;
|
13
|
+
}
|
14
|
+
|
15
|
+
export const NodeEndpointsTooltip = ({data}: NodeEdpointsTooltipProps) => {
|
16
|
+
const info: InfoViewerItem[] = [];
|
17
|
+
|
18
|
+
if (data?.Rack) {
|
19
|
+
info.push({label: 'Rack', value: data.Rack});
|
20
|
+
}
|
21
|
+
|
22
|
+
if (data?.Endpoints && data.Endpoints.length) {
|
23
|
+
data.Endpoints.forEach(({Name, Address}) => {
|
24
|
+
if (Name && Address) {
|
25
|
+
info.push({label: Name, value: Address});
|
26
|
+
}
|
27
|
+
});
|
28
|
+
}
|
29
|
+
|
30
|
+
return <InfoViewer className={b(null)} info={info} dots={false} size={'s'} />;
|
31
|
+
};
|
@@ -16,7 +16,7 @@ function TruncatedQuery({value, maxQueryHeight}) {
|
|
16
16
|
return (
|
17
17
|
<React.Fragment>
|
18
18
|
<span className={b()}>{content}</span>
|
19
|
-
<span className={b({color: 'secondary'})}>{message}</span>
|
19
|
+
<span className={b('message', {color: 'secondary'})}>{message}</span>
|
20
20
|
</React.Fragment>
|
21
21
|
);
|
22
22
|
}
|
@@ -5,9 +5,13 @@
|
|
5
5
|
white-space: pre;
|
6
6
|
word-break: break-word;
|
7
7
|
|
8
|
-
&
|
9
|
-
|
10
|
-
|
8
|
+
&__message {
|
9
|
+
white-space: pre-wrap;
|
10
|
+
|
11
|
+
&_color {
|
12
|
+
&_secondary {
|
13
|
+
color: var(--yc-color-text-secondary);
|
14
|
+
}
|
11
15
|
}
|
12
16
|
}
|
13
17
|
}
|
@@ -22,7 +22,7 @@ import {
|
|
22
22
|
USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
|
23
23
|
} from '../../utils/constants';
|
24
24
|
import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
|
25
|
-
import {isUnavailableNode, NodesUptimeFilterValues} from '../../utils/nodes';
|
25
|
+
import {AdditionalNodesInfo, isUnavailableNode, NodesUptimeFilterValues} from '../../utils/nodes';
|
26
26
|
|
27
27
|
import {setHeader} from '../../store/reducers/header';
|
28
28
|
import {
|
@@ -46,15 +46,11 @@ import i18n from './i18n';
|
|
46
46
|
|
47
47
|
const b = cn('ydb-nodes');
|
48
48
|
|
49
|
-
interface IAdditionalNodesInfo extends Record<string, unknown> {
|
50
|
-
getNodeRef?: Function;
|
51
|
-
}
|
52
|
-
|
53
49
|
interface NodesProps {
|
54
50
|
path?: string;
|
55
51
|
type?: EPathType;
|
56
52
|
className?: string;
|
57
|
-
additionalNodesInfo?:
|
53
|
+
additionalNodesInfo?: AdditionalNodesInfo;
|
58
54
|
}
|
59
55
|
|
60
56
|
export const Nodes = ({path, type, className, additionalNodesInfo = {}}: NodesProps) => {
|
@@ -1,22 +1,23 @@
|
|
1
1
|
.ydb-nodes-table {
|
2
|
-
&__host-
|
2
|
+
&__host-field-wrapper {
|
3
3
|
display: flex;
|
4
4
|
}
|
5
5
|
|
6
|
-
&
|
7
|
-
display:
|
8
|
-
align-items: center;
|
9
|
-
|
10
|
-
margin-left: 4px;
|
6
|
+
&__host-wrapper {
|
7
|
+
display: flex;
|
11
8
|
|
12
|
-
|
13
|
-
margin: 0 4px;
|
14
|
-
}
|
9
|
+
max-width: 330px;
|
15
10
|
}
|
16
11
|
|
17
|
-
&__host
|
12
|
+
&__host {
|
18
13
|
overflow: hidden;
|
19
14
|
}
|
15
|
+
|
16
|
+
&__external-button {
|
17
|
+
display: none;
|
18
|
+
|
19
|
+
margin-left: 4px;
|
20
|
+
}
|
20
21
|
}
|
21
22
|
|
22
23
|
.data-table__row:hover {
|
@@ -1,12 +1,13 @@
|
|
1
1
|
import cn from 'bem-cn-lite';
|
2
2
|
import DataTable, {Column} from '@gravity-ui/react-data-table';
|
3
|
-
import {Button, Popover} from '@gravity-ui/uikit';
|
3
|
+
import {Button, Popover, PopoverBehavior} from '@gravity-ui/uikit';
|
4
4
|
|
5
|
-
import {
|
5
|
+
import {IconWrapper} from '../../components/Icon';
|
6
6
|
import EntityStatus from '../../components/EntityStatus/EntityStatus';
|
7
7
|
import PoolsGraph from '../../components/PoolsGraph/PoolsGraph';
|
8
8
|
import ProgressViewer from '../../components/ProgressViewer/ProgressViewer';
|
9
9
|
import {TabletsStatistic} from '../../components/TabletsStatistic';
|
10
|
+
import {NodeEndpointsTooltip} from '../../components/Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip';
|
10
11
|
|
11
12
|
import {formatBytesToGigabyte} from '../../utils/index';
|
12
13
|
import {INodesPreparedEntity} from '../../types/store/nodes';
|
@@ -46,28 +47,32 @@ export function getNodesColumns({
|
|
46
47
|
return <span>—</span>;
|
47
48
|
}
|
48
49
|
return (
|
49
|
-
<div className={b('host-
|
50
|
-
<
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
50
|
+
<div className={b('host-field-wrapper')}>
|
51
|
+
<Popover
|
52
|
+
content={<NodeEndpointsTooltip data={row} />}
|
53
|
+
placement={['top', 'bottom']}
|
54
|
+
behavior={PopoverBehavior.Immediate}
|
55
|
+
>
|
56
|
+
<div className={b('host-wrapper')}>
|
57
|
+
<EntityStatus
|
58
|
+
name={row.Host}
|
59
|
+
status={row.SystemState}
|
60
|
+
path={getDefaultNodePath(row.NodeId)}
|
61
|
+
hasClipboardButton
|
62
|
+
className={b('host')}
|
63
|
+
/>
|
64
|
+
{nodeRef && (
|
65
|
+
<Button
|
66
|
+
size="s"
|
67
|
+
href={nodeRef}
|
68
|
+
className={b('external-button')}
|
69
|
+
target="_blank"
|
70
|
+
>
|
71
|
+
<IconWrapper name="external" />
|
72
|
+
</Button>
|
73
|
+
)}
|
74
|
+
</div>
|
75
|
+
</Popover>
|
71
76
|
</div>
|
72
77
|
);
|
73
78
|
},
|
@@ -3,6 +3,8 @@ import cn from 'bem-cn-lite';
|
|
3
3
|
|
4
4
|
import {Popup, PopupProps} from '@gravity-ui/uikit';
|
5
5
|
|
6
|
+
import type {NodesMap} from '../../../types/store/nodesList';
|
7
|
+
|
6
8
|
import {InfoViewer, InfoViewerItem} from '../../../components/InfoViewer';
|
7
9
|
|
8
10
|
import {EFlag} from '../../../types/api/enums';
|
@@ -17,12 +19,7 @@ const b = cn('pdisk-storage-popup');
|
|
17
19
|
|
18
20
|
const errorColors = [EFlag.Orange, EFlag.Red, EFlag.Yellow];
|
19
21
|
|
20
|
-
export
|
21
|
-
// NodeId => Host
|
22
|
-
[nodeId: number]: string;
|
23
|
-
}
|
24
|
-
|
25
|
-
export const preparePDiskData = (data: TPDiskStateInfo, nodes?: NodesHosts) => {
|
22
|
+
export const preparePDiskData = (data: TPDiskStateInfo, nodes?: NodesMap) => {
|
26
23
|
const {AvailableSize, TotalSize, State, PDiskId, NodeId, Path, Realtime, Device} = data;
|
27
24
|
|
28
25
|
const pdiskData: InfoViewerItem[] = [
|
@@ -35,8 +32,8 @@ export const preparePDiskData = (data: TPDiskStateInfo, nodes?: NodesHosts) => {
|
|
35
32
|
pdiskData.push({label: 'Node Id', value: NodeId});
|
36
33
|
}
|
37
34
|
|
38
|
-
if (nodes && NodeId && nodes
|
39
|
-
pdiskData.push({label: 'Host', value: nodes
|
35
|
+
if (nodes && NodeId && nodes.get(NodeId)) {
|
36
|
+
pdiskData.push({label: 'Host', value: nodes.get(NodeId)});
|
40
37
|
}
|
41
38
|
|
42
39
|
if (Path) {
|
@@ -61,7 +58,7 @@ export const preparePDiskData = (data: TPDiskStateInfo, nodes?: NodesHosts) => {
|
|
61
58
|
|
62
59
|
interface PDiskPopupProps extends PopupProps {
|
63
60
|
data: TPDiskStateInfo;
|
64
|
-
nodes?:
|
61
|
+
nodes?: NodesMap;
|
65
62
|
}
|
66
63
|
|
67
64
|
export const PDiskPopup = ({data, nodes, ...props}: PDiskPopupProps) => {
|
@@ -22,7 +22,6 @@ import {
|
|
22
22
|
setVisibleEntities,
|
23
23
|
setStorageFilter,
|
24
24
|
setUsageFilter,
|
25
|
-
getNodesObject,
|
26
25
|
StorageTypes,
|
27
26
|
setStorageType,
|
28
27
|
setNodesUptimeFilter,
|
@@ -32,7 +31,7 @@ import {
|
|
32
31
|
getStorageNodesCount,
|
33
32
|
getUsageFilterOptions,
|
34
33
|
} from '../../store/reducers/storage';
|
35
|
-
import {getNodesList} from '../../store/reducers/nodesList';
|
34
|
+
import {getNodesList, selectNodesMap} from '../../store/reducers/nodesList';
|
36
35
|
import StorageGroups from './StorageGroups/StorageGroups';
|
37
36
|
import StorageNodes from './StorageNodes/StorageNodes';
|
38
37
|
import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
|
@@ -74,6 +73,7 @@ class Storage extends React.Component {
|
|
74
73
|
nodesUptimeFilter: PropTypes.string,
|
75
74
|
setNodesUptimeFilter: PropTypes.func,
|
76
75
|
setDataWasNotLoaded: PropTypes.func,
|
76
|
+
additionalNodesInfo: PropTypes.object,
|
77
77
|
};
|
78
78
|
|
79
79
|
componentDidMount() {
|
@@ -181,8 +181,14 @@ class Storage extends React.Component {
|
|
181
181
|
}
|
182
182
|
|
183
183
|
renderDataTable() {
|
184
|
-
const {
|
185
|
-
|
184
|
+
const {
|
185
|
+
flatListStorageEntities,
|
186
|
+
visibleEntities,
|
187
|
+
nodesUptimeFilter,
|
188
|
+
nodes,
|
189
|
+
storageType,
|
190
|
+
additionalNodesInfo,
|
191
|
+
} = this.props;
|
186
192
|
|
187
193
|
return (
|
188
194
|
<div className={b('table-wrapper')}>
|
@@ -202,6 +208,7 @@ class Storage extends React.Component {
|
|
202
208
|
data={flatListStorageEntities}
|
203
209
|
tableSettings={tableSettings}
|
204
210
|
onShowAll={this.onShowAllNodes}
|
211
|
+
additionalNodesInfo={additionalNodesInfo}
|
205
212
|
/>
|
206
213
|
)}
|
207
214
|
</div>
|
@@ -345,7 +352,7 @@ function mapStateToProps(state) {
|
|
345
352
|
flatListStorageEntities: getFilteredEntities(state),
|
346
353
|
groupsCount: getStoragePoolsGroupsCount(state),
|
347
354
|
autorefresh: state.schema.autorefresh,
|
348
|
-
nodes:
|
355
|
+
nodes: selectNodesMap(state),
|
349
356
|
nodesCount: getStorageNodesCount(state),
|
350
357
|
loading,
|
351
358
|
wasLoaded,
|
@@ -3,6 +3,8 @@ import cn from 'bem-cn-lite';
|
|
3
3
|
import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
|
4
4
|
import {Icon, Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
|
5
5
|
|
6
|
+
import type {NodesMap} from '../../../types/store/nodesList';
|
7
|
+
|
6
8
|
import shieldIcon from '../../../assets/icons/shield.svg';
|
7
9
|
|
8
10
|
import {Stack} from '../../../components/Stack/Stack';
|
@@ -45,7 +47,7 @@ type TableColumnsIdsValues = typeof TableColumnsIds[TableColumnsIdsKeys];
|
|
45
47
|
|
46
48
|
interface StorageGroupsProps {
|
47
49
|
data: any;
|
48
|
-
nodes:
|
50
|
+
nodes: NodesMap;
|
49
51
|
tableSettings: Settings;
|
50
52
|
visibleEntities: keyof typeof VisibleEntities;
|
51
53
|
onShowAll?: VoidFunction;
|
@@ -20,18 +20,19 @@
|
|
20
20
|
margin-right: 0px;
|
21
21
|
}
|
22
22
|
}
|
23
|
-
&__fqdn-wrapper {
|
23
|
+
&__fqdn-field-wrapper {
|
24
24
|
width: 330px;
|
25
25
|
}
|
26
|
-
&__fqdn {
|
27
|
-
display:
|
28
|
-
|
26
|
+
&__fqdn-wrapper {
|
27
|
+
display: flex;
|
28
|
+
align-items: center;
|
29
29
|
|
30
30
|
max-width: 330px;
|
31
|
-
|
32
|
-
vertical-align: top;
|
33
|
-
text-overflow: ellipsis;
|
34
31
|
}
|
32
|
+
&__fqdn {
|
33
|
+
overflow: hidden;
|
34
|
+
}
|
35
|
+
|
35
36
|
&__group-id {
|
36
37
|
font-weight: 500;
|
37
38
|
}
|
@@ -39,4 +40,16 @@
|
|
39
40
|
&__node_unavailable {
|
40
41
|
opacity: 0.6;
|
41
42
|
}
|
43
|
+
|
44
|
+
&__external-button {
|
45
|
+
display: none;
|
46
|
+
|
47
|
+
margin-left: 4px;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
.data-table__row:hover {
|
52
|
+
.global-storage-nodes__external-button {
|
53
|
+
display: inline-flex;
|
54
|
+
}
|
42
55
|
}
|
@@ -2,10 +2,20 @@ import _ from 'lodash';
|
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
|
4
4
|
import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
|
5
|
-
import {Popover, PopoverBehavior} from '@gravity-ui/uikit';
|
5
|
+
import {Button, Popover, PopoverBehavior} from '@gravity-ui/uikit';
|
6
|
+
|
7
|
+
import {NodeEndpointsTooltip} from '../../../components/Tooltips/NodeEndpointsTooltip/NodeEndpointsTooltip';
|
8
|
+
import EntityStatus from '../../../components/EntityStatus/EntityStatus';
|
9
|
+
import {IconWrapper} from '../../../components/Icon';
|
6
10
|
|
7
11
|
import {VisibleEntities} from '../../../store/reducers/storage';
|
8
|
-
import {
|
12
|
+
import {
|
13
|
+
AdditionalNodesInfo,
|
14
|
+
isUnavailableNode,
|
15
|
+
NodesUptimeFilterValues,
|
16
|
+
} from '../../../utils/nodes';
|
17
|
+
|
18
|
+
import {getDefaultNodePath} from '../../Node/NodePages';
|
9
19
|
|
10
20
|
import {EmptyFilter} from '../EmptyFilter/EmptyFilter';
|
11
21
|
import {PDisk} from '../PDisk';
|
@@ -33,6 +43,7 @@ interface StorageNodesProps {
|
|
33
43
|
visibleEntities: keyof typeof VisibleEntities;
|
34
44
|
nodesUptimeFilter: keyof typeof NodesUptimeFilterValues;
|
35
45
|
onShowAll?: VoidFunction;
|
46
|
+
additionalNodesInfo?: AdditionalNodesInfo;
|
36
47
|
}
|
37
48
|
|
38
49
|
const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
|
@@ -73,7 +84,10 @@ function StorageNodes({
|
|
73
84
|
visibleEntities,
|
74
85
|
onShowAll,
|
75
86
|
nodesUptimeFilter,
|
87
|
+
additionalNodesInfo,
|
76
88
|
}: StorageNodesProps) {
|
89
|
+
const getNodeRef = additionalNodesInfo?.getNodeRef;
|
90
|
+
|
77
91
|
const allColumns: Column<any>[] = [
|
78
92
|
{
|
79
93
|
name: TableColumnsIds.NodeId,
|
@@ -85,15 +99,37 @@ function StorageNodes({
|
|
85
99
|
name: TableColumnsIds.FQDN,
|
86
100
|
header: tableColumnsNames[TableColumnsIds.FQDN],
|
87
101
|
width: 350,
|
88
|
-
render: ({
|
102
|
+
render: ({row}) => {
|
103
|
+
const nodeRef = getNodeRef ? getNodeRef(row) + 'internal' : undefined;
|
104
|
+
if (!row.Host) {
|
105
|
+
return <span>—</span>;
|
106
|
+
}
|
89
107
|
return (
|
90
|
-
<div className={b('fqdn-wrapper')}>
|
108
|
+
<div className={b('fqdn-field-wrapper')}>
|
91
109
|
<Popover
|
92
|
-
content={
|
93
|
-
placement={['
|
110
|
+
content={<NodeEndpointsTooltip data={row} />}
|
111
|
+
placement={['top', 'bottom']}
|
94
112
|
behavior={PopoverBehavior.Immediate}
|
95
113
|
>
|
96
|
-
<
|
114
|
+
<div className={b('fqdn-wrapper')}>
|
115
|
+
<EntityStatus
|
116
|
+
name={row.Host}
|
117
|
+
showStatus={false}
|
118
|
+
path={getDefaultNodePath(row.NodeId)}
|
119
|
+
hasClipboardButton
|
120
|
+
className={b('fqdn')}
|
121
|
+
/>
|
122
|
+
{nodeRef && (
|
123
|
+
<Button
|
124
|
+
size="s"
|
125
|
+
href={nodeRef}
|
126
|
+
className={b('external-button')}
|
127
|
+
target="_blank"
|
128
|
+
>
|
129
|
+
<IconWrapper name="external" />
|
130
|
+
</Button>
|
131
|
+
)}
|
132
|
+
</div>
|
97
133
|
</Popover>
|
98
134
|
</div>
|
99
135
|
);
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import React, {useEffect, useState, useRef, useMemo} from 'react';
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
|
4
|
+
import type {NodesMap} from '../../../types/store/nodesList';
|
5
|
+
|
4
6
|
import {InternalLink} from '../../../components/InternalLink';
|
5
7
|
|
6
8
|
import routes, {createHref} from '../../../routes';
|
@@ -12,7 +14,6 @@ import {isFullVDiskData} from '../../../utils/storage';
|
|
12
14
|
import {STRUCTURE} from '../../Node/NodePages';
|
13
15
|
|
14
16
|
import {DiskStateProgressBar, EDiskStateSeverity} from '../DiskStateProgressBar';
|
15
|
-
import type {NodesHosts} from '../PDiskPopup';
|
16
17
|
import {VDiskPopup} from '../VDiskPopup';
|
17
18
|
|
18
19
|
import type {IUnavailableDonor} from '../utils/types';
|
@@ -50,7 +51,7 @@ const getColorSeverity = (color?: EFlag) => {
|
|
50
51
|
interface VDiskProps {
|
51
52
|
data?: TVDiskStateInfo | IUnavailableDonor;
|
52
53
|
poolName?: string;
|
53
|
-
nodes?:
|
54
|
+
nodes?: NodesMap;
|
54
55
|
compact?: boolean;
|
55
56
|
}
|
56
57
|
|