diff --git a/x-pack/solutions/security/packages/distribution-bar/src/distribution_bar.tsx b/x-pack/solutions/security/packages/distribution-bar/src/distribution_bar.tsx index 0942cace23267..416933a9d1346 100644 --- a/x-pack/solutions/security/packages/distribution-bar/src/distribution_bar.tsx +++ b/x-pack/solutions/security/packages/distribution-bar/src/distribution_bar.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; +import React, { useMemo, useState } from 'react'; import { EuiFlexGroup, EuiBadge, useEuiTheme, EuiIcon, EuiFlexItem } from '@elastic/eui'; import numeral from '@elastic/numeral'; import { css } from '@emotion/react'; @@ -80,20 +80,14 @@ const useStyles = () => { transition: all 0.3s ease; } `, - // last tooltip should be displayed initially even without hover - lastTooltip: css` - &:last-child > div { + visibleTooltip: css` + & > div { opacity: 1; + top: calc(-${euiTheme.base + 2}px - 13px); } - &:last-child::after { + &::after { opacity: 1; } - &:hover ~ div:last-child > div { - opacity: 0; - } - &:hover ~ div:last-child::after { - opacity: 0; - } `, }, tooltip: css` @@ -131,12 +125,35 @@ const useStyles = () => { const EmptyBar: React.FC = ({ 'data-test-subj': dataTestSubj }) => { const styles = useStyles(); - const emptyBarStyle = [styles.part.base, styles.part.empty]; return
; }; +// Only show tooltip for segments thats hovered OR Set as Filter OR Last +const shouldShowTooltip = ({ + isHovered, + isCurrentFilter, + isLast, + hasFilterActive, + hideLastTooltip, + isHoveringAnyStatsBar, +}: { + isHovered: boolean; + isCurrentFilter: boolean; + isLast: boolean; + hasFilterActive: boolean; + hideLastTooltip?: boolean; + isHoveringAnyStatsBar: boolean; +}) => { + if (isHovered) return true; + + const shouldShowBecauseOfFilter = isCurrentFilter; + const shouldShowBecauseItIsLast = isLast && !hideLastTooltip && !hasFilterActive; + + return !isHoveringAnyStatsBar && (shouldShowBecauseOfFilter || shouldShowBecauseItIsLast); +}; + // TODO: fix tooltip direction if not enough space; /** * Security Solution DistributionBar component. @@ -147,7 +164,25 @@ export const DistributionBar: React.FC = React.memo(functi ) { const styles = useStyles(); const { stats, 'data-test-subj': dataTestSubj, hideLastTooltip } = props; - const parts = stats.map((stat) => { + + const [hoveredKey, setHoveredKey] = useState(null); + const hasCurrentFilter = useMemo(() => stats.some((item) => item.isCurrentFilter), [stats]); + + const parts = stats.map((stat, index) => { + const isLast = index === stats.length - 1; + const isHovered = hoveredKey === stat.key; + + // Only show tooltip for segments thats hovered OR Set as Filter OR Last + const isCurrentFilter = stat.isCurrentFilter ?? false; + const showTooltip = shouldShowTooltip({ + isHovered, + isCurrentFilter, + isLast, + hasFilterActive: hasCurrentFilter, + hideLastTooltip, + isHoveringAnyStatsBar: Boolean(hoveredKey), + }); + const partStyle = [ styles.part.base, styles.part.tick, @@ -157,8 +192,9 @@ export const DistributionBar: React.FC = React.memo(functi flex: ${stat.count}; `, ]; - if (!hideLastTooltip) { - partStyle.push(styles.part.lastTooltip); + + if (showTooltip) { + partStyle.push(styles.part.visibleTooltip); } const prettyNumber = numeral(stat.count).format('0,0a'); @@ -169,6 +205,8 @@ export const DistributionBar: React.FC = React.memo(functi css={partStyle} data-test-subj={`${dataTestSubj}__part`} onClick={stat.filter} + onMouseEnter={() => setHoveredKey(stat.key)} + onMouseLeave={() => setHoveredKey(null)} onKeyDown={(event) => { if (event.key === 'Enter' || event.key === ' ') { stat.filter?.(); @@ -177,30 +215,25 @@ export const DistributionBar: React.FC = React.memo(functi tabIndex={0} role="button" > -
- +
+ - + {prettyNumber} - - + + - + - {stat.label ? stat.label : stat.key} - {stat.isCurrentFilter ? ( + {stat.label ?? stat.key} + {stat.isCurrentFilter && stat.reset && ( - ) : undefined} + )} @@ -212,7 +245,7 @@ export const DistributionBar: React.FC = React.memo(functi return (