Skip to content

Commit

Permalink
Added toast notifications for failure cases in rule creation/edit (#70)
Browse files Browse the repository at this point in the history
* added toast notifications for failure

Signed-off-by: Amardeepsingh Siglani <[email protected]>

* updated toasts logic

Signed-off-by: Amardeepsingh Siglani <[email protected]>

Signed-off-by: Amardeepsingh Siglani <[email protected]>
  • Loading branch information
amsiglan authored Nov 4, 2022
1 parent a985878 commit 4ea1f27
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 23 deletions.
22 changes: 19 additions & 3 deletions public/pages/Main/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,11 @@ export default class Main extends Component<MainProps, MainState> {
<Route
path={ROUTES.RULES_CREATE}
render={(props: RouteComponentProps) => (
<CreateRule services={services} history={props.history} />
<CreateRule
services={services}
history={props.history}
notifications={core?.notifications}
/>
)}
/>
<Route
Expand All @@ -176,7 +180,13 @@ export default class Main extends Component<MainProps, MainState> {
return <Rules {...props} notifications={core?.notifications} />;
}

return <EditRule services={services} {...props} />;
return (
<EditRule
services={services}
{...props}
notifications={core?.notifications}
/>
);
}}
/>
<Route
Expand All @@ -187,7 +197,13 @@ export default class Main extends Component<MainProps, MainState> {
return <Rules {...props} notifications={core?.notifications} />;
}

return <DuplicateRule services={services} {...props} />;
return (
<DuplicateRule
services={services}
{...props}
notifications={core?.notifications}
/>
);
}}
/>
<Route
Expand Down
16 changes: 14 additions & 2 deletions public/pages/Rules/components/RuleEditor/RuleEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,12 @@ export const RuleEditor: React.FC<RuleEditorProps> = ({ title, rule, FooterActio
<EuiFlexGroup component="span">
<EuiFlexItem grow={false} style={{ minWidth: 400 }}>
<EuiFormRow label="Rule name">
<EuiFieldText placeholder="Enter rule name" value={name} onChange={onNameChange} />
<EuiFieldText
placeholder="Enter rule name"
value={name}
onChange={onNameChange}
required
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
Expand Down Expand Up @@ -176,6 +181,7 @@ export const RuleEditor: React.FC<RuleEditorProps> = ({ title, rule, FooterActio
]}
onChange={onLevelChange}
value={level}
required
/>
</EuiFormRow>

Expand Down Expand Up @@ -210,7 +216,12 @@ export const RuleEditor: React.FC<RuleEditorProps> = ({ title, rule, FooterActio
/>

<EuiFormRow label="Author">
<EuiFieldText placeholder="Enter author name" value={author} onChange={onAuthorChange} />
<EuiFieldText
placeholder="Enter author name"
value={author}
onChange={onAuthorChange}
required
/>
</EuiFormRow>

<EuiSpacer />
Expand All @@ -221,6 +232,7 @@ export const RuleEditor: React.FC<RuleEditorProps> = ({ title, rule, FooterActio
options={ruleStatus.map((status: string) => ({ value: status, text: status }))}
onChange={onStatusChange}
value={status}
required
/>
</EuiFormRow>

Expand Down
16 changes: 11 additions & 5 deletions public/pages/Rules/containers/CreateRule/CreateRule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,29 @@ import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { RouteComponentProps } from 'react-router-dom';
import { ROUTES } from '../../../../utils/constants';
import { Rule } from '../../../../../models/interfaces';
import { NotificationsStart } from 'opensearch-dashboards/public';
import { errorNotificationToast } from '../../../../utils/helpers';
import { validateRule } from '../../utils/helpers';

export interface CreateRuleProps {
services: BrowserServices;
history: RouteComponentProps['history'];
notifications?: NotificationsStart;
}

export const CreateRule: React.FC<CreateRuleProps> = ({ history, services }) => {
export const CreateRule: React.FC<CreateRuleProps> = ({ history, services, notifications }) => {
const footerActions: React.FC<{ rule: Rule }> = ({ rule }) => {
const onCreate = async () => {
if (!validateRule(rule, notifications!, 'create')) {
return;
}
const createRuleRes = await services.ruleService.createRule(rule);

if (!createRuleRes.ok) {
// TODO: show toast notification
alert('Failed rule creation');
errorNotificationToast(notifications!, 'create', 'rule', createRuleRes.error);
} else {
history.replace(ROUTES.RULES);
}

history.replace(ROUTES.RULES);
};

return (
Expand Down
21 changes: 16 additions & 5 deletions public/pages/Rules/containers/DuplicateRule/DuplicateRule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,34 @@ import { RouteComponentProps } from 'react-router-dom';
import { ROUTES } from '../../../../utils/constants';
import { Rule } from '../../../../../models/interfaces';
import { RuleItemInfoBase } from '../../models/types';
import { validateRule } from '../../utils/helpers';
import { NotificationsStart } from 'opensearch-dashboards/public';
import { errorNotificationToast } from '../../../../utils/helpers';

export interface DuplicateRuleProps
extends RouteComponentProps<any, any, { ruleItem: RuleItemInfoBase }> {
services: BrowserServices;
notifications?: NotificationsStart;
}

export const DuplicateRule: React.FC<DuplicateRuleProps> = ({ history, services, location }) => {
export const DuplicateRule: React.FC<DuplicateRuleProps> = ({
history,
services,
location,
notifications,
}) => {
const footerActions: React.FC<{ rule: Rule }> = ({ rule }) => {
const onCreate = async () => {
if (!validateRule(rule, notifications!, 'create')) {
return;
}
const updateRuleRes = await services.ruleService.createRule(rule);

if (!updateRuleRes.ok) {
// TODO: show toast notification
alert('Failed rule creation');
errorNotificationToast(notifications!, 'create', 'rule', updateRuleRes.error);
} else {
history.replace(ROUTES.RULES);
}

history.replace(ROUTES.RULES);
};

return (
Expand Down
26 changes: 19 additions & 7 deletions public/pages/Rules/containers/EditRule/EditRule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,39 @@ import { RouteComponentProps } from 'react-router-dom';
import { ROUTES } from '../../../../utils/constants';
import { Rule } from '../../../../../models/interfaces';
import { RuleItemInfoBase } from '../../models/types';
import { NotificationsStart } from 'opensearch-dashboards/public';
import { errorNotificationToast } from '../../../../utils/helpers';
import { validateRule } from '../../utils/helpers';

export interface EditRuleProps
extends RouteComponentProps<any, any, { ruleItem: RuleItemInfoBase }> {
services: BrowserServices;
notifications?: NotificationsStart;
}

export const EditRule: React.FC<EditRuleProps> = ({ history, services, location }) => {
export const EditRule: React.FC<EditRuleProps> = ({
history,
services,
location,
notifications,
}) => {
const footerActions: React.FC<{ rule: Rule }> = ({ rule }) => {
const onSave = async () => {
const updateRuleRes = await services.ruleService.updateRule(
if (!validateRule(rule, notifications!, 'save')) {
return;
}

const editRuleRes = await services.ruleService.updateRule(
location.state.ruleItem._id,
rule.category,
rule
);

if (!updateRuleRes.ok) {
// TODO: show toast notification
alert('Failed rule creation');
if (!editRuleRes.ok) {
errorNotificationToast(notifications!, 'save', 'rule', editRuleRes.error);
} else {
history.replace(ROUTES.RULES);
}

history.replace(ROUTES.RULES);
};

return (
Expand Down
5 changes: 5 additions & 0 deletions public/pages/Rules/containers/ImportRule/ImportRule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { load, safeDump } from 'js-yaml';
import { ContentPanel } from '../../../../components/ContentPanel';
import { NotificationsStart } from 'opensearch-dashboards/public';
import { errorNotificationToast } from '../../../../utils/helpers';
import { validateRule } from '../../utils/helpers';

export interface ImportRuleProps {
services: BrowserServices;
Expand Down Expand Up @@ -101,6 +102,10 @@ export const ImportRule: React.FC<ImportRuleProps> = ({ history, services, notif

const footerActions: React.FC<{ rule: Rule }> = ({ rule }) => {
const onCreate = async () => {
if (!validateRule(rule, notifications!, 'create')) {
return;
}

const updateRuleRes = await services.ruleService.createRule(rule);

if (!updateRuleRes.ok) {
Expand Down
32 changes: 31 additions & 1 deletion public/pages/Rules/utils/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@

import { EuiBasicTableColumn, EuiLink } from '@elastic/eui';
import React from 'react';
import { capitalizeFirstLetter } from '../../../utils/helpers';
import { capitalizeFirstLetter, errorNotificationToast } from '../../../utils/helpers';
import { ruleSeverity, ruleSource, ruleTypes } from './constants';
import { Search } from '@opensearch-project/oui/src/eui_components/basic_table';
import { RuleItemInfoBase } from '../models/types';
import { Rule } from '../../../../models/interfaces';
import { NotificationsStart } from 'opensearch-dashboards/public';

export interface RuleTableItem {
title: string;
Expand Down Expand Up @@ -99,3 +101,31 @@ export const getRulesTableSearchConfig = (): Search => {
],
};
};

export function validateRule(
rule: Rule,
notifications: NotificationsStart,
ruleAction: 'create' | 'save'
): boolean {
const invalidFields = [];

if (!rule.title) invalidFields.push('Rule name');
if (!rule.category) invalidFields.push('Log type');
if (!rule.detection) invalidFields.push('Detection');
if (!rule.level) invalidFields.push('Rule level');
if (!rule.author) invalidFields.push('Author');
if (!rule.status) invalidFields.push('Rule status');

if (invalidFields.length > 0) {
errorNotificationToast(
notifications!,
ruleAction,
'rule',
`Enter valid input for ${invalidFields.join(',')}`
);

return false;
}

return true;
}

0 comments on commit 4ea1f27

Please sign in to comment.