Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions src/components/EntityStatus/EntityStatus.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
margin-right: var(--g-spacing-2);
}

&__info-icon,
&__clipboard-button {
color: var(--g-color-text-secondary);

Expand All @@ -26,14 +27,30 @@
}
}

&__info-icon {
&:hover {
color: var(--g-color-text-primary);
}
}

&__wrapper {
position: relative;

overflow: hidden;

&_with-button {
&_with-clipboard-button {
padding-right: var(--button-width);
}

&_with-info-button {
padding-right: var(--button-width);
}

&_with-clipboard-button {
&.entity-status__wrapper_with-info-button {
padding-right: calc(2 * var(--button-width));
}
}
}

&__controls-wrapper {
Expand All @@ -51,6 +68,8 @@
&_visible {
width: min-content;
padding: var(--g-spacing-1);

background-color: var(--g-color-base-background);
}

.data-table__row:hover &,
Expand Down Expand Up @@ -79,13 +98,27 @@
display: inline-block;
overflow: hidden;

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

white-space: nowrap;
text-overflow: ellipsis;
}

&__wrapper_with-clipboard-button &__link {
width: calc(100% + var(--button-width));
}

&__wrapper_with-info-button &__link {
width: calc(100% + var(--button-width));
}

&__wrapper_with-clipboard-button {
&.entity-status__wrapper_with-info-button .entity-status__link {
width: calc(100% + 2 * var(--button-width));
}
}

&__link_with-left-trim {
text-align: end;
direction: rtl;
Expand Down
58 changes: 46 additions & 12 deletions src/components/EntityStatus/EntityStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import {ClipboardButton, Link as UIKitLink} from '@gravity-ui/uikit';
import React from 'react';

import {CircleInfo} from '@gravity-ui/icons';
import {Button, ClipboardButton, Icon, Popover, Link as UIKitLink} from '@gravity-ui/uikit';

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

hasClipboardButton?: boolean;
infoPopoverContent?: React.ReactNode;
clipboardButtonAlwaysVisible?: boolean;

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

hasClipboardButton,
infoPopoverContent,
clipboardButtonAlwaysVisible = false,

className,
}: EntityStatusProps) {
const [infoIconHovered, setInfoIconHovered] = React.useState(false);

const renderIcon = () => {
if (!showStatus) {
return null;
Expand Down Expand Up @@ -90,24 +97,51 @@ export function EntityStatus({
</span>
)}
{(path || name) && (
<div className={b('wrapper', {'with-button': hasClipboardButton})}>
<div
className={b('wrapper', {
'with-clipboard-button': hasClipboardButton,
'with-info-button': Boolean(infoPopoverContent),
})}
>
<span className={b('link', {'with-left-trim': withLeftTrim})} title={name}>
{renderLink()}
</span>
{hasClipboardButton && (
{(hasClipboardButton || infoPopoverContent) && (
<div
className={b('controls-wrapper', {
visible: clipboardButtonAlwaysVisible,
visible: clipboardButtonAlwaysVisible || infoIconHovered,
})}
>
<ClipboardButton
text={name}
size="xs"
view="normal"
className={b('clipboard-button', {
visible: clipboardButtonAlwaysVisible,
})}
/>
{infoPopoverContent && (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Info button always take place in column. It looks not good if column is narrow enough.
Screenshot 2025-03-27 at 10 41 50

<Popover
className={b('info-popover')}
content={infoPopoverContent}
tooltipOffset={[-4, 4]}
placement={['top-start', 'bottom-start']}
onOpenChange={(visible) => setInfoIconHovered(visible)}
>
<Button view="normal" size="xs">
<Icon
data={CircleInfo}
size="12"
className={b('info-icon', {
visible:
clipboardButtonAlwaysVisible || infoIconHovered,
})}
/>
</Button>
</Popover>
)}
{hasClipboardButton && (
<ClipboardButton
text={name}
size="xs"
view="normal"
className={b('clipboard-button', {
visible: clipboardButtonAlwaysVisible || infoIconHovered,
})}
/>
)}
</div>
)}
</div>
Expand Down
23 changes: 11 additions & 12 deletions src/components/NodeHostWrapper/NodeHostWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import {PopoverBehavior} from '@gravity-ui/uikit';

import {getDefaultNodePath} from '../../containers/Node/NodePages';
import type {GetNodeRefFunc, NodeAddress} from '../../types/additionalProps';
import type {TNodeInfo, TSystemStateInfo} from '../../types/api/nodes';
Expand All @@ -8,7 +6,6 @@ import {
createDeveloperUILinkWithNodeId,
} from '../../utils/developerUI/developerUI';
import {isUnavailableNode} from '../../utils/nodes';
import {CellWithPopover} from '../CellWithPopover/CellWithPopover';
import {EntityStatus} from '../EntityStatus/EntityStatus';
import {NodeEndpointsTooltipContent} from '../TooltipsContent';

Expand Down Expand Up @@ -64,14 +61,16 @@ export const NodeHostWrapper = ({
: undefined;

return (
<CellWithPopover
disabled={!isNodeAvailable}
content={<NodeEndpointsTooltipContent data={node} nodeHref={developerUIInternalHref} />}
placement={['top', 'bottom']}
behavior={PopoverBehavior.Immediate}
delayClosing={200}
>
<EntityStatus name={node.Host} status={status} path={nodePath} hasClipboardButton />
</CellWithPopover>
<EntityStatus
name={node.Host}
status={status}
path={nodePath}
hasClipboardButton
infoPopoverContent={
isNodeAvailable ? (
<NodeEndpointsTooltipContent data={node} nodeHref={developerUIInternalHref} />
) : null
}
/>
);
};
71 changes: 32 additions & 39 deletions src/components/TenantNameWrapper/TenantNameWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import {DefinitionList, Flex, PopoverBehavior} from '@gravity-ui/uikit';
import {DefinitionList, Flex} from '@gravity-ui/uikit';

import {getTenantPath} from '../../containers/Tenant/TenantPages';
import type {PreparedTenant} from '../../store/reducers/tenants/types';
import type {AdditionalTenantsProps, NodeAddress} from '../../types/additionalProps';
import {useIsUserAllowedToMakeChanges} from '../../utils/hooks/useIsUserAllowedToMakeChanges';
import {CellWithPopover} from '../CellWithPopover/CellWithPopover';
import {EntityStatus} from '../EntityStatus/EntityStatus';
import {LinkWithIcon} from '../LinkWithIcon/LinkWithIcon';

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

const infoPopoverContent =
(monitoringLink || logsLink) && isUserAllowedToMakeChanges ? (
<DefinitionList responsive>
<DefinitionList.Item name={i18n('field_links')}>
<Flex gap={2} wrap="wrap">
{monitoringLink && (
<LinkWithIcon
title={i18n('field_monitoring-link')}
url={monitoringLink}
/>
)}
{logsLink && (
<LinkWithIcon title={i18n('field_logs-link')} url={logsLink} />
)}
</Flex>
</DefinitionList.Item>
</DefinitionList>
) : null;

return (
<CellWithPopover
disabled={!isUserAllowedToMakeChanges || (!monitoringLink && !logsLink)}
delayClosing={200}
content={
monitoringLink || logsLink ? (
<DefinitionList responsive>
<DefinitionList.Item name={i18n('field_links')}>
<Flex gap={2} wrap="wrap">
{monitoringLink && (
<LinkWithIcon
title={i18n('field_monitoring-link')}
url={monitoringLink}
/>
)}
{logsLink && (
<LinkWithIcon title={i18n('field_logs-link')} url={logsLink} />
)}
</Flex>
</DefinitionList.Item>
</DefinitionList>
) : null
}
placement={['top', 'bottom']}
behavior={PopoverBehavior.Immediate}
>
<EntityStatus
externalLink={isExternalLink}
name={tenant.Name || i18n('context_unknown')}
withLeftTrim={true}
status={tenant.Overall}
hasClipboardButton
path={getTenantPath({
database: tenant.Name,
backend,
})}
/>
</CellWithPopover>
<EntityStatus
externalLink={isExternalLink}
name={tenant.Name || i18n('context_unknown')}
withLeftTrim={true}
status={tenant.Overall}
infoPopoverContent={infoPopoverContent}
hasClipboardButton
path={getTenantPath({
database: tenant.Name,
backend,
})}
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@use '../../../../styles/mixins.scss';

.ydb-storage-groups-columns {
&__vdisks-column,
&__disks-column {
Expand All @@ -17,6 +19,8 @@
}

&__group-id {
margin-right: var(--g-spacing-1);

font-weight: 500;
}
}
15 changes: 9 additions & 6 deletions src/containers/Storage/StorageGroups/columns/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import DataTable from '@gravity-ui/react-data-table';
import {Icon, Label, Popover, PopoverBehavior} from '@gravity-ui/uikit';

import {CellWithPopover} from '../../../../components/CellWithPopover/CellWithPopover';
import {InternalLink} from '../../../../components/InternalLink';
import {EntityStatus} from '../../../../components/EntityStatus/EntityStatus';
import {StatusIcon} from '../../../../components/StatusIcon/StatusIcon';
import {UsageLabel} from '../../../../components/UsageLabel/UsageLabel';
import {getStorageGroupPath} from '../../../../routes';
Expand Down Expand Up @@ -144,18 +144,21 @@ const diskSpaceUsageColumn: StorageGroupsColumn = {
const groupIdColumn: StorageGroupsColumn = {
name: STORAGE_GROUPS_COLUMNS_IDS.GroupId,
header: STORAGE_GROUPS_COLUMNS_TITLES.GroupId,
width: 130,
width: 140,
render: ({row}) => {
return row.GroupId ? (
<InternalLink className={b('group-id')} to={getStorageGroupPath(row.GroupId)}>
{row.GroupId}
</InternalLink>
<EntityStatus
name={String(row.GroupId)}
path={getStorageGroupPath(row.GroupId)}
hasClipboardButton
showStatus={false}
/>
) : (
'-'
);
},
sortAccessor: (row) => Number(row.GroupId),
align: DataTable.RIGHT,
align: DataTable.LEFT,
};

const usedColumn: StorageGroupsColumn = {
Expand Down
Loading