-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Inventory][ECO] Entities Group By View (#195475)
# Summary This PR introduces the API and Page for doing grouped views for the Inventory Page. Alongside the plain list view, the page now by default shows a grouped view of entities. In this PR, the only current supported grouping is by Entity Type. https://github.com/user-attachments/assets/a07db592-d6c6-4ec1-a00b-bb469908aa6a Tests TBA ## How to test - Navigate to the new Inventory Page - By default, the page should load into a grouped view (Type) - The page should show all entities currently grouped by their type. - If a group has enough entities, pagination navigation should only apply to the list within the group. - The plain list view should function same as before. - Using the search/filter bar should function the same with grouped and list view. Closes #194740 --------- Co-authored-by: Bryce Buchanan <[email protected]> Co-authored-by: kibanamachine <[email protected]> Co-authored-by: Elastic Machine <[email protected]>
- Loading branch information
1 parent
b7beae8
commit e65ca78
Showing
21 changed files
with
1,037 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
...ervability_solution/inventory/public/components/grouped_inventory/group_selector.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import React from 'react'; | ||
import { render, screen } from '@testing-library/react'; | ||
import userEvent from '@testing-library/user-event'; | ||
|
||
import { GroupSelector } from './group_selector'; | ||
|
||
import { InventoryComponentWrapperMock } from './mock/inventory_component_wrapper_mock'; | ||
|
||
describe('GroupSelector', () => { | ||
beforeEach(() => { | ||
render( | ||
<InventoryComponentWrapperMock> | ||
<GroupSelector /> | ||
</InventoryComponentWrapperMock> | ||
); | ||
}); | ||
it('Should default to Type', async () => { | ||
expect(await screen.findByText('Group entities by: Type')).toBeInTheDocument(); | ||
}); | ||
|
||
it.skip('Should change to None', async () => { | ||
const user = userEvent.setup(); | ||
|
||
const selector = screen.getByText('Group entities by: Type'); | ||
|
||
expect(selector).toBeInTheDocument(); | ||
|
||
await user.click(selector); | ||
|
||
const noneOption = screen.getByTestId('panelUnified'); | ||
|
||
expect(noneOption).toBeInTheDocument(); | ||
|
||
await user.click(noneOption); | ||
|
||
expect(await screen.findByText('Group entities by: None')).toBeInTheDocument(); | ||
}); | ||
}); |
112 changes: 112 additions & 0 deletions
112
...s/observability_solution/inventory/public/components/grouped_inventory/group_selector.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { EuiPopover, EuiContextMenu, EuiButtonEmpty } from '@elastic/eui'; | ||
import React, { useCallback, useState } from 'react'; | ||
import { i18n } from '@kbn/i18n'; | ||
import { FormattedMessage } from '@kbn/i18n-react'; | ||
import type { EntityView } from '../../../common/entities'; | ||
import { useInventoryParams } from '../../hooks/use_inventory_params'; | ||
import { useInventoryRouter } from '../../hooks/use_inventory_router'; | ||
|
||
const GROUP_LABELS: Record<EntityView, string> = { | ||
unified: i18n.translate('xpack.inventory.groupedInventoryPage.noneLabel', { | ||
defaultMessage: 'None', | ||
}), | ||
grouped: i18n.translate('xpack.inventory.groupedInventoryPage.typeLabel', { | ||
defaultMessage: 'Type', | ||
}), | ||
}; | ||
|
||
export interface GroupedSelectorProps { | ||
groupSelected: string; | ||
onGroupChange: (groupSelection: string) => void; | ||
} | ||
|
||
export function GroupSelector() { | ||
const { query } = useInventoryParams('/'); | ||
const inventoryRoute = useInventoryRouter(); | ||
const [isPopoverOpen, setIsPopoverOpen] = useState(false); | ||
const groupBy = query.view ?? 'grouped'; | ||
|
||
const onGroupChange = (selected: EntityView) => { | ||
const { pagination: _, ...rest } = query; | ||
|
||
inventoryRoute.push('/', { | ||
path: {}, | ||
query: { | ||
...rest, | ||
view: groupBy === selected ? 'unified' : selected, | ||
}, | ||
}); | ||
}; | ||
|
||
const isGroupSelected = (groupKey: EntityView) => { | ||
return groupBy === groupKey; | ||
}; | ||
|
||
const panels = [ | ||
{ | ||
id: 'firstPanel', | ||
title: i18n.translate('xpack.inventory.groupedInventoryPage.groupSelectorLabel', { | ||
defaultMessage: 'Select grouping', | ||
}), | ||
items: [ | ||
{ | ||
'data-test-subj': 'panelUnified', | ||
name: GROUP_LABELS.unified, | ||
icon: isGroupSelected('unified') ? 'check' : 'empty', | ||
onClick: () => onGroupChange('unified'), | ||
}, | ||
{ | ||
'data-test-subj': 'panelType', | ||
name: GROUP_LABELS.grouped, | ||
icon: isGroupSelected('grouped') ? 'check' : 'empty', | ||
onClick: () => onGroupChange('grouped'), | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
const onButtonClick = useCallback(() => setIsPopoverOpen((currentVal) => !currentVal), []); | ||
|
||
const closePopover = useCallback(() => setIsPopoverOpen(false), []); | ||
|
||
const button = ( | ||
<EuiButtonEmpty | ||
data-test-subj="groupSelectorDropdown" | ||
iconSide="right" | ||
iconSize="s" | ||
iconType="arrowDown" | ||
onClick={onButtonClick} | ||
title={GROUP_LABELS[groupBy]} | ||
size="s" | ||
> | ||
<FormattedMessage | ||
id="xpack.inventory.groupedInventoryPage.groupedByLabel" | ||
defaultMessage={`Group entities by: {grouping}`} | ||
values={{ grouping: GROUP_LABELS[groupBy] }} | ||
/> | ||
</EuiButtonEmpty> | ||
); | ||
|
||
return ( | ||
<EuiPopover | ||
data-test-subj="inventoryGroupsPopover" | ||
button={button} | ||
closePopover={closePopover} | ||
isOpen={isPopoverOpen} | ||
panelPaddingSize="none" | ||
> | ||
<EuiContextMenu | ||
data-test-subj="entitiesGroupByContextMenu" | ||
initialPanelId="firstPanel" | ||
panels={panels} | ||
/> | ||
</EuiPopover> | ||
); | ||
} |
Oops, something went wrong.