Skip to content

Commit

Permalink
Refactor node component
Browse files Browse the repository at this point in the history
  • Loading branch information
jennypavlova committed Sep 26, 2023
1 parent 47449f8 commit ff4753a
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 212 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
import { GroupName } from './group_name';
import { Node } from './node';
import { InventoryItemType } from '../../../../../../common/inventory_models/types';
import { useAssetDetailsFlyoutState } from '../../hooks/use_asset_details_flyout_url_state';

interface Props {
onDrilldown: (filter: string) => void;
Expand Down Expand Up @@ -45,7 +44,6 @@ const isEqualGroupOfNodes = (prevProps: Props, nextProps: Props) => {
export const GroupOfNodes = React.memo<Props>(
({ group, options, formatter, onDrilldown, isChild = false, bounds, nodeType, currentTime }) => {
const width = group.width > 200 ? group.width : 200;
const [_, setProperties] = useAssetDetailsFlyoutState();

return (
<GroupOfNodesContainer style={{ width }}>
Expand All @@ -62,7 +60,6 @@ export const GroupOfNodes = React.memo<Props>(
bounds={bounds}
nodeType={nodeType}
currentTime={currentTime}
setShowAssetDetailsFlyout={setProperties}
/>
))
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@
* 2.0.
*/

import { darken, readableColor } from 'polished';
import React from 'react';

import { i18n } from '@kbn/i18n';

import { first } from 'lodash';
import { EuiPopover, EuiToolTip } from '@elastic/eui';
import { euiStyled } from '@kbn/kibana-react-plugin/common';
import { useBoolean } from '../../../../../hooks/use_boolean';
import {
InfraWaffleMapBounds,
InfraWaffleMapNode,
Expand All @@ -23,15 +20,8 @@ import { colorFromValue } from '../../lib/color_from_value';
import { InventoryItemType } from '../../../../../../common/inventory_models/types';

import { NodeContextMenu } from './node_context_menu';

const initialState = {
isPopoverOpen: false,
isOverlayOpen: false,
isAlertFlyoutVisible: false,
isToolTipOpen: false,
};

type State = Readonly<typeof initialState>;
import { NodeSquare } from './node_square';
import { useAssetDetailsFlyoutState } from '../../hooks/use_asset_details_flyout_url_state';

interface Props {
squareSize: number;
Expand All @@ -41,206 +31,75 @@ interface Props {
bounds: InfraWaffleMapBounds;
nodeType: InventoryItemType;
currentTime: number;
setShowAssetDetailsFlyout: ({ detailsItemId }: { detailsItemId: string | null }) => void;
}

export class Node extends React.PureComponent<Props, State> {
public readonly state: State = initialState;
public render() {
const { nodeType, node, options, squareSize, bounds, formatter, currentTime } = this.props;
const { isPopoverOpen, isToolTipOpen } = this.state;
const metric = first(node.metrics);
const valueMode = squareSize > 70;
const ellipsisMode = squareSize > 30;
const rawValue = (metric && metric.value) || 0;
const color = colorFromValue(options.legend, rawValue, bounds);
const value = formatter(rawValue);
const nodeAriaLabel = i18n.translate('xpack.infra.node.ariaLabel', {
defaultMessage: '{nodeName}, click to open menu',
values: { nodeName: node.name },
});

const nodeBorder = this.state.isOverlayOpen ? { border: 'solid 4px #000' } : undefined;

const bigSquare = (
<NodeContainer
data-test-subj="nodeContainer"
style={{ width: squareSize || 0, height: squareSize || 0 }}
onClick={this.togglePopover}
onMouseOver={this.showToolTip}
onMouseLeave={this.hideToolTip}
className="buttonContainer"
>
<SquareOuter color={color} style={nodeBorder}>
<SquareInner color={color}>
{valueMode ? (
<ValueInner aria-label={nodeAriaLabel}>
<Label data-test-subj="nodeName" color={color}>
{node.name}
</Label>
<Value data-test-subj="nodeValue" color={color}>
{value}
</Value>
</ValueInner>
) : (
ellipsisMode && (
<ValueInner aria-label={nodeAriaLabel}>
<Label color={color}>...</Label>
</ValueInner>
)
)}
</SquareInner>
</SquareOuter>
</NodeContainer>
);

const smallSquare = (
<NodeContainerSmall
data-test-subj="nodeContainer"
style={{ width: squareSize || 0, height: squareSize || 0, ...nodeBorder }}
onClick={this.togglePopover}
onMouseOver={this.showToolTip}
onMouseLeave={this.hideToolTip}
color={color}
/>
);

const nodeSquare = valueMode || ellipsisMode ? bigSquare : smallSquare;

return (
<>
{isPopoverOpen ? (
<EuiPopover
button={nodeSquare}
isOpen={isPopoverOpen}
closePopover={this.closePopover}
anchorPosition="downCenter"
style={{ height: squareSize }}
>
<NodeContextMenu
node={node}
nodeType={nodeType}
options={options}
currentTime={currentTime}
/>
</EuiPopover>
) : isToolTipOpen ? (
<EuiToolTip
delay="regular"
position="right"
content={
<ConditionalToolTip currentTime={currentTime} node={node} nodeType={nodeType} />
}
>
{nodeSquare}
</EuiToolTip>
) : (
nodeSquare
)}
</>
);
}

private togglePopover = () => {
const { nodeType, node, setShowAssetDetailsFlyout } = this.props;
export const Node = ({
nodeType,
node,
options,
squareSize,
bounds,
formatter,
currentTime,
}: Props) => {
const [isToolTipOpen, { off: hideToolTip, on: showToolTip }] = useBoolean(false);
const [isPopoverOpen, { off: closePopover, toggle: togglePopover }] = useBoolean(false);
const [{ detailsItemId }, setProperties] = useAssetDetailsFlyoutState();

const metric = first(node.metrics);
const rawValue = (metric && metric.value) || 0;
const color = colorFromValue(options.legend, rawValue, bounds);
const value = formatter(rawValue);

const toggleAssetPopover = () => {
if (nodeType === 'host') {
setShowAssetDetailsFlyout({ detailsItemId: node.name });
setProperties({ detailsItemId: node.name });
} else {
this.setState((prevState) => ({ isPopoverOpen: !prevState.isPopoverOpen }));
togglePopover();
}
};

private closePopover = () => {
if (this.state.isPopoverOpen) {
this.setState({ isPopoverOpen: false });
}
};
private showToolTip = () => {
this.setState({ isToolTipOpen: true });
};
private hideToolTip = () => {
this.setState({ isToolTipOpen: false });
};
}

const NodeContainer = euiStyled.div`
position: relative;
cursor: pointer;
`;
const NodeContainerSmall = euiStyled.div<ColorProps>`
cursor: pointer;
position: relative;
background-color: ${(props) => darken(0.1, props.color)};
border-radius: 3px;
margin: 2px;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
`;

interface ColorProps {
color: string;
}

const SquareOuter = euiStyled.div<ColorProps>`
position: absolute;
top: 4px;
left: 4px;
bottom: 4px;
right: 4px;
background-color: ${(props) => darken(0.1, props.color)};
border-radius: 3px;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
`;

const SquareInner = euiStyled.div<ColorProps>`
position: absolute;
top: 0;
right: 0;
bottom: 2px;
left: 0;
border-radius: 3px;
background-color: ${(props) => props.color};
`;

const ValueInner = euiStyled.button`
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
line-height: 1.2em;
align-items: center;
align-content: center;
padding: 1em;
overflow: hidden;
flex-wrap: wrap;
width: 100%;
border: none;
&:focus {
outline: none !important;
border: ${(params) => params.theme?.eui.euiFocusRingSize} solid
${(params) => params.theme?.eui.euiFocusRingColor};
box-shadow: none;
}
`;

const SquareTextContent = euiStyled.div<ColorProps>`
text-align: center;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1 0 auto;
color: ${(props) => readableColor(props.color)};
`;

const Value = euiStyled(SquareTextContent)`
font-weight: bold;
font-size: 0.9em;
line-height: 1.2em;
`;

const Label = euiStyled(SquareTextContent)`
font-size: 0.7em;
margin-bottom: 0.7em;
`;
const nodeSquare = (
<NodeSquare
squareSize={squareSize}
togglePopover={toggleAssetPopover}
showToolTip={showToolTip}
hideToolTip={hideToolTip}
color={color}
nodeName={node.name}
value={value}
isOverlayOpen={!!detailsItemId}
/>
);

return (
<>
{isPopoverOpen ? (
<EuiPopover
button={nodeSquare}
isOpen={isPopoverOpen}
closePopover={closePopover}
anchorPosition="downCenter"
style={{ height: squareSize }}
>
<NodeContextMenu
node={node}
nodeType={nodeType}
options={options}
currentTime={currentTime}
/>
</EuiPopover>
) : isToolTipOpen ? (
<EuiToolTip
delay="regular"
position="right"
content={<ConditionalToolTip currentTime={currentTime} node={node} nodeType={nodeType} />}
>
{nodeSquare}
</EuiToolTip>
) : (
nodeSquare
)}
</>
);
};
Loading

0 comments on commit ff4753a

Please sign in to comment.