mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[Attack Discovery][Scheduling] Cases support followup 1 (#225452)
## Summary
Summarize your PR. If it involves visual changes include a screenshot or
gif.
These changes addresses the review comment from my previous PR
36ed6b38c1 (r2150081638)
Initially I broke up rendered component into multiple memoized
sub-sections. Reverting that back and adding tests coverage for the new
functionality - Case actions UI for the Attack Discovery rule type:
* Hidden `group by` component
* Hidden `time window` component
* Hidden `reopen case` component
* Disabled `template selector` component
* Tooltip explaining why we disabled the `template selector` component
This commit is contained in:
parent
4de6f7ca2c
commit
d38801034a
2 changed files with 133 additions and 100 deletions
|
@ -19,6 +19,7 @@ import { useGetAllCaseConfigurations } from '../../../containers/configure/use_g
|
|||
import { useGetAllCaseConfigurationsResponse } from '../../configure_cases/__mock__';
|
||||
import { templatesConfigurationMock } from '../../../containers/mock';
|
||||
import * as utils from '../../../containers/configure/utils';
|
||||
import { ATTACK_DISCOVERY_SCHEDULES_ALERT_TYPE_ID } from '@kbn/elastic-assistant-common';
|
||||
|
||||
jest.mock('@kbn/alerts-ui-shared/src/common/hooks/use_alerts_data_view');
|
||||
jest.mock('../../../common/lib/kibana/use_application');
|
||||
|
@ -72,6 +73,7 @@ describe('CasesParamsFields renders', () => {
|
|||
// Workaround for timeout via https://github.com/testing-library/user-event/issues/833#issuecomment-1171452841
|
||||
user = userEvent.setup({
|
||||
advanceTimers: jest.advanceTimersByTime,
|
||||
pointerEventsCheck: 0,
|
||||
});
|
||||
useApplicationMock.mockReturnValueOnce({ appId: 'management' });
|
||||
useAlertsDataViewMock.mockReturnValue({
|
||||
|
@ -397,4 +399,67 @@ describe('CasesParamsFields renders', () => {
|
|||
expect(editAction.mock.calls[0][1].reopenClosedCases).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Attack Discovery', () => {
|
||||
it('does not render `group by` component', async () => {
|
||||
const newProps = {
|
||||
...defaultProps,
|
||||
ruleTypeId: ATTACK_DISCOVERY_SCHEDULES_ALERT_TYPE_ID,
|
||||
};
|
||||
render(<CasesParamsFields {...newProps} />);
|
||||
|
||||
expect(screen.queryByTestId('group-by-alert-field-combobox')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render `time window` component', async () => {
|
||||
const newProps = {
|
||||
...defaultProps,
|
||||
ruleTypeId: ATTACK_DISCOVERY_SCHEDULES_ALERT_TYPE_ID,
|
||||
};
|
||||
render(<CasesParamsFields {...newProps} />);
|
||||
|
||||
expect(screen.queryByTestId('time-window-size-input')).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId('time-window-unit-select')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render `reopen case` component', async () => {
|
||||
const newProps = {
|
||||
...defaultProps,
|
||||
ruleTypeId: ATTACK_DISCOVERY_SCHEDULES_ALERT_TYPE_ID,
|
||||
};
|
||||
render(<CasesParamsFields {...newProps} />);
|
||||
|
||||
expect(screen.queryByTestId('reopen-case')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders disabled `template selector` component', async () => {
|
||||
const newProps = {
|
||||
...defaultProps,
|
||||
ruleTypeId: ATTACK_DISCOVERY_SCHEDULES_ALERT_TYPE_ID,
|
||||
};
|
||||
render(<CasesParamsFields {...newProps} />);
|
||||
|
||||
const templateSelectorComponent = await screen.findByTestId('create-case-template-select');
|
||||
|
||||
expect(templateSelectorComponent).toBeInTheDocument();
|
||||
expect(templateSelectorComponent).toBeDisabled();
|
||||
});
|
||||
|
||||
it('shows attack discovery explanation tooltip', async () => {
|
||||
const newProps = {
|
||||
...defaultProps,
|
||||
ruleTypeId: ATTACK_DISCOVERY_SCHEDULES_ALERT_TYPE_ID,
|
||||
};
|
||||
render(<CasesParamsFields {...newProps} />);
|
||||
|
||||
await user.hover(await screen.findByTestId('create-case-template-select'));
|
||||
|
||||
expect(await screen.findByTestId('case-action-attack-discovery-tooltip')).toBeTruthy();
|
||||
expect(
|
||||
await screen.findByText(
|
||||
'Attack Discovery Schedules fully manage Case actions, automatically filling in all fields for new Cases.'
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -188,8 +188,26 @@ export const CasesParamsFieldsComponent: React.FunctionComponent<
|
|||
[editSubActionProperty]
|
||||
);
|
||||
|
||||
const groupByComponent = useMemo(() => {
|
||||
if (isAttackDiscoveryRuleType) {
|
||||
return (
|
||||
<EuiToolTip
|
||||
data-test-subj="case-action-attack-discovery-tooltip"
|
||||
content={i18n.ATTACK_DISCOVERY_TEMPLATE_TOOLTIP}
|
||||
>
|
||||
<TemplateSelector
|
||||
key={currentConfiguration.id}
|
||||
isLoading={isLoadingCaseConfiguration}
|
||||
templates={[defaultTemplate, ...currentConfiguration.templates]}
|
||||
onTemplateChange={onTemplateChange}
|
||||
initialTemplate={selectedTemplate}
|
||||
isDisabled={true}
|
||||
/>
|
||||
</EuiToolTip>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={true}>
|
||||
<EuiFormRow fullWidth label={i18n.GROUP_BY_ALERT} labelAppend={OptionalFieldLabel}>
|
||||
|
@ -207,71 +225,54 @@ export const CasesParamsFieldsComponent: React.FunctionComponent<
|
|||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}, [loadingAlertDataViews, onChangeComboBox, options, selectedOptions]);
|
||||
|
||||
const timeWindowComponent = useMemo(() => {
|
||||
return (
|
||||
<>
|
||||
<EuiFormRow
|
||||
fullWidth
|
||||
id="timeWindow"
|
||||
error={errors.timeWindow as string[]}
|
||||
isInvalid={
|
||||
errors.timeWindow !== undefined &&
|
||||
Number(errors.timeWindow.length) > 0 &&
|
||||
timeWindow !== undefined
|
||||
}
|
||||
>
|
||||
<EuiFlexGroup alignItems="flexEnd" gutterSize="s">
|
||||
<EuiFlexItem grow={4}>
|
||||
<EuiFieldNumber
|
||||
prepend={i18n.TIME_WINDOW}
|
||||
data-test-subj="time-window-size-input"
|
||||
value={timeWindowSize}
|
||||
min={1}
|
||||
step={1}
|
||||
onChange={(e) => {
|
||||
handleTimeWindowChange('timeWindowSize', e.target.value);
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={3}>
|
||||
<EuiSelect
|
||||
fullWidth
|
||||
data-test-subj="time-window-unit-select"
|
||||
value={timeWindowUnit}
|
||||
onChange={(e) => {
|
||||
handleTimeWindowChange('timeWindowUnit', e.target.value);
|
||||
}}
|
||||
options={getTimeUnitOptions(timeWindowSize)}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer size="s" />
|
||||
{showTimeWindowWarning && (
|
||||
<EuiCallOut
|
||||
data-test-subj="show-time-window-warning"
|
||||
title={i18n.TIME_WINDOW_WARNING}
|
||||
color="warning"
|
||||
iconType="alert"
|
||||
size="s"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}, [
|
||||
errors.timeWindow,
|
||||
handleTimeWindowChange,
|
||||
showTimeWindowWarning,
|
||||
timeWindow,
|
||||
timeWindowSize,
|
||||
timeWindowUnit,
|
||||
]);
|
||||
|
||||
const templateSelectorComponent = useMemo(() => {
|
||||
return (
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFormRow
|
||||
fullWidth
|
||||
id="timeWindow"
|
||||
error={errors.timeWindow as string[]}
|
||||
isInvalid={
|
||||
errors.timeWindow !== undefined &&
|
||||
Number(errors.timeWindow.length) > 0 &&
|
||||
timeWindow !== undefined
|
||||
}
|
||||
>
|
||||
<EuiFlexGroup alignItems="flexEnd" gutterSize="s">
|
||||
<EuiFlexItem grow={4}>
|
||||
<EuiFieldNumber
|
||||
prepend={i18n.TIME_WINDOW}
|
||||
data-test-subj="time-window-size-input"
|
||||
value={timeWindowSize}
|
||||
min={1}
|
||||
step={1}
|
||||
onChange={(e) => {
|
||||
handleTimeWindowChange('timeWindowSize', e.target.value);
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={3}>
|
||||
<EuiSelect
|
||||
fullWidth
|
||||
data-test-subj="time-window-unit-select"
|
||||
value={timeWindowUnit}
|
||||
onChange={(e) => {
|
||||
handleTimeWindowChange('timeWindowUnit', e.target.value);
|
||||
}}
|
||||
options={getTimeUnitOptions(timeWindowSize)}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer size="s" />
|
||||
{showTimeWindowWarning && (
|
||||
<EuiCallOut
|
||||
data-test-subj="show-time-window-warning"
|
||||
title={i18n.TIME_WINDOW_WARNING}
|
||||
color="warning"
|
||||
iconType="alert"
|
||||
size="s"
|
||||
/>
|
||||
)}
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={true}>
|
||||
<TemplateSelector
|
||||
|
@ -280,23 +281,10 @@ export const CasesParamsFieldsComponent: React.FunctionComponent<
|
|||
templates={[defaultTemplate, ...currentConfiguration.templates]}
|
||||
onTemplateChange={onTemplateChange}
|
||||
initialTemplate={selectedTemplate}
|
||||
isDisabled={isAttackDiscoveryRuleType}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}, [
|
||||
currentConfiguration.id,
|
||||
currentConfiguration.templates,
|
||||
defaultTemplate,
|
||||
isAttackDiscoveryRuleType,
|
||||
isLoadingCaseConfiguration,
|
||||
onTemplateChange,
|
||||
selectedTemplate,
|
||||
]);
|
||||
|
||||
const reopenClosedCasesComponent = useMemo(() => {
|
||||
return (
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiCheckbox
|
||||
|
@ -310,26 +298,6 @@ export const CasesParamsFieldsComponent: React.FunctionComponent<
|
|||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}, [editSubActionProperty, index, reopenClosedCases]);
|
||||
|
||||
if (isAttackDiscoveryRuleType) {
|
||||
return (
|
||||
<EuiToolTip content={i18n.ATTACK_DISCOVERY_TEMPLATE_TOOLTIP}>
|
||||
{templateSelectorComponent}
|
||||
</EuiToolTip>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{groupByComponent}
|
||||
<EuiSpacer size="m" />
|
||||
{timeWindowComponent}
|
||||
<EuiSpacer size="m" />
|
||||
{templateSelectorComponent}
|
||||
<EuiSpacer size="m" />
|
||||
{reopenClosedCasesComponent}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue