mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[Security Solution][Endpoint][Response Actions]fix tray collapse on history page (#165260)
## Summary
Fixes a bug on the response actions history page where the details tray
does not collapse on a single click.
**before**
elastic/kibana/issues/165058
**after**

### Checklist
- [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
This commit is contained in:
parent
a2e841e6e4
commit
c9c7f076ba
4 changed files with 41 additions and 25 deletions
|
@ -7,19 +7,19 @@
|
||||||
import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
EuiI18nNumber,
|
type CriteriaWithPagination,
|
||||||
EuiAvatar,
|
EuiAvatar,
|
||||||
EuiBasicTable,
|
EuiBasicTable,
|
||||||
EuiButtonIcon,
|
EuiButtonIcon,
|
||||||
EuiFacetButton,
|
EuiFacetButton,
|
||||||
EuiHorizontalRule,
|
EuiHorizontalRule,
|
||||||
RIGHT_ALIGNMENT,
|
EuiI18nNumber,
|
||||||
EuiScreenReaderOnly,
|
EuiScreenReaderOnly,
|
||||||
|
EuiSkeletonText,
|
||||||
EuiText,
|
EuiText,
|
||||||
EuiToolTip,
|
EuiToolTip,
|
||||||
type HorizontalAlignment,
|
type HorizontalAlignment,
|
||||||
type CriteriaWithPagination,
|
RIGHT_ALIGNMENT,
|
||||||
EuiSkeletonText,
|
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
||||||
import { FormattedMessage } from '@kbn/i18n-react';
|
import { FormattedMessage } from '@kbn/i18n-react';
|
||||||
|
@ -30,14 +30,13 @@ import { SecuritySolutionLinkAnchor } from '../../../../common/components/links'
|
||||||
import type { ActionListApiResponse } from '../../../../../common/endpoint/types';
|
import type { ActionListApiResponse } from '../../../../../common/endpoint/types';
|
||||||
import type { EndpointActionListRequestQuery } from '../../../../../common/api/endpoint';
|
import type { EndpointActionListRequestQuery } from '../../../../../common/api/endpoint';
|
||||||
import { FormattedDate } from '../../../../common/components/formatted_date';
|
import { FormattedDate } from '../../../../common/components/formatted_date';
|
||||||
import { TABLE_COLUMN_NAMES, UX_MESSAGES, ARIA_LABELS } from '../translations';
|
import { ARIA_LABELS, TABLE_COLUMN_NAMES, UX_MESSAGES } from '../translations';
|
||||||
import { getActionStatus, getUiCommand } from './hooks';
|
import { getActionStatus, getUiCommand } from './hooks';
|
||||||
import { getEmptyValue } from '../../../../common/components/empty_value';
|
import { getEmptyValue } from '../../../../common/components/empty_value';
|
||||||
import { StatusBadge } from './status_badge';
|
import { StatusBadge } from './status_badge';
|
||||||
import { ActionsLogExpandedTray } from './action_log_expanded_tray';
|
import { ActionsLogExpandedTray } from './action_log_expanded_tray';
|
||||||
import { useTestIdGenerator } from '../../../hooks/use_test_id_generator';
|
import { useTestIdGenerator } from '../../../hooks/use_test_id_generator';
|
||||||
import { MANAGEMENT_PAGE_SIZE_OPTIONS } from '../../../common/constants';
|
import { MANAGEMENT_PAGE_SIZE_OPTIONS } from '../../../common/constants';
|
||||||
import { useActionHistoryUrlParams } from './use_action_history_url_params';
|
|
||||||
import { useUrlPagination } from '../../../hooks/use_url_pagination';
|
import { useUrlPagination } from '../../../hooks/use_url_pagination';
|
||||||
|
|
||||||
const emptyValue = getEmptyValue();
|
const emptyValue = getEmptyValue();
|
||||||
|
@ -292,22 +291,19 @@ export const ActionsLogTable = memo<ActionsLogTableProps>(
|
||||||
}) => {
|
}) => {
|
||||||
const getTestId = useTestIdGenerator(dataTestSubj);
|
const getTestId = useTestIdGenerator(dataTestSubj);
|
||||||
const { pagination: paginationFromUrlParams } = useUrlPagination();
|
const { pagination: paginationFromUrlParams } = useUrlPagination();
|
||||||
const { withOutputs: withOutputsFromUrl } = useActionHistoryUrlParams();
|
|
||||||
|
|
||||||
const [expandedRowMap, setExpandedRowMap] = useState<ExpandedRowMapType>({});
|
const [expandedRowMap, setExpandedRowMap] = useState<ExpandedRowMapType>({});
|
||||||
|
|
||||||
const actionIdsWithOpenTrays = useMemo((): string[] => {
|
const actionIdsWithOpenTrays = useMemo(
|
||||||
// get the list of action ids from URL params on the history page
|
(): string[] =>
|
||||||
if (!isFlyout) {
|
// get the list of action ids from the query params for flyout view
|
||||||
return withOutputsFromUrl ?? [];
|
queryParams.withOutputs
|
||||||
}
|
? typeof queryParams.withOutputs === 'string'
|
||||||
// get the list of action ids form the query params for flyout view
|
? [queryParams.withOutputs]
|
||||||
return queryParams.withOutputs
|
: queryParams.withOutputs
|
||||||
? typeof queryParams.withOutputs === 'string'
|
: [],
|
||||||
? [queryParams.withOutputs]
|
[queryParams.withOutputs]
|
||||||
: queryParams.withOutputs
|
);
|
||||||
: [];
|
|
||||||
}, [isFlyout, queryParams.withOutputs, withOutputsFromUrl]);
|
|
||||||
|
|
||||||
const redoOpenTrays = useCallback(() => {
|
const redoOpenTrays = useCallback(() => {
|
||||||
if (actionIdsWithOpenTrays.length && items.length) {
|
if (actionIdsWithOpenTrays.length && items.length) {
|
||||||
|
|
|
@ -7,12 +7,13 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as reactTestingLibrary from '@testing-library/react';
|
import * as reactTestingLibrary from '@testing-library/react';
|
||||||
|
import { waitFor } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl';
|
import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl';
|
||||||
import type { IHttpFetchError } from '@kbn/core-http-browser';
|
import type { IHttpFetchError } from '@kbn/core-http-browser';
|
||||||
import {
|
import {
|
||||||
createAppRootMockRenderer,
|
|
||||||
type AppContextTestRender,
|
type AppContextTestRender,
|
||||||
|
createAppRootMockRenderer,
|
||||||
} from '../../../../common/mock/endpoint';
|
} from '../../../../common/mock/endpoint';
|
||||||
import { ResponseActionsLog } from '../response_actions_log';
|
import { ResponseActionsLog } from '../response_actions_log';
|
||||||
import type {
|
import type {
|
||||||
|
@ -29,7 +30,6 @@ import { v4 as uuidv4 } from 'uuid';
|
||||||
import { RESPONSE_ACTION_API_COMMANDS_NAMES } from '../../../../../common/endpoint/service/response_actions/constants';
|
import { RESPONSE_ACTION_API_COMMANDS_NAMES } from '../../../../../common/endpoint/service/response_actions/constants';
|
||||||
import { useUserPrivileges as _useUserPrivileges } from '../../../../common/components/user_privileges';
|
import { useUserPrivileges as _useUserPrivileges } from '../../../../common/components/user_privileges';
|
||||||
import { responseActionsHttpMocks } from '../../../mocks/response_actions_http_mocks';
|
import { responseActionsHttpMocks } from '../../../mocks/response_actions_http_mocks';
|
||||||
import { waitFor } from '@testing-library/react';
|
|
||||||
import { getEndpointAuthzInitialStateMock } from '../../../../../common/endpoint/service/authz/mocks';
|
import { getEndpointAuthzInitialStateMock } from '../../../../../common/endpoint/service/authz/mocks';
|
||||||
import { useGetEndpointActionList as _useGetEndpointActionList } from '../../../hooks/response_actions/use_get_endpoint_action_list';
|
import { useGetEndpointActionList as _useGetEndpointActionList } from '../../../hooks/response_actions/use_get_endpoint_action_list';
|
||||||
import { OUTPUT_MESSAGES } from '../translations';
|
import { OUTPUT_MESSAGES } from '../translations';
|
||||||
|
@ -470,7 +470,7 @@ describe('Response actions history', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should expand each row to show details', async () => {
|
it('should expand/collapse each row to show/hide details', async () => {
|
||||||
render();
|
render();
|
||||||
const { getAllByTestId, queryAllByTestId } = renderResult;
|
const { getAllByTestId, queryAllByTestId } = renderResult;
|
||||||
|
|
||||||
|
@ -961,8 +961,7 @@ describe('Response actions history', () => {
|
||||||
|
|
||||||
const expandButtons = getAllByTestId(`${testPrefix}-expand-button`);
|
const expandButtons = getAllByTestId(`${testPrefix}-expand-button`);
|
||||||
expandButtons.map((button) => userEvent.click(button));
|
expandButtons.map((button) => userEvent.click(button));
|
||||||
const outputs = getAllByTestId(`${testPrefix}-details-tray-output`);
|
return getAllByTestId(`${testPrefix}-details-tray-output`);
|
||||||
return outputs;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
it.each(RESPONSE_ACTION_API_COMMANDS_NAMES)(
|
it.each(RESPONSE_ACTION_API_COMMANDS_NAMES)(
|
||||||
|
|
|
@ -50,4 +50,25 @@ describe('Response actions history page', () => {
|
||||||
cy.getByTestSubj('pagination-button-0').click();
|
cy.getByTestSubj('pagination-button-0').click();
|
||||||
cy.getByTestSubj('response-actions-list-details-tray').should('exist');
|
cy.getByTestSubj('response-actions-list-details-tray').should('exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('collapses expanded tray with a single click', () => {
|
||||||
|
loadPage(`/app/security/administration/response_actions_history`);
|
||||||
|
// 2nd row on 1st page
|
||||||
|
const row = cy.getByTestSubj('response-actions-list-expand-button').eq(1);
|
||||||
|
|
||||||
|
// expand the row
|
||||||
|
row.click();
|
||||||
|
cy.getByTestSubj('response-actions-list-details-tray').should('exist');
|
||||||
|
cy.url().should('include', 'withOutputs');
|
||||||
|
|
||||||
|
// collapse the row
|
||||||
|
cy.intercept('GET', '/api/endpoint/action*').as('getResponses');
|
||||||
|
row.click();
|
||||||
|
// wait for the API response to come back
|
||||||
|
// and then see if the tray is actually closed
|
||||||
|
cy.wait('@getResponses', { timeout: 500 }).then(() => {
|
||||||
|
cy.getByTestSubj('response-actions-list-details-tray').should('not.exist');
|
||||||
|
cy.url().should('not.include', 'withOutputs');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -236,7 +236,7 @@ describe('Response actions history page', () => {
|
||||||
return {
|
return {
|
||||||
id: `agent-id-${i}`,
|
id: `agent-id-${i}`,
|
||||||
name: `Host-name-${i}`,
|
name: `Host-name-${i}`,
|
||||||
selected: [0, 1, 3, 5].includes(i) ? true : false,
|
selected: [0, 1, 3, 5].includes(i),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
page: 0,
|
page: 0,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue