Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solution][Endpoint] Fix UI inconsistency between isolation forms and remove display of Pending isolation statuses #106118

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ describe('when using the EndpointHostIsolationStatus component', () => {
expect(getByTestId('test').textContent).toBe('Isolated');
});

it.each([
// FIXME: un-skip when we bring back the pending isolation statuses
it.skip.each([
['Isolating', { pendingIsolate: 2 }],
['Releasing', { pendingUnIsolate: 2 }],
['4 actions pending', { isIsolated: true, pendingUnIsolate: 2, pendingIsolate: 2 }],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
*/

import React, { memo, useMemo } from 'react';
import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiTextColor, EuiToolTip } from '@elastic/eui';
import { EuiBadge } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { useTestIdGenerator } from '../../../../management/components/hooks/use_test_id_generator';
// import { useTestIdGenerator } from '../../../../management/components/hooks/use_test_id_generator';

export interface EndpointHostIsolationStatusProps {
isIsolated: boolean;
Expand All @@ -25,94 +25,114 @@ export interface EndpointHostIsolationStatusProps {
* (`null` is returned)
*/
export const EndpointHostIsolationStatus = memo<EndpointHostIsolationStatusProps>(
({ isIsolated, pendingIsolate = 0, pendingUnIsolate = 0, 'data-test-subj': dataTestSubj }) => {
const getTestId = useTestIdGenerator(dataTestSubj);
({
isIsolated,
/* pendingIsolate = 0, pendingUnIsolate = 0,*/ 'data-test-subj': dataTestSubj,
}) => {
// const getTestId = useTestIdGenerator(dataTestSubj);

return useMemo(() => {
// If nothing is pending and host is not currently isolated, then render nothing
if (!isIsolated && !pendingIsolate && !pendingUnIsolate) {
if (!isIsolated) {
return null;
}
// if (!isIsolated && !pendingIsolate && !pendingUnIsolate) {
// return null;
// }

// If nothing is pending, but host is isolated, then show isolation badge
if (!pendingIsolate && !pendingUnIsolate) {
return (
<EuiBadge color="hollow" data-test-subj={dataTestSubj}>
<FormattedMessage
id="xpack.securitySolution.endpoint.hostIsolationStatus.isolated"
defaultMessage="Isolated"
/>
</EuiBadge>
);
}

// If there are multiple types of pending isolation actions, then show count of actions with tooltip that displays breakdown
if (pendingIsolate && pendingUnIsolate) {
return (
<EuiBadge color="hollow" data-test-subj={dataTestSubj}>
<EuiToolTip
display="block"
anchorClassName="eui-textTruncate"
content={
<div data-test-subj={getTestId('tooltipContent')}>
<div>
<FormattedMessage
id="xpack.securitySolution.endpoint.hostIsolationStatus.tooltipPendingActions"
defaultMessage="Pending actions:"
/>
</div>
<EuiFlexGroup gutterSize="none" justifyContent="spaceBetween">
<EuiFlexItem grow>
<FormattedMessage
id="xpack.securitySolution.endpoint.hostIsolationStatus.tooltipPendingIsolate"
defaultMessage="Isolate"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>{pendingIsolate}</EuiFlexItem>
</EuiFlexGroup>
<EuiFlexGroup gutterSize="none">
<EuiFlexItem grow>
<FormattedMessage
id="xpack.securitySolution.endpoint.hostIsolationStatus.tooltipPendingUnIsolate"
defaultMessage="Release"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>{pendingUnIsolate}</EuiFlexItem>
</EuiFlexGroup>
</div>
}
>
<EuiTextColor color="subdued" data-test-subj={getTestId('pending')}>
<FormattedMessage
id="xpack.securitySolution.endpoint.hostIsolationStatus.multiplePendingActions"
defaultMessage="{count} actions pending"
values={{ count: pendingIsolate + pendingUnIsolate }}
/>
</EuiTextColor>
</EuiToolTip>
</EuiBadge>
);
}

// Show 'pending [un]isolate' depending on what's pending
return (
<EuiBadge color="hollow" data-test-subj={dataTestSubj}>
<EuiTextColor color="subdued" data-test-subj={getTestId('pending')}>
{pendingIsolate ? (
<FormattedMessage
id="xpack.securitySolution.endpoint.hostIsolationStatus.isIsolating"
defaultMessage="Isolating"
/>
) : (
<FormattedMessage
id="xpack.securitySolution.endpoint.hostIsolationStatus.isUnIsolating"
defaultMessage="Releasing"
/>
)}
</EuiTextColor>
<FormattedMessage
id="xpack.securitySolution.endpoint.hostIsolationStatus.isolated"
defaultMessage="Isolated"
/>
</EuiBadge>
);
}, [dataTestSubj, getTestId, isIsolated, pendingIsolate, pendingUnIsolate]);

// If nothing is pending and host is not currently isolated, then render nothing
// if (!isIsolated && !pendingIsolate && !pendingUnIsolate) {
// return null;
// }
//
// // If nothing is pending, but host is isolated, then show isolation badge
// if (!pendingIsolate && !pendingUnIsolate) {
// return (
// <EuiBadge color="hollow" data-test-subj={dataTestSubj}>
// <FormattedMessage
// id="xpack.securitySolution.endpoint.hostIsolationStatus.isolated"
// defaultMessage="Isolated"
// />
// </EuiBadge>
// );
// }
//
// // If there are multiple types of pending isolation actions, then show count of actions with tooltip that displays breakdown
// if (pendingIsolate && pendingUnIsolate) {
// return (
// <EuiBadge color="hollow" data-test-subj={dataTestSubj}>
// <EuiToolTip
// display="block"
// anchorClassName="eui-textTruncate"
// content={
// <div data-test-subj={getTestId('tooltipContent')}>
// <div>
// <FormattedMessage
// id="xpack.securitySolution.endpoint.hostIsolationStatus.tooltipPendingActions"
// defaultMessage="Pending actions:"
// />
// </div>
// <EuiFlexGroup gutterSize="none" justifyContent="spaceBetween">
// <EuiFlexItem grow>
// <FormattedMessage
// id="xpack.securitySolution.endpoint.hostIsolationStatus.tooltipPendingIsolate"
// defaultMessage="Isolate"
// />
// </EuiFlexItem>
// <EuiFlexItem grow={false}>{pendingIsolate}</EuiFlexItem>
// </EuiFlexGroup>
// <EuiFlexGroup gutterSize="none">
// <EuiFlexItem grow>
// <FormattedMessage
// id="xpack.securitySolution.endpoint.hostIsolationStatus.tooltipPendingUnIsolate"
// defaultMessage="Release"
// />
// </EuiFlexItem>
// <EuiFlexItem grow={false}>{pendingUnIsolate}</EuiFlexItem>
// </EuiFlexGroup>
// </div>
// }
// >
// <EuiTextColor color="subdued" data-test-subj={getTestId('pending')}>
// <FormattedMessage
// id="xpack.securitySolution.endpoint.hostIsolationStatus.multiplePendingActions"
// defaultMessage="{count} actions pending"
// values={{ count: pendingIsolate + pendingUnIsolate }}
// />
// </EuiTextColor>
// </EuiToolTip>
// </EuiBadge>
// );
// }
//
// // Show 'pending [un]isolate' depending on what's pending
// return (
// <EuiBadge color="hollow" data-test-subj={dataTestSubj}>
// <EuiTextColor color="subdued" data-test-subj={getTestId('pending')}>
// {pendingIsolate ? (
// <FormattedMessage
// id="xpack.securitySolution.endpoint.hostIsolationStatus.isIsolating"
// defaultMessage="Isolating"
// />
// ) : (
// <FormattedMessage
// id="xpack.securitySolution.endpoint.hostIsolationStatus.isUnIsolating"
// defaultMessage="Releasing"
// />
// )}
// </EuiTextColor>
// </EuiBadge>
// );
}, [dataTestSubj, isIsolated /* , getTestId , pendingIsolate, pendingUnIsolate*/]);
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import {
EuiButtonEmpty,
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
EuiForm,
EuiFormRow,
EuiText,
EuiTextArea,
EuiTitle,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { CANCEL, COMMENT, COMMENT_PLACEHOLDER, CONFIRM, UNISOLATE, ISOLATED } from './translations';
Expand All @@ -30,50 +30,49 @@ export const EndpointUnisolateForm = memo<EndpointIsolatedFormProps>(
);

return (
<>
<EuiText size="s">
<p>
<FormattedMessage
id="xpack.securitySolution.endpoint.hostIsolation.unIsolateThisHost"
defaultMessage="{hostName} is currently {isolated}. Are you sure you want to {unisolate} this host?"
values={{
hostName: <b>{hostName}</b>,
isolated: <b>{ISOLATED}</b>,
unisolate: <b>{UNISOLATE}</b>,
}}
/>{' '}
{messageAppend}
</p>
</EuiText>
<EuiForm>
<EuiFormRow fullWidth>
<EuiText size="s">
<p>
<FormattedMessage
id="xpack.securitySolution.endpoint.hostIsolation.unIsolateThisHost"
defaultMessage="{hostName} is currently {isolated}. Are you sure you want to {unisolate} this host?"
values={{
hostName: <b>{hostName}</b>,
isolated: <b>{ISOLATED}</b>,
unisolate: <b>{UNISOLATE}</b>,
}}
/>{' '}
{messageAppend}
</p>
</EuiText>
</EuiFormRow>

<EuiSpacer size="m" />
<EuiFormRow label={COMMENT} fullWidth>
<EuiTextArea
data-test-subj="host_isolation_comment"
fullWidth
placeholder={COMMENT_PLACEHOLDER}
value={comment}
onChange={handleCommentChange}
/>
</EuiFormRow>

<EuiTitle size="xs">
<h4>{COMMENT}</h4>
</EuiTitle>
<EuiTextArea
data-test-subj="host_isolation_comment"
fullWidth
placeholder={COMMENT_PLACEHOLDER}
value={comment}
onChange={handleCommentChange}
/>

<EuiSpacer size="m" />

<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={onCancel} disabled={isLoading}>
{CANCEL}
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton fill onClick={onConfirm} disabled={isLoading} isLoading={isLoading}>
{CONFIRM}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</>
<EuiFormRow fullWidth>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={onCancel} disabled={isLoading}>
{CANCEL}
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton fill onClick={onConfirm} disabled={isLoading} isLoading={isLoading}>
{CONFIRM}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFormRow>
</EuiForm>
);
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ export const ContextMenuItemNavByRouter = memo<ContextMenuItemNavByRouterProps>(
);
}
);

ContextMenuItemNavByRouter.displayName = 'EuiContextMenuItemNavByRouter';
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ describe('When using the EndpointAgentStatus component', () => {
expect(renderResult.getByTestId('rowHostStatus').textContent).toEqual(expectedLabel);
});

describe('and host is isolated or pending isolation', () => {
// FIXME: un-skip test once Islation pending statuses are supported
describe.skip('and host is isolated or pending isolation', () => {
beforeEach(async () => {
// Ensure pending action api sets pending action for the test endpoint metadata
const pendingActionsResponseProvider = httpMocks.responseProvider.pendingActions.getMockImplementation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,3 @@ export const TableRowActions = memo<TableRowActionProps>(({ endpointMetadata })
);
});
TableRowActions.displayName = 'EndpointTableRowActions';

ContextMenuItemNavByRouter.displayName = 'EuiContextMenuItemNavByRouter';
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ describe('EndpointOverview Component', () => {
expect(findData.at(3).text()).toEqual('HealthyIsolated');
});

test.each([
// FIXME: un-skip once pending isolation status are supported again
test.skip.each([
['isolate', 'Isolating'],
['unisolate', 'Releasing'],
])('it shows pending %s status', (action, expectedLabel) => {
Expand Down