Skip to content

Commit

Permalink
[Security Solution] Updates redirect route upon rule creation (#92715) (
Browse files Browse the repository at this point in the history
#93528)

* [Security Solution] Updates redirect route upon rule creation

Closes #82562.
  • Loading branch information
ecezalp authored Mar 4, 2021
1 parent fb1c983 commit f61f387
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export const ANOMALY_THRESHOLD_INPUT = '[data-test-subj="anomalyThresholdSlider"

export const ADVANCED_SETTINGS_BTN = '[data-test-subj="advancedSettings"] .euiAccordion__button';

export const BACK_TO_ALL_RULES_LINK = '[data-test-subj="ruleDetailsBackToAllRules"]';

export const COMBO_BOX_CLEAR_BTN = '[data-test-subj="comboBoxClearButton"]';

export const COMBO_BOX_INPUT = '[data-test-subj="comboBoxInput"]';
Expand Down
53 changes: 28 additions & 25 deletions x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,51 @@ import {
ADD_REFERENCE_URL_BTN,
ADVANCED_SETTINGS_BTN,
ANOMALY_THRESHOLD_INPUT,
AT_LEAST_ONE_INDEX_PATTERN,
AT_LEAST_ONE_VALID_MATCH,
BACK_TO_ALL_RULES_LINK,
COMBO_BOX_CLEAR_BTN,
COMBO_BOX_INPUT,
CREATE_AND_ACTIVATE_BTN,
CUSTOM_QUERY_INPUT,
CUSTOM_QUERY_REQUIRED,
DEFAULT_RISK_SCORE_INPUT,
DEFINE_CONTINUE_BUTTON,
DEFINE_EDIT_TAB,
EQL_QUERY_INPUT,
EQL_QUERY_PREVIEW_HISTOGRAM,
EQL_QUERY_VALIDATION_SPINNER,
EQL_TYPE,
FALSE_POSITIVES_INPUT,
IMPORT_QUERY_FROM_SAVED_TIMELINE_LINK,
INDICATOR_MATCH_TYPE,
INPUT,
INVALID_MATCH_CONTENT,
INVESTIGATION_NOTES_TEXTAREA,
LOOK_BACK_INTERVAL,
LOOK_BACK_TIME_TYPE,
MACHINE_LEARNING_DROPDOWN,
MACHINE_LEARNING_LIST,
MACHINE_LEARNING_TYPE,
MITRE_ATTACK_ADD_SUBTECHNIQUE_BUTTON,
MITRE_ATTACK_ADD_TACTIC_BUTTON,
MITRE_ATTACK_ADD_TECHNIQUE_BUTTON,
MITRE_ATTACK_SUBTECHNIQUE_DROPDOWN,
MITRE_ATTACK_TACTIC_DROPDOWN,
MITRE_ATTACK_TECHNIQUE_DROPDOWN,
MITRE_TACTIC,
QUERY_PREVIEW_BUTTON,
REFERENCE_URLS_INPUT,
REFRESH_BUTTON,
DEFAULT_RISK_SCORE_INPUT,
RISK_MAPPING_OVERRIDE_OPTION,
RISK_OVERRIDE,
RULE_DESCRIPTION_INPUT,
RULE_NAME_INPUT,
RULE_NAME_OVERRIDE,
RULE_STATUS,
RULE_TIMESTAMP_OVERRIDE,
RULES_CREATION_FORM,
RULES_CREATION_PREVIEW,
RUNS_EVERY_INTERVAL,
RUNS_EVERY_TIME_TYPE,
SCHEDULE_CONTINUE_BUTTON,
Expand All @@ -55,36 +74,18 @@ import {
SEVERITY_MAPPING_OVERRIDE_OPTION,
SEVERITY_OVERRIDE_ROW,
TAGS_INPUT,
THRESHOLD_FIELD_SELECTION,
THRESHOLD_INPUT_AREA,
THRESHOLD_TYPE,
EQL_TYPE,
EQL_QUERY_INPUT,
QUERY_PREVIEW_BUTTON,
EQL_QUERY_PREVIEW_HISTOGRAM,
EQL_QUERY_VALIDATION_SPINNER,
COMBO_BOX_CLEAR_BTN,
MITRE_ATTACK_TACTIC_DROPDOWN,
MITRE_ATTACK_TECHNIQUE_DROPDOWN,
MITRE_ATTACK_SUBTECHNIQUE_DROPDOWN,
MITRE_ATTACK_ADD_TACTIC_BUTTON,
MITRE_ATTACK_ADD_SUBTECHNIQUE_BUTTON,
MITRE_ATTACK_ADD_TECHNIQUE_BUTTON,
THREAT_COMBO_BOX_INPUT,
THREAT_ITEM_ENTRY_DELETE_BUTTON,
THREAT_MAPPING_COMBO_BOX_INPUT,
THREAT_MATCH_AND_BUTTON,
INVALID_MATCH_CONTENT,
THREAT_MATCH_OR_BUTTON,
AT_LEAST_ONE_VALID_MATCH,
AT_LEAST_ONE_INDEX_PATTERN,
CUSTOM_QUERY_REQUIRED,
RULES_CREATION_FORM,
RULES_CREATION_PREVIEW,
THREAT_MATCH_CUSTOM_QUERY_INPUT,
THREAT_MATCH_INDICATOR_INDEX,
THREAT_MATCH_INDICATOR_INDICATOR_INDEX,
THREAT_MATCH_CUSTOM_QUERY_INPUT,
THREAT_MATCH_OR_BUTTON,
THREAT_MATCH_QUERY_INPUT,
THREAT_MAPPING_COMBO_BOX_INPUT,
THRESHOLD_FIELD_SELECTION,
THRESHOLD_INPUT_AREA,
THRESHOLD_TYPE,
} from '../screens/create_new_rule';
import { TOAST_ERROR } from '../screens/shared';
import { SERVER_SIDE_EVENT_COUNT } from '../screens/timeline';
Expand All @@ -95,6 +96,8 @@ export const createAndActivateRule = () => {
cy.get(SCHEDULE_CONTINUE_BUTTON).click({ force: true });
cy.get(CREATE_AND_ACTIVATE_BTN).click({ force: true });
cy.get(CREATE_AND_ACTIVATE_BTN).should('not.exist');
cy.get(BACK_TO_ALL_RULES_LINK).click({ force: true });
cy.get(BACK_TO_ALL_RULES_LINK).should('not.exist');
};

export const fillAboutRule = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import { renderHook, act } from '@testing-library/react-hooks';

import { useCreateRule, ReturnCreateRule } from './use_create_rule';
import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock';
import { getRulesSchemaMock } from '../../../../../common/detection_engine/schemas/response/rules_schema.mocks';

jest.mock('./api');

describe('useCreateRule', () => {
test('init', async () => {
const { result } = renderHook<unknown, ReturnCreateRule>(() => useCreateRule());

expect(result.current).toEqual([{ isLoading: false, isSaved: false }, result.current[1]]);
expect(result.current).toEqual([{ isLoading: false, ruleId: null }, result.current[1]]);
});

test('saving rule with isLoading === true', async () => {
Expand All @@ -27,19 +28,22 @@ describe('useCreateRule', () => {
await waitForNextUpdate();
result.current[1](getCreateRulesSchemaMock());
rerender();
expect(result.current).toEqual([{ isLoading: true, isSaved: false }, result.current[1]]);
expect(result.current).toEqual([{ isLoading: true, ruleId: null }, result.current[1]]);
});
});

test('saved rule with isSaved === true', async () => {
test('updates ruleId after the rule has been saved', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook<void, ReturnCreateRule>(() =>
useCreateRule()
);
await waitForNextUpdate();
result.current[1](getCreateRulesSchemaMock());
await waitForNextUpdate();
expect(result.current).toEqual([{ isLoading: false, isSaved: true }, result.current[1]]);
expect(result.current).toEqual([
{ isLoading: false, ruleId: getRulesSchemaMock().id },
result.current[1],
]);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,31 @@ import { transformOutput } from './transforms';

interface CreateRuleReturn {
isLoading: boolean;
isSaved: boolean;
ruleId: string | null;
}

export type ReturnCreateRule = [CreateRuleReturn, Dispatch<CreateRulesSchema | null>];

export const useCreateRule = (): ReturnCreateRule => {
const [rule, setRule] = useState<CreateRulesSchema | null>(null);
const [isSaved, setIsSaved] = useState(false);
const [ruleId, setRuleId] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [, dispatchToaster] = useStateToaster();

useEffect(() => {
let isSubscribed = true;
const abortCtrl = new AbortController();
setIsSaved(false);
setRuleId(null);
const saveRule = async () => {
if (rule != null) {
try {
setIsLoading(true);
await createRule({ rule: transformOutput(rule), signal: abortCtrl.signal });
const createRuleResponse = await createRule({
rule: transformOutput(rule),
signal: abortCtrl.signal,
});
if (isSubscribed) {
setIsSaved(true);
setRuleId(createRuleResponse.id);
}
} catch (error) {
if (isSubscribed) {
Expand All @@ -57,5 +60,5 @@ export const useCreateRule = (): ReturnCreateRule => {
};
}, [rule, dispatchToaster]);

return [{ isLoading, isSaved }, setRule];
return [{ isLoading, ruleId }, setRule];
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ import { CreateRulesSchema } from '../../../../../../common/detection_engine/sch
import { useListsConfig } from '../../../../containers/detection_engine/lists/use_lists_config';

import {
getRulesUrl,
getDetectionEngineUrl,
getRuleDetailsUrl,
getRulesUrl,
} from '../../../../../common/components/link_to/redirect_to_detection_engine';
import { WrapperPage } from '../../../../../common/components/wrapper_page';
import { displaySuccessToast, useStateToaster } from '../../../../../common/components/toasters';
Expand Down Expand Up @@ -138,7 +139,7 @@ const CreateRulePageComponent: React.FC = () => {
[RuleStep.scheduleRule]: false,
[RuleStep.ruleActions]: false,
});
const [{ isLoading, isSaved }, setRule] = useCreateRule();
const [{ isLoading, ruleId }, setRule] = useCreateRule();
const ruleType = stepsData.current[RuleStep.defineRule].data?.ruleType;
const ruleName = stepsData.current[RuleStep.aboutRule].data?.name;
const actionMessageParams = useMemo(() => getActionMessageParams(ruleType), [ruleType]);
Expand Down Expand Up @@ -263,9 +264,9 @@ const CreateRulePageComponent: React.FC = () => {
/>
);

if (isSaved && ruleName) {
if (ruleName && ruleId) {
displaySuccessToast(i18n.SUCCESSFULLY_CREATED_RULES(ruleName), dispatchToaster);
history.replace(getRulesUrl());
history.replace(getRuleDetailsUrl(ruleId));
return null;
}

Expand Down

0 comments on commit f61f387

Please sign in to comment.