Skip to content

Commit

Permalink
[Fleet] replace EuiFilterSelectItem with EuiSelectable (#175101)
Browse files Browse the repository at this point in the history
## Summary

Closes #162766

Replace deprecated EUI component.

Agent details: select log level

<img width="1302" alt="image"
src="https://github.com/elastic/kibana/assets/90178898/2ab0cd2c-38f3-4219-9ea2-62dfaa3a8e99">

Agent details: select dataset

<img width="1387" alt="image"
src="https://github.com/elastic/kibana/assets/90178898/4187c274-e035-4831-9d9d-87c87a3ff9c3">

Agent status filter:
<img width="1251" alt="image"
src="https://github.com/elastic/kibana/assets/90178898/15e226a2-cc10-4b43-881f-923fe03364f5">

Agent list view:
Agent policy select:
<img width="461" alt="image"
src="https://github.com/elastic/kibana/assets/90178898/4f0f697c-af33-4934-92ef-e9a8e16bf1ed">

Tags select:
<img width="280" alt="image"
src="https://github.com/elastic/kibana/assets/90178898/0be8719e-cf4b-4a1d-a4c6-c04090f72600">



### Checklist

Delete any items that are not applicable to this PR.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
  • Loading branch information
juliaElastic authored Jan 23, 2024
1 parent bd1d679 commit f77542c
Show file tree
Hide file tree
Showing 8 changed files with 402 additions and 237 deletions.
50 changes: 25 additions & 25 deletions x-pack/plugins/fleet/cypress/e2e/agents/agent_list.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,17 +165,17 @@ describe('View agents list', () => {

cy.getBySel(FLEET_AGENT_LIST_PAGE.POLICY_FILTER).click();

cy.get('button').contains('Agent policy 1');
cy.get('button').contains('Agent policy 2');
cy.get('button').contains('Agent policy 3');
cy.get('li').contains('Agent policy 1');
cy.get('li').contains('Agent policy 2');
cy.get('li').contains('Agent policy 3');
});

it('should filter on single policy (no results)', () => {
cy.visit('/app/fleet/agents');

cy.getBySel(FLEET_AGENT_LIST_PAGE.POLICY_FILTER).click();

cy.get('button').contains('Agent policy 4').click();
cy.get('li').contains('Agent policy 4').click();

assertTableIsEmpty();
});
Expand All @@ -185,7 +185,7 @@ describe('View agents list', () => {

cy.getBySel(FLEET_AGENT_LIST_PAGE.POLICY_FILTER).click();

cy.get('button').contains('Agent policy 1').click();
cy.get('li').contains('Agent policy 1').click();

cy.getBySel(FLEET_AGENT_LIST_PAGE.TABLE).find('tr').should('have.length', 2);
cy.getBySel(FLEET_AGENT_LIST_PAGE.TABLE).contains('agent-1');
Expand All @@ -196,8 +196,8 @@ describe('View agents list', () => {

cy.getBySel(FLEET_AGENT_LIST_PAGE.POLICY_FILTER).click();

cy.get('button').contains('Agent policy 1').click();
cy.get('button').contains('Agent policy 2').click();
cy.get('li').contains('Agent policy 1').click();
cy.get('li').contains('Agent policy 2').click();

cy.getBySel(FLEET_AGENT_LIST_PAGE.TABLE).find('tr').should('have.length', 3);
cy.getBySel(FLEET_AGENT_LIST_PAGE.TABLE).contains('agent-1');
Expand All @@ -208,10 +208,10 @@ describe('View agents list', () => {
describe('Agent status filter', () => {
const clearFilters = () => {
cy.getBySel(FLEET_AGENT_LIST_PAGE.STATUS_FILTER).click();
cy.get('button').contains('Healthy').click();
cy.get('button').contains('Unhealthy').click();
cy.get('button').contains('Updating').click();
cy.get('button').contains('Offline').click();
cy.get('li').contains('Healthy').click();
cy.get('li').contains('Unhealthy').click();
cy.get('li').contains('Updating').click();
cy.get('li').contains('Offline').click();
cy.getBySel(FLEET_AGENT_LIST_PAGE.STATUS_FILTER).click();
cy.wait('@getAgents');
};
Expand All @@ -220,7 +220,7 @@ describe('View agents list', () => {
clearFilters();
cy.getBySel(FLEET_AGENT_LIST_PAGE.STATUS_FILTER).click();

cy.get('button').contains('Healthy').click();
cy.get('li').contains('Healthy').click();
cy.wait('@getAgents');

assertTableContainsNAgents(18);
Expand All @@ -232,7 +232,7 @@ describe('View agents list', () => {
clearFilters();
cy.getBySel(FLEET_AGENT_LIST_PAGE.STATUS_FILTER).click();

cy.get('button').contains('Unhealthy').click();
cy.get('li').contains('Unhealthy').click();
cy.wait('@getAgents');

assertTableContainsNAgents(1);
Expand All @@ -245,7 +245,7 @@ describe('View agents list', () => {

cy.getBySel(FLEET_AGENT_LIST_PAGE.STATUS_FILTER).click();

cy.get('button').contains('Inactive').click();
cy.get('li').contains('Inactive').click();

cy.getBySel(FLEET_AGENT_LIST_PAGE.TABLE).contains('No agents found');
});
Expand All @@ -256,8 +256,8 @@ describe('View agents list', () => {

cy.getBySel(FLEET_AGENT_LIST_PAGE.STATUS_FILTER).click();

cy.get('button').contains('Healthy').click();
cy.get('button').contains('Unhealthy').click();
cy.get('li').contains('Healthy').click();
cy.get('li').contains('Unhealthy').click();
cy.wait('@getAgents');

assertTableContainsNAgents(18);
Expand All @@ -270,7 +270,7 @@ describe('View agents list', () => {
it('should allow to filter on one tag (tag1)', () => {
cy.visit('/app/fleet/agents');
cy.getBySel(FLEET_AGENT_LIST_PAGE.TAGS_FILTER).click();
cy.get('button').contains('tag1').click();
cy.get('li').contains('tag1').click();

assertTableContainsNAgents(2);
cy.getBySel(FLEET_AGENT_LIST_PAGE.TABLE).contains('agent-3');
Expand All @@ -280,8 +280,8 @@ describe('View agents list', () => {
it('should allow to filter on multiple tag (tag1, tag2)', () => {
cy.visit('/app/fleet/agents');
cy.getBySel(FLEET_AGENT_LIST_PAGE.TAGS_FILTER).click();
cy.get('button').contains('tag1').click();
cy.get('button').contains('tag2').click();
cy.get('li').contains('tag1').click();
cy.get('li').contains('tag2').click();
cy.wait('@getAgents');

assertTableContainsNAgents(4);
Expand All @@ -294,8 +294,8 @@ describe('View agents list', () => {
it('should allow to clear filters', () => {
cy.visit('/app/fleet/agents');
cy.getBySel(FLEET_AGENT_LIST_PAGE.TAGS_FILTER).click();
cy.get('button').contains('tag1').click();
cy.get('button').contains('tag2').click();
cy.get('li').contains('tag1').click();
cy.get('li').contains('tag2').click();
cy.getBySel(FLEET_AGENT_LIST_PAGE.TAGS_FILTER).click();

assertTableContainsNAgents(4);
Expand All @@ -311,7 +311,7 @@ describe('View agents list', () => {

cy.getBySel(FLEET_AGENT_LIST_PAGE.POLICY_FILTER).click();

cy.get('button').contains('Agent policy 3').click();
cy.get('li').contains('Agent policy 3').click();
assertTableContainsNAgents(15);

cy.getBySel(FLEET_AGENT_LIST_PAGE.CHECKBOX_SELECT_ALL).click();
Expand Down Expand Up @@ -345,7 +345,7 @@ describe('View agents list', () => {

cy.getBySel(FLEET_AGENT_LIST_PAGE.POLICY_FILTER).click();

cy.get('button').contains('Agent policy 3').click();
cy.get('li').contains('Agent policy 3').click();
assertTableContainsNAgents(15);
cy.getBySel(FLEET_AGENT_LIST_PAGE.CHECKBOX_SELECT_ALL).click();
// Trigger a bulk upgrade
Expand All @@ -362,7 +362,7 @@ describe('View agents list', () => {
cy.visit('/app/fleet/agents');

cy.getBySel(FLEET_AGENT_LIST_PAGE.POLICY_FILTER).click();
cy.get('button').contains('Agent policy 3').click();
cy.get('li').contains('Agent policy 3').click();
cy.wait('@getAgents');
assertTableContainsNAgents(15);
cy.getBySel(FLEET_AGENT_LIST_PAGE.CHECKBOX_SELECT_ALL).click();
Expand All @@ -375,7 +375,7 @@ describe('View agents list', () => {
assertTableIsEmpty();
// Select new policy is filters
cy.getBySel(FLEET_AGENT_LIST_PAGE.POLICY_FILTER).click();
cy.get('button').contains('Agent policy 4').click();
cy.get('li').contains('Agent policy 4').click();
cy.wait('@getAgents');
assertTableContainsNAgents(15);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
*/

import React, { memo, useState, useEffect, useCallback } from 'react';
import { EuiPopover, EuiFilterButton, EuiFilterSelectItem } from '@elastic/eui';
import type { EuiSelectableOption } from '@elastic/eui';
import { EuiPopover, EuiFilterButton, EuiSelectable } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import type { DataViewField, FieldSpec } from '@kbn/data-views-plugin/public';

Expand All @@ -26,6 +27,20 @@ export const DatasetFilter: React.FunctionComponent<{
const togglePopover = useCallback(() => setIsOpen((prevIsOpen) => !prevIsOpen), [setIsOpen]);
const closePopover = useCallback(() => setIsOpen(false), [setIsOpen]);

const datasetValuesToOptions = useCallback(
(values: string[]): EuiSelectableOption[] => {
return values.map((value) => ({
label: value,
checked: selectedDatasets.includes(value) ? 'on' : undefined,
key: value,
}));
},
[selectedDatasets]
);
const [options, setOptions] = useState<EuiSelectableOption[]>(
datasetValuesToOptions(datasetValues)
);

useEffect(() => {
const fetchValues = async () => {
setIsLoading(true);
Expand All @@ -47,14 +62,18 @@ export const DatasetFilter: React.FunctionComponent<{
field: DATASET_FIELD as DataViewField,
query: '',
});
if (values.length > 0) setDatasetValues(values.sort());
if (values.length > 0) {
setDatasetValues(values.sort());
setOptions(datasetValuesToOptions(values.sort()));
}
} catch (e) {
setDatasetValues([AGENT_DATASET]);
setOptions(datasetValuesToOptions([AGENT_DATASET]));
}
setIsLoading(false);
};
fetchValues();
}, [data.dataViews, unifiedSearch.autocomplete]);
}, [data.dataViews, unifiedSearch.autocomplete, datasetValuesToOptions]);

return (
<EuiPopover
Expand All @@ -78,15 +97,28 @@ export const DatasetFilter: React.FunctionComponent<{
closePopover={closePopover}
panelPaddingSize="none"
>
{datasetValues.map((dataset) => (
<EuiFilterSelectItem
checked={selectedDatasets.includes(dataset) ? 'on' : undefined}
key={dataset}
onClick={() => onToggleDataset(dataset)}
>
{dataset}
</EuiFilterSelectItem>
))}
<EuiSelectable
options={options}
onChange={(newOptions) => {
setOptions(newOptions);
newOptions.forEach((option, index) => {
if (option.checked !== options[index].checked) {
onToggleDataset(option.label);
return;
}
});
}}
data-test-subj="agentList.datasetFilterOptions"
isLoading={isLoading}
listProps={{
paddingSize: 's',
style: {
minWidth: 220,
},
}}
>
{(list) => list}
</EuiSelectable>
</EuiPopover>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
*/

import React, { memo, useState, useCallback } from 'react';
import { EuiPopover, EuiFilterButton, EuiFilterSelectItem } from '@elastic/eui';
import type { EuiSelectableOption } from '@elastic/eui';
import { EuiPopover, EuiFilterButton, EuiSelectable } from '@elastic/eui';
import { i18n } from '@kbn/i18n';

import { AGENT_LOG_LEVELS } from './constants';
Expand All @@ -22,15 +23,13 @@ export const LogLevelFilter: React.FunctionComponent<{
const togglePopover = useCallback(() => setIsOpen((prevIsOpen) => !prevIsOpen), []);
const closePopover = useCallback(() => setIsOpen(false), []);

const filterSelect = LEVEL_VALUES.map((level) => (
<EuiFilterSelectItem
checked={selectedLevels.includes(level) ? 'on' : undefined}
key={level}
onClick={() => onToggleLevel(level)}
>
{level}
</EuiFilterSelectItem>
));
const [options, setOptions] = useState<EuiSelectableOption[]>(
LEVEL_VALUES.map((level) => ({
label: level,
checked: selectedLevels.includes(level) ? 'on' : undefined,
key: level,
}))
);

return (
<EuiPopover
Expand All @@ -53,7 +52,24 @@ export const LogLevelFilter: React.FunctionComponent<{
closePopover={closePopover}
panelPaddingSize="none"
>
{filterSelect}
<EuiSelectable
options={options}
onChange={(newOptions) => {
setOptions(newOptions);
newOptions.forEach((option, index) => {
if (option.checked !== options[index].checked) {
onToggleLevel(option.label);
return;
}
});
}}
data-test-subj="agentList.logLevelFilterOptions"
listProps={{
paddingSize: 's',
}}
>
{(list) => list}
</EuiSelectable>
</EuiPopover>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,21 @@ describe('AgentStatusFilter', () => {
it('Should should show difference between last seen inactive agents and total agents', async () => {
mockLocalStorage['fleet.lastSeenInactiveAgentsCount'] = '100';

const { getByText, container } = renderComponent({
const { getByText, getByTestId } = renderComponent({
selectedStatus: [],
onSelectedStatusChange: () => {},
totalInactiveAgents: 999,
});

await act(async () => {
const statusFilterButton = container.querySelector(
'[data-test-subj="agentList.statusFilter"]'
);
const statusFilterButton = getByTestId('agentList.statusFilter');

expect(statusFilterButton).not.toBeNull();
fireEvent.click(statusFilterButton!);
fireEvent.click(statusFilterButton);

await waitFor(() => expect(getByText('899')).toBeInTheDocument());
await waitFor(() => {
expect(getByTestId('agentList.agentStatusFilterOptions')).toBeInTheDocument();
expect(getByText('899')).toBeInTheDocument();
});
});
});
});
Loading

0 comments on commit f77542c

Please sign in to comment.