Skip to content

Commit 21de77f

Browse files
authored
feat: add new popup menu icon (#2045)
1 parent 1521580 commit 21de77f

File tree

6 files changed

+137
-71
lines changed

6 files changed

+137
-71
lines changed

src/components/EntityStatus/EntityStatus.scss

+35-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
margin-right: var(--g-spacing-2);
1717
}
1818

19+
&__info-icon,
1920
&__clipboard-button {
2021
color: var(--g-color-text-secondary);
2122

@@ -26,14 +27,30 @@
2627
}
2728
}
2829

30+
&__info-icon {
31+
&:hover {
32+
color: var(--g-color-text-primary);
33+
}
34+
}
35+
2936
&__wrapper {
3037
position: relative;
3138

3239
overflow: hidden;
3340

34-
&_with-button {
41+
&_with-clipboard-button {
42+
padding-right: var(--button-width);
43+
}
44+
45+
&_with-info-button {
3546
padding-right: var(--button-width);
3647
}
48+
49+
&_with-clipboard-button {
50+
&.entity-status__wrapper_with-info-button {
51+
padding-right: calc(2 * var(--button-width));
52+
}
53+
}
3754
}
3855

3956
&__controls-wrapper {
@@ -51,6 +68,8 @@
5168
&_visible {
5269
width: min-content;
5370
padding: var(--g-spacing-1);
71+
72+
background-color: var(--g-color-base-background);
5473
}
5574

5675
.data-table__row:hover &,
@@ -79,13 +98,27 @@
7998
display: inline-block;
8099
overflow: hidden;
81100

82-
width: calc(100% + var(--button-width));
101+
width: 100%;
83102
margin-top: 5px;
84103

85104
white-space: nowrap;
86105
text-overflow: ellipsis;
87106
}
88107

108+
&__wrapper_with-clipboard-button &__link {
109+
width: calc(100% + var(--button-width));
110+
}
111+
112+
&__wrapper_with-info-button &__link {
113+
width: calc(100% + var(--button-width));
114+
}
115+
116+
&__wrapper_with-clipboard-button {
117+
&.entity-status__wrapper_with-info-button .entity-status__link {
118+
width: calc(100% + 2 * var(--button-width));
119+
}
120+
}
121+
89122
&__link_with-left-trim {
90123
text-align: end;
91124
direction: rtl;

src/components/EntityStatus/EntityStatus.tsx

+46-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import {ClipboardButton, Link as UIKitLink} from '@gravity-ui/uikit';
1+
import React from 'react';
2+
3+
import {CircleInfo} from '@gravity-ui/icons';
4+
import {Button, ClipboardButton, Icon, Popover, Link as UIKitLink} from '@gravity-ui/uikit';
25

36
import {EFlag} from '../../types/api/enums';
47
import {cn} from '../../utils/cn';
@@ -25,6 +28,7 @@ interface EntityStatusProps {
2528
withLeftTrim?: boolean;
2629

2730
hasClipboardButton?: boolean;
31+
infoPopoverContent?: React.ReactNode;
2832
clipboardButtonAlwaysVisible?: boolean;
2933

3034
className?: string;
@@ -45,10 +49,13 @@ export function EntityStatus({
4549
withLeftTrim = false,
4650

4751
hasClipboardButton,
52+
infoPopoverContent,
4853
clipboardButtonAlwaysVisible = false,
4954

5055
className,
5156
}: EntityStatusProps) {
57+
const [infoIconHovered, setInfoIconHovered] = React.useState(false);
58+
5259
const renderIcon = () => {
5360
if (!showStatus) {
5461
return null;
@@ -90,24 +97,51 @@ export function EntityStatus({
9097
</span>
9198
)}
9299
{(path || name) && (
93-
<div className={b('wrapper', {'with-button': hasClipboardButton})}>
100+
<div
101+
className={b('wrapper', {
102+
'with-clipboard-button': hasClipboardButton,
103+
'with-info-button': Boolean(infoPopoverContent),
104+
})}
105+
>
94106
<span className={b('link', {'with-left-trim': withLeftTrim})} title={name}>
95107
{renderLink()}
96108
</span>
97-
{hasClipboardButton && (
109+
{(hasClipboardButton || infoPopoverContent) && (
98110
<div
99111
className={b('controls-wrapper', {
100-
visible: clipboardButtonAlwaysVisible,
112+
visible: clipboardButtonAlwaysVisible || infoIconHovered,
101113
})}
102114
>
103-
<ClipboardButton
104-
text={name}
105-
size="xs"
106-
view="normal"
107-
className={b('clipboard-button', {
108-
visible: clipboardButtonAlwaysVisible,
109-
})}
110-
/>
115+
{infoPopoverContent && (
116+
<Popover
117+
className={b('info-popover')}
118+
content={infoPopoverContent}
119+
tooltipOffset={[-4, 4]}
120+
placement={['top-start', 'bottom-start']}
121+
onOpenChange={(visible) => setInfoIconHovered(visible)}
122+
>
123+
<Button view="normal" size="xs">
124+
<Icon
125+
data={CircleInfo}
126+
size="12"
127+
className={b('info-icon', {
128+
visible:
129+
clipboardButtonAlwaysVisible || infoIconHovered,
130+
})}
131+
/>
132+
</Button>
133+
</Popover>
134+
)}
135+
{hasClipboardButton && (
136+
<ClipboardButton
137+
text={name}
138+
size="xs"
139+
view="normal"
140+
className={b('clipboard-button', {
141+
visible: clipboardButtonAlwaysVisible || infoIconHovered,
142+
})}
143+
/>
144+
)}
111145
</div>
112146
)}
113147
</div>

src/components/NodeHostWrapper/NodeHostWrapper.tsx

+11-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import {PopoverBehavior} from '@gravity-ui/uikit';
2-
31
import {getDefaultNodePath} from '../../containers/Node/NodePages';
42
import type {GetNodeRefFunc, NodeAddress} from '../../types/additionalProps';
53
import type {TNodeInfo, TSystemStateInfo} from '../../types/api/nodes';
@@ -8,7 +6,6 @@ import {
86
createDeveloperUILinkWithNodeId,
97
} from '../../utils/developerUI/developerUI';
108
import {isUnavailableNode} from '../../utils/nodes';
11-
import {CellWithPopover} from '../CellWithPopover/CellWithPopover';
129
import {EntityStatus} from '../EntityStatus/EntityStatus';
1310
import {NodeEndpointsTooltipContent} from '../TooltipsContent';
1411

@@ -64,14 +61,16 @@ export const NodeHostWrapper = ({
6461
: undefined;
6562

6663
return (
67-
<CellWithPopover
68-
disabled={!isNodeAvailable}
69-
content={<NodeEndpointsTooltipContent data={node} nodeHref={developerUIInternalHref} />}
70-
placement={['top', 'bottom']}
71-
behavior={PopoverBehavior.Immediate}
72-
delayClosing={200}
73-
>
74-
<EntityStatus name={node.Host} status={status} path={nodePath} hasClipboardButton />
75-
</CellWithPopover>
64+
<EntityStatus
65+
name={node.Host}
66+
status={status}
67+
path={nodePath}
68+
hasClipboardButton
69+
infoPopoverContent={
70+
isNodeAvailable ? (
71+
<NodeEndpointsTooltipContent data={node} nodeHref={developerUIInternalHref} />
72+
) : null
73+
}
74+
/>
7675
);
7776
};
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import {DefinitionList, Flex, PopoverBehavior} from '@gravity-ui/uikit';
1+
import {DefinitionList, Flex} from '@gravity-ui/uikit';
22

33
import {getTenantPath} from '../../containers/Tenant/TenantPages';
44
import type {PreparedTenant} from '../../store/reducers/tenants/types';
55
import type {AdditionalTenantsProps, NodeAddress} from '../../types/additionalProps';
66
import {useIsUserAllowedToMakeChanges} from '../../utils/hooks/useIsUserAllowedToMakeChanges';
7-
import {CellWithPopover} from '../CellWithPopover/CellWithPopover';
87
import {EntityStatus} from '../EntityStatus/EntityStatus';
98
import {LinkWithIcon} from '../LinkWithIcon/LinkWithIcon';
109

@@ -41,43 +40,37 @@ export function TenantNameWrapper({tenant, additionalTenantsProps}: TenantNameWr
4140
const monitoringLink = additionalTenantsProps?.getMonitoringLink?.(tenant.Name, tenant.Type);
4241
const logsLink = additionalTenantsProps?.getLogsLink?.(tenant.Name);
4342

43+
const infoPopoverContent =
44+
(monitoringLink || logsLink) && isUserAllowedToMakeChanges ? (
45+
<DefinitionList responsive>
46+
<DefinitionList.Item name={i18n('field_links')}>
47+
<Flex gap={2} wrap="wrap">
48+
{monitoringLink && (
49+
<LinkWithIcon
50+
title={i18n('field_monitoring-link')}
51+
url={monitoringLink}
52+
/>
53+
)}
54+
{logsLink && (
55+
<LinkWithIcon title={i18n('field_logs-link')} url={logsLink} />
56+
)}
57+
</Flex>
58+
</DefinitionList.Item>
59+
</DefinitionList>
60+
) : null;
61+
4462
return (
45-
<CellWithPopover
46-
disabled={!isUserAllowedToMakeChanges || (!monitoringLink && !logsLink)}
47-
delayClosing={200}
48-
content={
49-
monitoringLink || logsLink ? (
50-
<DefinitionList responsive>
51-
<DefinitionList.Item name={i18n('field_links')}>
52-
<Flex gap={2} wrap="wrap">
53-
{monitoringLink && (
54-
<LinkWithIcon
55-
title={i18n('field_monitoring-link')}
56-
url={monitoringLink}
57-
/>
58-
)}
59-
{logsLink && (
60-
<LinkWithIcon title={i18n('field_logs-link')} url={logsLink} />
61-
)}
62-
</Flex>
63-
</DefinitionList.Item>
64-
</DefinitionList>
65-
) : null
66-
}
67-
placement={['top', 'bottom']}
68-
behavior={PopoverBehavior.Immediate}
69-
>
70-
<EntityStatus
71-
externalLink={isExternalLink}
72-
name={tenant.Name || i18n('context_unknown')}
73-
withLeftTrim={true}
74-
status={tenant.Overall}
75-
hasClipboardButton
76-
path={getTenantPath({
77-
database: tenant.Name,
78-
backend,
79-
})}
80-
/>
81-
</CellWithPopover>
63+
<EntityStatus
64+
externalLink={isExternalLink}
65+
name={tenant.Name || i18n('context_unknown')}
66+
withLeftTrim={true}
67+
status={tenant.Overall}
68+
infoPopoverContent={infoPopoverContent}
69+
hasClipboardButton
70+
path={getTenantPath({
71+
database: tenant.Name,
72+
backend,
73+
})}
74+
/>
8275
);
8376
}

src/containers/Storage/StorageGroups/columns/StorageGroupsColumns.scss

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@use '../../../../styles/mixins.scss';
2+
13
.ydb-storage-groups-columns {
24
&__vdisks-column,
35
&__disks-column {
@@ -17,6 +19,8 @@
1719
}
1820

1921
&__group-id {
22+
margin-right: var(--g-spacing-1);
23+
2024
font-weight: 500;
2125
}
2226
}

src/containers/Storage/StorageGroups/columns/columns.tsx

+9-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import DataTable from '@gravity-ui/react-data-table';
33
import {Icon, Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';
44

55
import {CellWithPopover} from '../../../../components/CellWithPopover/CellWithPopover';
6-
import {InternalLink} from '../../../../components/InternalLink';
6+
import {EntityStatus} from '../../../../components/EntityStatus/EntityStatus';
77
import {StatusIcon} from '../../../../components/StatusIcon/StatusIcon';
88
import {UsageLabel} from '../../../../components/UsageLabel/UsageLabel';
99
import {getStorageGroupPath} from '../../../../routes';
@@ -144,18 +144,21 @@ const diskSpaceUsageColumn: StorageGroupsColumn = {
144144
const groupIdColumn: StorageGroupsColumn = {
145145
name: STORAGE_GROUPS_COLUMNS_IDS.GroupId,
146146
header: STORAGE_GROUPS_COLUMNS_TITLES.GroupId,
147-
width: 130,
147+
width: 140,
148148
render: ({row}) => {
149149
return row.GroupId ? (
150-
<InternalLink className={b('group-id')} to={getStorageGroupPath(row.GroupId)}>
151-
{row.GroupId}
152-
</InternalLink>
150+
<EntityStatus
151+
name={String(row.GroupId)}
152+
path={getStorageGroupPath(row.GroupId)}
153+
hasClipboardButton
154+
showStatus={false}
155+
/>
153156
) : (
154157
'-'
155158
);
156159
},
157160
sortAccessor: (row) => Number(row.GroupId),
158-
align: DataTable.RIGHT,
161+
align: DataTable.LEFT,
159162
};
160163

161164
const usedColumn: StorageGroupsColumn = {

0 commit comments

Comments
 (0)