From 198e93263fd833075c0e6630c6e82106d716a7c0 Mon Sep 17 00:00:00 2001 From: Phillip Burch Date: Tue, 4 Feb 2020 14:37:26 -0600 Subject: [PATCH 1/5] Disable scroll when popover is open. Switch to hooks --- .../components/nodes_overview/table.tsx | 254 +++++++++--------- .../components/waffle/node_context_menu.tsx | 7 +- 2 files changed, 132 insertions(+), 129 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx b/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx index dc0de6f6e9c69..b7d8341265205 100644 --- a/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx +++ b/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx @@ -8,29 +8,25 @@ import { EuiButtonEmpty, EuiInMemoryTable, EuiToolTip, EuiBasicTableColumn } fro import { i18n } from '@kbn/i18n'; import { last } from 'lodash'; -import React from 'react'; +import React, { useState, useCallback, useRef, useEffect } from 'react'; import { createWaffleMapNode } from '../../containers/waffle/nodes_to_wafflemap'; import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../lib/lib'; import { fieldToName } from '../waffle/lib/field_to_display_name'; import { NodeContextMenu } from '../waffle/node_context_menu'; import { InventoryItemType } from '../../../common/inventory_models/types'; import { SnapshotNode, SnapshotNodePath } from '../../../common/http_api/snapshot_api'; +import { ROOT_ELEMENT_ID } from '../../app'; interface Props { nodes: SnapshotNode[]; nodeType: InventoryItemType; options: InfraWaffleMapOptions; - formatter: (subject: string | number) => string; currentTime: number; + onOpen(): void; + formatter: (subject: string | number) => string; onFilter: (filter: string) => void; } -const initialState = { - isPopoverOpen: [] as string[], -}; - -type State = Readonly; - const getGroupPaths = (path: SnapshotNodePath[]) => { switch (path.length) { case 3: @@ -42,126 +38,134 @@ const getGroupPaths = (path: SnapshotNodePath[]) => { } }; -export const TableView = class extends React.PureComponent { - public readonly state: State = initialState; - public render() { - const { nodes, options, formatter, currentTime, nodeType } = this.props; - const columns: Array> = [ - { - field: 'name', - name: i18n.translate('xpack.infra.tableView.columnName.name', { defaultMessage: 'Name' }), - sortable: true, - truncateText: true, - textOnly: true, - render: (value: string, item: { node: InfraWaffleMapNode }) => { - const tooltipText = item.node.id === value ? `${value}` : `${value} (${item.node.id})`; - // For the table we need to create a UniqueID that takes into to account the groupings - // as well as the node name. There is the possibility that a node can be present in two - // different groups and be on the screen at the same time. - const uniqueID = [...item.node.path.map(p => p.value), item.node.name].join(':'); - return ( - - - {value} - - - ); - }, - }, - ...options.groupBy.map((grouping, index) => ({ - field: `group_${index}`, - name: fieldToName((grouping && grouping.field) || ''), - sortable: true, - truncateText: true, - textOnly: true, - render: (value: string) => { - const handleClick = () => this.props.onFilter(`${grouping.field}:"${value}"`); - return ( - - {value} +export const TableView = (props: Props) => { + const { nodes, options, formatter, currentTime, nodeType } = props; + const [isPopoverOpen, setIsPopoverOpen] = useState([]); + const openPopoverFor = useCallback( + (id: string) => () => { + document.getElementById(ROOT_ELEMENT_ID)!.style.overflowY = 'hidden'; + setIsPopoverOpen([...isPopoverOpen, id]); + }, + [isPopoverOpen] + ); + + const closePopoverFor = useCallback( + (id: string) => () => { + setIsPopoverOpen([...isPopoverOpen, id]); + document.getElementById(ROOT_ELEMENT_ID)!.style.overflowY = 'auto'; + if (isPopoverOpen.includes(id)) { + setIsPopoverOpen(isPopoverOpen.filter(subject => subject !== id)); + } + }, + [isPopoverOpen] + ); + + useEffect(() => { + if (isPopoverOpen.length > 0) { + document.getElementById(ROOT_ELEMENT_ID)!.style.overflowY = 'hidden'; + } else { + document.getElementById(ROOT_ELEMENT_ID)!.style.overflowY = 'auto'; + } + }, [isPopoverOpen]); + + const columns: Array> = [ + { + field: 'name', + name: i18n.translate('xpack.infra.tableView.columnName.name', { defaultMessage: 'Name' }), + sortable: true, + truncateText: true, + textOnly: true, + render: (value: string, item: { node: InfraWaffleMapNode }) => { + const tooltipText = item.node.id === value ? `${value}` : `${value} (${item.node.id})`; + // For the table we need to create a UniqueID that takes into to account the groupings + // as well as the node name. There is the possibility that a node can be present in two + // different groups and be on the screen at the same time. + const uniqueID = [...item.node.path.map(p => p.value), item.node.name].join(':'); + return ( + + + {value} - ); - }, - })), - { - field: 'value', - name: i18n.translate('xpack.infra.tableView.columnName.last1m', { - defaultMessage: 'Last 1m', - }), - sortable: true, - truncateText: true, - dataType: 'number', - render: (value: number) => {formatter(value)}, - }, - { - field: 'avg', - name: i18n.translate('xpack.infra.tableView.columnName.avg', { defaultMessage: 'Avg' }), - sortable: true, - truncateText: true, - dataType: 'number', - render: (value: number) => {formatter(value)}, + + ); }, - { - field: 'max', - name: i18n.translate('xpack.infra.tableView.columnName.max', { defaultMessage: 'Max' }), - sortable: true, - truncateText: true, - dataType: 'number', - render: (value: number) => {formatter(value)}, + }, + ...options.groupBy.map((grouping, index) => ({ + field: `group_${index}`, + name: fieldToName((grouping && grouping.field) || ''), + sortable: true, + truncateText: true, + textOnly: true, + render: (value: string) => { + const handleClick = () => props.onFilter(`${grouping.field}:"${value}"`); + return ( + + {value} + + ); }, - ]; - const items = nodes.map(node => { - const name = last(node.path); - return { - name: (name && name.label) || 'unknown', - ...getGroupPaths(node.path).reduce( - (acc, path, index) => ({ - ...acc, - [`group_${index}`]: path.label, - }), - {} - ), - value: node.metric.value, - avg: node.metric.avg, - max: node.metric.max, - node: createWaffleMapNode(node), - }; - }); - const initialSorting = { - sort: { - field: 'value', - direction: 'desc', - }, - } as const; - return ( - - ); - } + })), + { + field: 'value', + name: i18n.translate('xpack.infra.tableView.columnName.last1m', { + defaultMessage: 'Last 1m', + }), + sortable: true, + truncateText: true, + dataType: 'number', + render: (value: number) => {formatter(value)}, + }, + { + field: 'avg', + name: i18n.translate('xpack.infra.tableView.columnName.avg', { defaultMessage: 'Avg' }), + sortable: true, + truncateText: true, + dataType: 'number', + render: (value: number) => {formatter(value)}, + }, + { + field: 'max', + name: i18n.translate('xpack.infra.tableView.columnName.max', { defaultMessage: 'Max' }), + sortable: true, + truncateText: true, + dataType: 'number', + render: (value: number) => {formatter(value)}, + }, + ]; - private openPopoverFor = (id: string) => () => { - this.setState(prevState => ({ isPopoverOpen: [...prevState.isPopoverOpen, id] })); - }; + const items = nodes.map(node => { + const name = last(node.path); + return { + name: (name && name.label) || 'unknown', + ...getGroupPaths(node.path).reduce( + (acc, path, index) => ({ + ...acc, + [`group_${index}`]: path.label, + }), + {} + ), + value: node.metric.value, + avg: node.metric.avg, + max: node.metric.max, + node: createWaffleMapNode(node), + }; + }); + const initialSorting = { + sort: { + field: 'value', + direction: 'desc', + }, + } as const; - private closePopoverFor = (id: string) => () => { - if (this.state.isPopoverOpen.includes(id)) { - this.setState(prevState => { - return { - isPopoverOpen: prevState.isPopoverOpen.filter(subject => subject !== id), - }; - }); - } - }; + return ( + + ); }; diff --git a/x-pack/legacy/plugins/infra/public/components/waffle/node_context_menu.tsx b/x-pack/legacy/plugins/infra/public/components/waffle/node_context_menu.tsx index 86a22c358b4d5..97b85a7e6e17d 100644 --- a/x-pack/legacy/plugins/infra/public/components/waffle/node_context_menu.tsx +++ b/x-pack/legacy/plugins/infra/public/components/waffle/node_context_menu.tsx @@ -28,7 +28,6 @@ import { interface Props { options: InfraWaffleMapOptions; currentTime: number; - children: any; node: InfraWaffleMapNode; nodeType: InventoryItemType; isPopoverOpen: boolean; @@ -36,7 +35,7 @@ interface Props { popoverPosition: EuiPopoverProps['anchorPosition']; } -export const NodeContextMenu = ({ +export const NodeContextMenu: React.FC = ({ options, currentTime, children, @@ -45,7 +44,7 @@ export const NodeContextMenu = ({ closePopover, nodeType, popoverPosition, -}: Props) => { +}) => { const uiCapabilities = useKibana().services.application?.capabilities; const inventoryModel = findInventoryModel(nodeType); const nodeDetailFrom = currentTime - inventoryModel.metrics.defaultTimeRangeInSeconds * 1000; @@ -132,7 +131,7 @@ export const NodeContextMenu = ({ closePopover={closePopover} id={`${node.pathId}-popover`} isOpen={isPopoverOpen} - button={children} + button={children!} anchorPosition={popoverPosition} >
From 46c616770929681d5fcc0e890aa020171381083b Mon Sep 17 00:00:00 2001 From: Phillip Burch Date: Tue, 4 Feb 2020 14:41:26 -0600 Subject: [PATCH 2/5] Remove unused prop --- .../plugins/infra/public/components/nodes_overview/table.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx b/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx index b7d8341265205..3bb5c837b05fd 100644 --- a/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx +++ b/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx @@ -22,7 +22,6 @@ interface Props { nodeType: InventoryItemType; options: InfraWaffleMapOptions; currentTime: number; - onOpen(): void; formatter: (subject: string | number) => string; onFilter: (filter: string) => void; } From c3db1ec0125ae2ff0543019130aea7636dbfd977 Mon Sep 17 00:00:00 2001 From: Phillip Burch Date: Tue, 4 Feb 2020 14:43:22 -0600 Subject: [PATCH 3/5] UseEffect to update styles --- .../plugins/infra/public/components/nodes_overview/table.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx b/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx index 3bb5c837b05fd..06f9321012f6d 100644 --- a/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx +++ b/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx @@ -42,7 +42,6 @@ export const TableView = (props: Props) => { const [isPopoverOpen, setIsPopoverOpen] = useState([]); const openPopoverFor = useCallback( (id: string) => () => { - document.getElementById(ROOT_ELEMENT_ID)!.style.overflowY = 'hidden'; setIsPopoverOpen([...isPopoverOpen, id]); }, [isPopoverOpen] @@ -51,7 +50,6 @@ export const TableView = (props: Props) => { const closePopoverFor = useCallback( (id: string) => () => { setIsPopoverOpen([...isPopoverOpen, id]); - document.getElementById(ROOT_ELEMENT_ID)!.style.overflowY = 'auto'; if (isPopoverOpen.includes(id)) { setIsPopoverOpen(isPopoverOpen.filter(subject => subject !== id)); } From bc477431b0f17f024a138756bdd2181b8868118d Mon Sep 17 00:00:00 2001 From: Phillip Burch Date: Tue, 4 Feb 2020 15:57:49 -0600 Subject: [PATCH 4/5] Remove ununsed import --- .../plugins/infra/public/components/nodes_overview/table.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx b/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx index 06f9321012f6d..c5c73319ad1df 100644 --- a/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx +++ b/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx @@ -8,7 +8,7 @@ import { EuiButtonEmpty, EuiInMemoryTable, EuiToolTip, EuiBasicTableColumn } fro import { i18n } from '@kbn/i18n'; import { last } from 'lodash'; -import React, { useState, useCallback, useRef, useEffect } from 'react'; +import React, { useState, useCallback, useEffect } from 'react'; import { createWaffleMapNode } from '../../containers/waffle/nodes_to_wafflemap'; import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../lib/lib'; import { fieldToName } from '../waffle/lib/field_to_display_name'; From e4d45b514b2c4418117712919f66b33a3e6fbc89 Mon Sep 17 00:00:00 2001 From: Phillip Burch Date: Thu, 6 Feb 2020 11:57:01 -0600 Subject: [PATCH 5/5] Rename variables for clarity --- .../components/nodes_overview/table.tsx | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx b/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx index c5c73319ad1df..5c793f670119c 100644 --- a/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx +++ b/x-pack/legacy/plugins/infra/public/components/nodes_overview/table.tsx @@ -39,31 +39,30 @@ const getGroupPaths = (path: SnapshotNodePath[]) => { export const TableView = (props: Props) => { const { nodes, options, formatter, currentTime, nodeType } = props; - const [isPopoverOpen, setIsPopoverOpen] = useState([]); + const [openPopovers, setOpenPopovers] = useState([]); const openPopoverFor = useCallback( (id: string) => () => { - setIsPopoverOpen([...isPopoverOpen, id]); + setOpenPopovers([...openPopovers, id]); }, - [isPopoverOpen] + [openPopovers] ); const closePopoverFor = useCallback( (id: string) => () => { - setIsPopoverOpen([...isPopoverOpen, id]); - if (isPopoverOpen.includes(id)) { - setIsPopoverOpen(isPopoverOpen.filter(subject => subject !== id)); + if (openPopovers.includes(id)) { + setOpenPopovers(openPopovers.filter(subject => subject !== id)); } }, - [isPopoverOpen] + [openPopovers] ); useEffect(() => { - if (isPopoverOpen.length > 0) { + if (openPopovers.length > 0) { document.getElementById(ROOT_ELEMENT_ID)!.style.overflowY = 'hidden'; } else { document.getElementById(ROOT_ELEMENT_ID)!.style.overflowY = 'auto'; } - }, [isPopoverOpen]); + }, [openPopovers]); const columns: Array> = [ { @@ -84,7 +83,7 @@ export const TableView = (props: Props) => { nodeType={nodeType} closePopover={closePopoverFor(uniqueID)} currentTime={currentTime} - isPopoverOpen={isPopoverOpen.includes(uniqueID)} + isPopoverOpen={openPopovers.includes(uniqueID)} options={options} popoverPosition="rightCenter" >