Skip to content

Commit 7e2a588

Browse files
feat: update Disk indicators visual design across console (#3241)
1 parent 141974c commit 7e2a588

File tree

29 files changed

+423
-216
lines changed

29 files changed

+423
-216
lines changed

src/components/DiskStateProgressBar/DiskStateProgressBar.scss

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
$block: &;
55

66
$border-width: 1px;
7-
$outer-border-radius: 4px;
7+
$outer-border-radius: var(--g-border-radius-s);
88
$inner-border-radius: $outer-border-radius - $border-width;
9+
$outer-compact-border-radius: var(--g-border-radius-xs);
10+
$inner-compact-border-radius: $outer-compact-border-radius - $border-width;
911

10-
--progress-bar-full-height: var(--g-text-body-3-line-height);
12+
--progress-bar-full-height: var(--g-text-subheader-2-line-height);
1113
--progress-bar-compact-height: 12px;
1214

1315
--stripe-width: 4px;
@@ -16,6 +18,8 @@
1618
position: relative;
1719
z-index: 0;
1820

21+
overflow: hidden;
22+
1923
min-width: 50px;
2024
height: var(--progress-bar-full-height);
2125

@@ -25,13 +29,14 @@
2529
border: $border-width solid var(--entity-state-border-color);
2630
border-radius: $outer-border-radius;
2731
background-color: var(--entity-state-background-color);
28-
@include mixins.entity-state-colors();
32+
33+
@include mixins.entity-state-colors($block);
2934

3035
&_compact {
31-
min-width: 0;
36+
min-width: 8px;
3237
height: var(--progress-bar-compact-height);
3338

34-
border-radius: 2px;
39+
border-radius: $outer-compact-border-radius;
3540
}
3641

3742
&_faded {
@@ -78,7 +83,7 @@
7883
}
7984

8085
&_compact {
81-
border-radius: 1px;
86+
border-radius: $inner-compact-border-radius;
8287
}
8388

8489
&_inverted {
@@ -93,20 +98,21 @@
9398
position: relative;
9499
z-index: 2;
95100

96-
margin-right: var(--g-spacing-1);
101+
margin-right: var(--g-spacing-half);
97102

98-
font-size: var(--g-text-body-1-font-size);
103+
font-family: var(--g-text-caption-font-family);
104+
font-size: var(--g-text-caption-1-font-size);
99105
// bar height minus borders
100106
line-height: calc(var(--progress-bar-full-height) - #{$border-width * 2});
101107

102-
color: inherit;
108+
color: var(--entity-state-font-color);
103109
}
104110

105111
&__icon {
106112
position: relative;
107113
z-index: 2;
108114

109-
margin-left: var(--g-spacing-1);
115+
margin-left: calc(var(--g-spacing-1) - $border-width);
110116

111117
color: var(--entity-state-border-color);
112118
}

src/components/DiskStateProgressBar/DiskStateProgressBar.tsx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {cn} from '../../utils/cn';
77
import {DONOR_COLOR} from '../../utils/disks/constants';
88
import {getSeverityColor, getVDiskStatusIcon} from '../../utils/disks/helpers';
99
import {useSetting} from '../../utils/hooks';
10+
import {isNumeric} from '../../utils/utils';
1011

1112
import './DiskStateProgressBar.scss';
1213

@@ -24,6 +25,8 @@ interface DiskStateProgressBarProps {
2425
className?: string;
2526
isDonor?: boolean;
2627
withIcon?: boolean;
28+
highlighted?: boolean;
29+
noDataPlaceholder?: React.ReactNode;
2730
}
2831

2932
export function DiskStateProgressBar({
@@ -38,6 +41,8 @@ export function DiskStateProgressBar({
3841
className,
3942
isDonor,
4043
withIcon,
44+
highlighted,
45+
noDataPlaceholder,
4146
}: DiskStateProgressBarProps) {
4247
const [inverted] = useSetting<boolean | undefined>(SETTING_KEYS.INVERTED_DISKS);
4348

@@ -48,6 +53,7 @@ export function DiskStateProgressBar({
4853
empty,
4954
inactive,
5055
striped,
56+
highlighted,
5157
};
5258

5359
if (isDonor) {
@@ -59,33 +65,39 @@ export function DiskStateProgressBar({
5965
}
6066
}
6167

68+
const hasAllocatedPercent = isNumeric(diskAllocatedPercent) && diskAllocatedPercent >= 0;
69+
6270
const renderAllocatedPercent = () => {
6371
if (compact) {
6472
return <div className={b('fill-bar', mods)} style={{width: '100%'}} />;
6573
}
6674

75+
if (!hasAllocatedPercent) {
76+
return null;
77+
}
78+
6779
// diskAllocatedPercent could be more than 100
6880
let fillWidth = Math.min(diskAllocatedPercent, 100);
6981
if (inverted) {
7082
fillWidth = Math.max(100 - diskAllocatedPercent, 0);
7183
}
7284

73-
if (diskAllocatedPercent >= 0) {
74-
return <div className={b('fill-bar', mods)} style={{width: `${fillWidth}%`}} />;
75-
}
76-
77-
return null;
85+
return <div className={b('fill-bar', mods)} style={{width: `${fillWidth}%`}} />;
7886
};
7987

8088
const renderContent = () => {
8189
if (content) {
8290
return content;
8391
}
8492

85-
if (!compact && diskAllocatedPercent >= 0) {
93+
if (!compact && hasAllocatedPercent) {
8694
return <div className={b('title')}>{`${Math.floor(diskAllocatedPercent)}%`}</div>;
8795
}
8896

97+
if (!compact && !hasAllocatedPercent && noDataPlaceholder) {
98+
return <div className={b('title')}>{noDataPlaceholder}</div>;
99+
}
100+
89101
return null;
90102
};
91103

@@ -111,7 +123,7 @@ export function DiskStateProgressBar({
111123
aria-label="Disk allocated space"
112124
aria-valuemin={0}
113125
aria-valuemax={100}
114-
aria-valuenow={diskAllocatedPercent}
126+
aria-valuenow={hasAllocatedPercent ? diskAllocatedPercent : undefined}
115127
>
116128
{iconElement}
117129
{renderAllocatedPercent()}

src/components/HoverPopup/HoverPopup.tsx

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,48 +34,77 @@ export const HoverPopup = ({
3434
delayOpen = DEBOUNCE_TIMEOUT,
3535
}: HoverPopupProps) => {
3636
const [isPopupVisible, setIsPopupVisible] = React.useState(false);
37-
const anchor = React.useRef<HTMLDivElement>(null);
37+
const [isPopupContentHovered, setIsPopupContentHovered] = React.useState(false);
38+
const [isFocused, setIsFocused] = React.useState(false);
39+
40+
const anchor = React.useRef<HTMLSpanElement>(null);
41+
42+
const reportedOpenRef = React.useRef(false);
43+
44+
const reportOpen = React.useCallback(
45+
(nextOpen: boolean) => {
46+
if (reportedOpenRef.current === nextOpen) {
47+
return;
48+
}
49+
50+
reportedOpenRef.current = nextOpen;
51+
52+
if (nextOpen) {
53+
onShowPopup?.();
54+
} else {
55+
onHidePopup?.();
56+
}
57+
},
58+
[onShowPopup, onHidePopup],
59+
);
3860

3961
const debouncedHandleShowPopup = React.useMemo(
4062
() =>
4163
debounce(() => {
4264
setIsPopupVisible(true);
43-
onShowPopup?.();
65+
reportOpen(true);
4466
}, delayOpen),
45-
[onShowPopup, delayOpen],
67+
[delayOpen, reportOpen],
4668
);
4769

4870
const hidePopup = React.useCallback(() => {
4971
setIsPopupVisible(false);
50-
onHidePopup?.();
51-
}, [onHidePopup]);
72+
}, []);
5273

5374
const debouncedHandleHidePopup = React.useMemo(
54-
() => debounce(hidePopup, delayClose),
55-
[hidePopup, delayClose],
75+
() =>
76+
debounce(() => {
77+
hidePopup();
78+
reportOpen(false);
79+
}, delayClose),
80+
[delayClose, reportOpen, hidePopup],
5681
);
5782

58-
const onMouseEnter = debouncedHandleShowPopup;
83+
const onMouseEnter = () => {
84+
debouncedHandleHidePopup.cancel();
85+
debouncedHandleShowPopup();
86+
};
5987

6088
const onMouseLeave = () => {
6189
debouncedHandleShowPopup.cancel();
6290
debouncedHandleHidePopup();
6391
};
6492

65-
const [isPopupContentHovered, setIsPopupContentHovered] = React.useState(false);
66-
const [isFocused, setIsFocused] = React.useState(false);
67-
6893
const onPopupMouseEnter = React.useCallback(() => {
94+
debouncedHandleHidePopup.cancel();
6995
setIsPopupContentHovered(true);
70-
}, []);
96+
reportOpen(true);
97+
}, [reportOpen, debouncedHandleHidePopup]);
7198

7299
const onPopupMouseLeave = React.useCallback(() => {
73100
setIsPopupContentHovered(false);
74-
}, []);
101+
debouncedHandleHidePopup();
102+
}, [debouncedHandleHidePopup]);
75103

76104
const onPopupContextMenu = React.useCallback(() => {
77105
setIsFocused(true);
78-
}, []);
106+
reportOpen(true);
107+
}, [reportOpen]);
79108

80109
const onPopupBlur = React.useCallback(() => {
81110
setIsFocused(false);
@@ -85,26 +114,30 @@ export const HoverPopup = ({
85114
setIsFocused(false);
86115
setIsPopupContentHovered(false);
87116
hidePopup();
88-
}, [hidePopup]);
117+
reportOpen(false);
118+
}, [hidePopup, reportOpen]);
119+
120+
const internalOpen = isPopupVisible || isPopupContentHovered || isFocused;
121+
const open = internalOpen || showPopup;
89122

90-
const open = isPopupVisible || showPopup || isPopupContentHovered || isFocused;
123+
const anchorElement = anchorRef?.current || anchor.current;
91124

92125
return (
93126
<React.Fragment>
94127
<span ref={anchor} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
95128
{children}
96129
</span>
97-
{open ? (
130+
{anchorElement ? (
98131
<Popup
99-
anchorElement={anchorRef?.current || anchor.current}
132+
anchorElement={anchorElement}
100133
onOpenChange={(_open, _event, reason) => {
101134
if (reason === 'escape-key') {
102135
onPopupEscapeKeyDown();
103136
}
104137
}}
105138
placement={placement}
106139
hasArrow
107-
open
140+
open={open}
108141
// bigger offset for easier switching to neighbour nodes
109142
// matches the default offset for popup with arrow out of a sense of beauty
110143
offset={offset || {mainAxis: 12, crossAxis: 0}}

src/components/VDisk/VDisk.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export interface VDiskProps {
2222
delayOpen?: number;
2323
delayClose?: number;
2424
withIcon?: boolean;
25+
highlighted?: boolean;
2526
}
2627

2728
export const VDisk = ({
@@ -35,13 +36,14 @@ export const VDisk = ({
3536
delayClose,
3637
delayOpen,
3738
withIcon,
39+
highlighted,
3840
}: VDiskProps) => {
3941
const getVDiskLink = useVDiskPagePath();
4042
const vDiskPath = getVDiskLink({nodeId: data.NodeId, vDiskId: data.StringifiedId});
4143

4244
const severity = data.Severity;
4345
const isReplicatingColor = severity === DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Blue;
44-
const isHealthyDonor = data.DonorMode && isReplicatingColor;
46+
const isDonor = data.DonorMode;
4547

4648
return (
4749
<HoverPopup
@@ -60,10 +62,11 @@ export const VDisk = ({
6062
severity={severity}
6163
compact={compact}
6264
inactive={inactive}
63-
striped={isReplicatingColor}
64-
isDonor={isHealthyDonor}
65+
striped={isReplicatingColor || isDonor}
66+
isDonor={isDonor}
6567
className={progressBarClassName}
6668
withIcon={withIcon}
69+
highlighted={highlighted}
6770
/>
6871
</InternalLink>
6972
</div>

0 commit comments

Comments
 (0)