mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Infrastructure UI] Fix inventory table pagination navigation (#153849)
## 📓 Summary Closes #153739 Each time the whole inventory table was rerendering due to a click on an entry, a new list of items was regenerated, reinitializing the in-memory table component from the first page. Memoizing the generated items solves the issue and the table work as expected. This PR also solve another issue occurring when multiple table entries were clicked, which resulted in many popovers opened and a blocked UI as per the following screenshot: <img width="1267" alt="multi-popover" src="https://user-images.githubusercontent.com/34506779/228196645-9c0444b7-9114-47c2-8e5d-0bec29ed5305.png"> ## 🧪 Testing - Navigate to `Inventory` and select the `Kubernetes Pods` option from the **Show** filter. - Switch the view to a table with the top-right selector - Verify the popover correctly opens on any entry of the first table page, then switch to different pages and check the behaviour is maintained and there are no reinitializations for the table. - Verify the same from the `Docker Containers` list. https://user-images.githubusercontent.com/34506779/228198613-afafe3fe-f714-4c88-a288-fc4c95ca801a.mov Co-authored-by: Marco Antonio Ghiani <marcoantonio.ghiani@elastic.co>
This commit is contained in:
parent
598453d2d3
commit
f17457b86e
2 changed files with 38 additions and 56 deletions
|
@ -7,8 +7,6 @@
|
|||
|
||||
import { APP_WRAPPER_CLASS } from '@kbn/core/public';
|
||||
|
||||
export const CONTAINER_CLASSNAME = 'infra-container-element';
|
||||
|
||||
export const prepareMountElement = (element: HTMLElement, testSubject?: string) => {
|
||||
// Ensure all wrapping elements have the APP_WRAPPER_CLASS so that the KinanaPageTemplate works as expected
|
||||
element.classList.add(APP_WRAPPER_CLASS);
|
||||
|
|
|
@ -9,7 +9,7 @@ import { EuiButtonEmpty, EuiInMemoryTable, EuiToolTip, EuiBasicTableColumn } fro
|
|||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { last, first } from 'lodash';
|
||||
import React, { useState, useCallback, useEffect } from 'react';
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import { EuiPopover } from '@elastic/eui';
|
||||
import { createWaffleMapNode } from '../lib/nodes_to_wafflemap';
|
||||
import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../lib/lib';
|
||||
|
@ -17,7 +17,6 @@ import { fieldToName } from '../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 { CONTAINER_CLASSNAME } from '../../../../apps/common_styles';
|
||||
|
||||
interface Props {
|
||||
nodes: SnapshotNode[];
|
||||
|
@ -28,6 +27,13 @@ interface Props {
|
|||
onFilter: (filter: string) => void;
|
||||
}
|
||||
|
||||
const initialSorting = {
|
||||
sort: {
|
||||
field: 'value',
|
||||
direction: 'desc',
|
||||
},
|
||||
} as const;
|
||||
|
||||
const getGroupPaths = (path: SnapshotNodePath[]) => {
|
||||
switch (path.length) {
|
||||
case 3:
|
||||
|
@ -41,33 +47,10 @@ const getGroupPaths = (path: SnapshotNodePath[]) => {
|
|||
|
||||
export const TableView = (props: Props) => {
|
||||
const { nodes, options, formatter, currentTime, nodeType } = props;
|
||||
const [openPopovers, setOpenPopovers] = useState<string[]>([]);
|
||||
const openPopoverFor = useCallback(
|
||||
(id: string) => () => {
|
||||
setOpenPopovers([...openPopovers, id]);
|
||||
},
|
||||
[openPopovers]
|
||||
);
|
||||
|
||||
const closePopoverFor = useCallback(
|
||||
(id: string) => () => {
|
||||
if (openPopovers.includes(id)) {
|
||||
setOpenPopovers(openPopovers.filter((subject) => subject !== id));
|
||||
}
|
||||
},
|
||||
[openPopovers]
|
||||
);
|
||||
const [openPopoverId, setOpenPopoverId] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const el = document.getElementsByClassName(CONTAINER_CLASSNAME)[0];
|
||||
if (el instanceof HTMLElement) {
|
||||
if (openPopovers.length > 0) {
|
||||
el.style.overflowY = 'hidden';
|
||||
} else {
|
||||
el.style.overflowY = 'auto';
|
||||
}
|
||||
}
|
||||
}, [openPopovers]);
|
||||
const closePopover = () => setOpenPopoverId(null);
|
||||
|
||||
const columns: Array<EuiBasicTableColumn<typeof items[number]>> = [
|
||||
{
|
||||
|
@ -84,7 +67,10 @@ export const TableView = (props: Props) => {
|
|||
const uniqueID = [...item.node.path.map((p) => p.value), item.node.name].join(':');
|
||||
const button = (
|
||||
<EuiToolTip content={tooltipText}>
|
||||
<EuiButtonEmpty data-test-subj="infraColumnsButton" onClick={openPopoverFor(uniqueID)}>
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="infraColumnsButton"
|
||||
onClick={() => setOpenPopoverId(uniqueID)}
|
||||
>
|
||||
{value}
|
||||
</EuiButtonEmpty>
|
||||
</EuiToolTip>
|
||||
|
@ -93,8 +79,8 @@ export const TableView = (props: Props) => {
|
|||
return (
|
||||
<EuiPopover
|
||||
button={button}
|
||||
isOpen={openPopovers.includes(uniqueID)}
|
||||
closePopover={closePopoverFor(uniqueID)}
|
||||
isOpen={openPopoverId === uniqueID}
|
||||
closePopover={closePopover}
|
||||
anchorPosition="rightCenter"
|
||||
>
|
||||
<NodeContextMenu
|
||||
|
@ -152,30 +138,28 @@ export const TableView = (props: Props) => {
|
|||
},
|
||||
];
|
||||
|
||||
const items = nodes.map((node) => {
|
||||
const name = last(node.path);
|
||||
const metric = first(node.metrics);
|
||||
return {
|
||||
name: (name && name.label) || 'unknown',
|
||||
...getGroupPaths(node.path).reduce(
|
||||
(acc, path, index) => ({
|
||||
...acc,
|
||||
[`group_${index}`]: path.label,
|
||||
}),
|
||||
{}
|
||||
),
|
||||
value: (metric && metric.value) || 0,
|
||||
avg: (metric && metric.avg) || 0,
|
||||
max: (metric && metric.max) || 0,
|
||||
node: createWaffleMapNode(node),
|
||||
};
|
||||
});
|
||||
const initialSorting = {
|
||||
sort: {
|
||||
field: 'value',
|
||||
direction: 'desc',
|
||||
},
|
||||
} as const;
|
||||
const items = useMemo(
|
||||
() =>
|
||||
nodes.map((node) => {
|
||||
const name = last(node.path);
|
||||
const metric = first(node.metrics);
|
||||
return {
|
||||
name: (name && name.label) || 'unknown',
|
||||
...getGroupPaths(node.path).reduce(
|
||||
(acc, path, index) => ({
|
||||
...acc,
|
||||
[`group_${index}`]: path.label,
|
||||
}),
|
||||
{}
|
||||
),
|
||||
value: (metric && metric.value) || 0,
|
||||
avg: (metric && metric.avg) || 0,
|
||||
max: (metric && metric.max) || 0,
|
||||
node: createWaffleMapNode(node),
|
||||
};
|
||||
}),
|
||||
[nodes]
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiInMemoryTable pagination={true} sorting={initialSorting} items={items} columns={columns} />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue