Skip to content

Commit 6da7c82

Browse files
authored
[FEATURE] More validations on YAML rule editor (#279)
* yaml editor as custom form component Signed-off-by: Aleksandar Djindjic <[email protected]> * refactor file structure for rule editor Signed-off-by: Aleksandar Djindjic <[email protected]> * rename RuleEditorFormState to RuleEditorFormModel Signed-off-by: Aleksandar Djindjic <[email protected]> * refactor yaml rule editor custom form component Signed-off-by: Aleksandar Djindjic <[email protected]> * pr comments fixes and snapshot tests Signed-off-by: Aleksandar Djindjic <[email protected]> * more snapshot tests Signed-off-by: Aleksandar Djindjic <[email protected]> * align fields labels styling with create detector Signed-off-by: Aleksandar Djindjic <[email protected]> * aligne formik version with alerting plugin Signed-off-by: Aleksandar Djindjic <[email protected]> * addresing validation UX issues Signed-off-by: Aleksandar Djindjic <[email protected]> * validate tag format Signed-off-by: Aleksandar Djindjic <[email protected]> Signed-off-by: Aleksandar Djindjic <[email protected]>
1 parent 9072a4f commit 6da7c82

24 files changed

+878
-995
lines changed

cypress/integration/2_rules.spec.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,10 @@ describe('Rules', () => {
8484
);
8585

8686
// Enter the reference
87-
cy.get('[data-test-subj="rule_references_-_optional_field_0"]').type(SAMPLE_RULE.references);
87+
cy.get('[data-test-subj="rule_references_field_0"]').type(SAMPLE_RULE.references);
8888

8989
// Enter the false positive cases
90-
cy.get('[data-test-subj="rule_false_positive_cases_-_optional_field_0"]').type(
91-
SAMPLE_RULE.falsePositive
92-
);
90+
cy.get('[data-test-subj="rule_false_positives_field_0"]').type(SAMPLE_RULE.falsePositive);
9391

9492
// Enter the author
9593
cy.get('[data-test-subj="rule_author_field"]').type(SAMPLE_RULE.author);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,6 @@
6767
"yarn": "^1.21.1"
6868
},
6969
"dependencies": {
70-
"formik": "^2.2.9"
70+
"formik": "^2.2.6"
7171
}
7272
}

public/pages/Detectors/components/UpdateRules/UpdateRules.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,6 @@ export const UpdateDetectorRules: React.FC<UpdateDetectorRulesProps> = (props) =
217217
const ruleItems = prePackagedRuleItems.concat(customRuleItems);
218218

219219
const onRuleDetails = (ruleItem: RuleItem) => {
220-
console.log('onRuleDetails', ruleItem);
221220
setFlyoutData(() => ({
222221
title: ruleItem.name,
223222
level: ruleItem.severity,

public/pages/Rules/components/RuleEditor/FieldTextArray.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import {
1414
import React, { ChangeEvent } from 'react';
1515

1616
export interface FieldTextArrayProps {
17-
label: string;
17+
label: string | React.ReactNode;
18+
name: string;
1819
fields: string[];
1920
addButtonName: string;
2021
onFieldEdit: (value: string, fieldIndex: number) => void;
@@ -25,6 +26,7 @@ export interface FieldTextArrayProps {
2526
export const FieldTextArray: React.FC<FieldTextArrayProps> = ({
2627
addButtonName,
2728
label,
29+
name,
2830
fields,
2931
onFieldEdit,
3032
onFieldRemove,
@@ -43,7 +45,7 @@ export const FieldTextArray: React.FC<FieldTextArrayProps> = ({
4345
onChange={(e: ChangeEvent<HTMLInputElement>) => {
4446
onFieldEdit(e.target.value, index);
4547
}}
46-
data-test-subj={`rule_${label
48+
data-test-subj={`rule_${name
4749
.toLowerCase()
4850
.replaceAll(' ', '_')}_field_${index}`}
4951
/>

public/pages/Rules/components/RuleEditor/FormSubmitionErrorToastNotification.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { useFormikContext } from 'formik';
77
import { NotificationsStart } from 'opensearch-dashboards/public';
88
import { errorNotificationToast } from '../../../../utils/helpers';
99

10-
export const FormSubmitionErrorToastNotification = ({
10+
export const FormSubmissionErrorToastNotification = ({
1111
notifications,
1212
}: {
1313
notifications?: NotificationsStart;

public/pages/Rules/components/RuleEditor/RuleEditor.tsx

Lines changed: 0 additions & 140 deletions
This file was deleted.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import React, { useCallback } from 'react';
7+
import { RouteComponentProps } from 'react-router-dom';
8+
import { NotificationsStart } from 'opensearch-dashboards/public';
9+
import { RuleService } from '../../../../services';
10+
import { ROUTES } from '../../../../utils/constants';
11+
import { EuiSpacer } from '@elastic/eui';
12+
import { Rule } from '../../../../../models/interfaces';
13+
import { RuleEditorFormModel, ruleEditorStateDefaultValue } from './RuleEditorFormModel';
14+
import { mapFormToRule, mapRuleToForm } from './mappers';
15+
import { RuleEditorForm } from './RuleEditorForm';
16+
import { validateRule } from '../../utils/helpers';
17+
import { errorNotificationToast } from '../../../../utils/helpers';
18+
19+
export interface RuleEditorProps {
20+
title: string;
21+
rule?: Rule;
22+
history: RouteComponentProps['history'];
23+
notifications?: NotificationsStart;
24+
ruleService: RuleService;
25+
mode: 'create' | 'edit';
26+
}
27+
28+
export interface VisualEditorFormErrorsState {
29+
nameError: string | null;
30+
descriptionError: string | null;
31+
authorError: string | null;
32+
}
33+
34+
export const RuleEditorContainer: React.FC<RuleEditorProps> = ({
35+
history,
36+
notifications,
37+
title,
38+
rule,
39+
ruleService,
40+
mode,
41+
}) => {
42+
const initialRuleValue = rule
43+
? { ...mapRuleToForm(rule), id: ruleEditorStateDefaultValue.id }
44+
: ruleEditorStateDefaultValue;
45+
46+
const onSubmit = async (values: RuleEditorFormModel) => {
47+
const submitingRule = mapFormToRule(values);
48+
if (!validateRule(submitingRule, notifications!, 'create')) {
49+
return;
50+
}
51+
52+
let result;
53+
if (mode === 'edit') {
54+
if (!rule) {
55+
console.error('No rule id found');
56+
return;
57+
}
58+
result = await ruleService.updateRule(rule?.id, submitingRule.category, submitingRule);
59+
} else {
60+
result = await ruleService.createRule(submitingRule);
61+
}
62+
63+
if (!result.ok) {
64+
errorNotificationToast(
65+
notifications!,
66+
mode === 'create' ? 'create' : 'save',
67+
'rule',
68+
result.error
69+
);
70+
} else {
71+
history.replace(ROUTES.RULES);
72+
}
73+
};
74+
75+
const goToRulesList = useCallback(() => {
76+
history.replace(ROUTES.RULES);
77+
}, [history]);
78+
79+
return (
80+
<>
81+
<RuleEditorForm
82+
title={title}
83+
mode={mode}
84+
notifications={notifications}
85+
initialValue={initialRuleValue}
86+
cancel={goToRulesList}
87+
submit={onSubmit}
88+
/>
89+
<EuiSpacer size="xl" />
90+
</>
91+
);
92+
};

0 commit comments

Comments
 (0)