-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
# Backport This will backport the following commits from `main` to `8.x`: - [Inventory][ECO] Entities Group By View (#195475) (e65ca78) <!--- Backport version: 8.9.8 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Gonçalo Rica Pais da Silva","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-10-30T13:43:47Z","message":"[Inventory][ECO] Entities Group By View (#195475)\n\n# Summary\r\n\r\nThis PR introduces the API and Page for doing grouped views for the\r\nInventory Page. Alongside the plain list view, the page now by default\r\nshows a grouped view of entities. In this PR, the only current supported\r\ngrouping is by Entity Type.\r\n\r\n\r\nhttps://github.com/user-attachments/assets/a07db592-d6c6-4ec1-a00b-bb469908aa6a\r\n\r\nTests TBA\r\n\r\n## How to test\r\n\r\n- Navigate to the new Inventory Page\r\n- By default, the page should load into a grouped view (Type)\r\n- The page should show all entities currently grouped by their type.\r\n- If a group has enough entities, pagination navigation should only\r\napply to the list within the group.\r\n- The plain list view should function same as before.\r\n- Using the search/filter bar should function the same with grouped and\r\nlist view.\r\n\r\nCloses #194740\r\n\r\n---------\r\n\r\nCo-authored-by: Bryce Buchanan <[email protected]>\r\nCo-authored-by: kibanamachine <[email protected]>\r\nCo-authored-by: Elastic Machine <[email protected]>","sha":"e65ca78d444b3ba324b43ea7ab07d08fc1014c13"},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[]}] BACKPORT--> Co-authored-by: Gonçalo Rica Pais da Silva <[email protected]>
- Loading branch information
1 parent
2cb9b9b
commit 6ddfb80
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.