Skip to content

Commit 51c1691

Browse files
authored
Feat/14047 sigma rules to event definition wizard UI (#26111)
* feat(14047): New Sigma Event Definition import options plugin * feat(14047): Updates to EventDefinitionFormContainer * feat(14047): Moved requests to a reusable hook * feat(14047): Have the new sigma page working * feat(14047): Updated event definitions form buttons * feat(14047): Now it shows the list of available notifications * feat(14047): Fixed some lint issues * feat(14047): Fixed failing test * feat(14047): Added new alert routes to point to new sigma import page
1 parent 7ed809a commit 51c1691

17 files changed

Lines changed: 465 additions & 224 deletions

graylog2-web-interface/src/components/common/CreateButton.tsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,22 @@
1414
* along with this program. If not, see
1515
* <http://www.mongodb.com/licensing/server-side-public-license>.
1616
*/
17-
import * as React from 'react';
18-
import { useCallback, useMemo } from 'react';
17+
import React, { useCallback, useMemo } from 'react';
18+
import type { Permissions } from 'graylog-web-plugin/plugin';
1919

2020
import IfPermitted from 'components/common/IfPermitted';
2121
import { LinkContainer } from 'components/common';
22-
import Button from 'components/bootstrap/Button';
22+
import { Button } from 'components/bootstrap';
2323
import usePluginEntities from 'hooks/usePluginEntities';
2424
import useSendTelemetry from 'logic/telemetry/useSendTelemetry';
2525
import useLocation from 'routing/useLocation';
2626
import { getPathnameWithoutId } from 'util/URLUtils';
2727

2828
type Props = {
29-
disabled?: boolean;
3029
entityKey: string;
30+
disabled?: boolean;
3131
};
32+
3233
const useEntityCreator = (entityKey: string) => {
3334
const entityCreators = usePluginEntities('entityCreators');
3435

@@ -42,10 +43,18 @@ const useEntityCreator = (entityKey: string) => {
4243

4344
return entityCreator;
4445
};
46+
47+
const PermissionWrapper = ({
48+
permissions = undefined,
49+
children = undefined,
50+
}: React.PropsWithChildren<{ permissions?: Permissions }>) =>
51+
permissions ? <IfPermitted permissions={permissions}>{children}</IfPermitted> : <>{children}</>;
52+
4553
const CreateButton = ({ disabled = false, entityKey }: Props) => {
4654
const entityCreator = useEntityCreator(entityKey);
4755
const sendTelemetry = useSendTelemetry();
4856
const { pathname } = useLocation();
57+
4958
const _onClick = useCallback(() => {
5059
const { telemetryEvent } = entityCreator;
5160
if (telemetryEvent) {
@@ -57,12 +66,6 @@ const CreateButton = ({ disabled = false, entityKey }: Props) => {
5766
}
5867
}, [entityCreator, pathname, sendTelemetry]);
5968

60-
const PermissionWrapper = entityCreator?.permissions
61-
? ({ children }: React.PropsWithChildren<{}>) => (
62-
<IfPermitted permissions={entityCreator.permissions}>{children}</IfPermitted>
63-
)
64-
: React.Fragment;
65-
6669
return (
6770
<PermissionWrapper>
6871
<LinkContainer to={entityCreator.path}>

graylog2-web-interface/src/components/common/Wizard.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ export type StepType<StepKey extends string> = {
278278
title: React.ReactNode;
279279
component: React.ReactElement;
280280
disabled?: boolean;
281+
hidden?: boolean;
281282
};
282283

283284
export type StepsType<StepKey extends string> = Array<StepType<StepKey>>;

graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionForm.tsx

Lines changed: 6 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,24 @@
1414
* along with this program. If not, see
1515
* <http://www.mongodb.com/licensing/server-side-public-license>.
1616
*/
17+
import React from 'react';
1718
import type { SyntheticEvent } from 'react';
18-
import * as React from 'react';
19-
import { useMemo } from 'react';
20-
import { PluginStore } from 'graylog-web-plugin/plugin';
2119
import styled from 'styled-components';
2220

2321
import { getPathnameWithoutId } from 'util/URLUtils';
2422
import { Col, Row } from 'components/bootstrap';
2523
import { Wizard } from 'components/common';
26-
import type { EventNotification } from 'stores/event-notifications/EventNotificationsStore';
27-
import type {
28-
EventDefinition,
29-
EventDefinitionFormControlsProps,
30-
} from 'components/event-definitions/event-definitions-types';
31-
import type User from 'logic/users/User';
24+
import type { StepType } from 'components/common/Wizard';
25+
import type { EventDefinitionFormControlsProps } from 'components/event-definitions/event-definitions-types';
3226
import useSendTelemetry from 'logic/telemetry/useSendTelemetry';
3327
import useLocation from 'routing/useLocation';
3428
import { TELEMETRY_EVENT_TYPE } from 'logic/telemetry/Constants';
3529
import EventDefinitionFormControls from 'components/event-definitions/event-definition-form/EventDefinitionFormControls';
36-
import type { EntitySharePayload } from 'actions/permissions/EntityShareActions';
37-
38-
import EventDetailsForm from './EventDetailsForm';
39-
import EventConditionForm from './EventConditionForm';
40-
import FieldsForm from './FieldsForm';
41-
import NotificationsForm from './NotificationsForm';
42-
import EventDefinitionSummary from './EventDefinitionSummary';
43-
import ShareForm from './ShareForm';
4430

4531
const WizardContainer = styled.div`
4632
margin-bottom: 10px;
4733
`;
34+
4835
const STEP_KEYS = {
4936
EVENT_DETAILS: 'event-details',
5037
CONDITION: 'condition',
@@ -71,55 +58,24 @@ const STEP_TELEMETRY_KEYS = [
7158
TELEMETRY_EVENT_TYPE.EVENTDEFINITION_SUMMARY.STEP_CLICKED,
7259
];
7360

74-
const getConditionPlugin = (type: string | undefined) => {
75-
if (type === undefined) {
76-
return { displayName: null };
77-
}
78-
79-
return PluginStore.exports('eventDefinitionTypes').find((edt) => edt.type === type) || {};
80-
};
81-
8261
type Props = {
62+
steps: Array<StepType<string>>;
8363
activeStep: string;
8464
action?: 'edit' | 'create';
85-
eventDefinition: EventDefinition & {
86-
share_request?: EntitySharePayload;
87-
};
88-
currentUser: User;
89-
validation: {
90-
errors: {
91-
config?: unknown;
92-
title?: string;
93-
};
94-
};
95-
entityTypes: {};
96-
notifications: Array<EventNotification>;
97-
defaults: { default_backlog_size: number };
98-
onChange: (key: string, value: unknown) => void;
9965
onChangeStep: (step: string) => void;
10066
onCancel: () => void;
10167
onSubmit: () => void;
102-
canEdit: boolean;
10368
formControls?: React.ComponentType<EventDefinitionFormControlsProps>;
104-
hideFieldsStep?: boolean;
10569
};
10670

10771
const EventDefinitionForm = ({
72+
steps,
10873
action = 'edit',
10974
activeStep,
110-
canEdit,
111-
currentUser,
112-
defaults,
113-
entityTypes,
114-
eventDefinition,
11575
formControls: FormControls = EventDefinitionFormControls,
116-
notifications,
11776
onCancel,
118-
onChange,
11977
onChangeStep,
12078
onSubmit,
121-
validation,
122-
hideFieldsStep = false,
12379
}: Props) => {
12480
const { pathname } = useLocation();
12581
const sendTelemetry = useSendTelemetry();
@@ -132,75 +88,6 @@ const EventDefinitionForm = ({
13288
onSubmit();
13389
};
13490

135-
const defaultStepProps = {
136-
key: eventDefinition.id, // Recreate components if ID changed
137-
action,
138-
entityTypes,
139-
eventDefinition,
140-
onChange,
141-
validation,
142-
currentUser,
143-
};
144-
145-
const canEditCondition = useMemo(
146-
() => canEdit || eventDefinition._scope.toUpperCase() === 'ILLUMINATE',
147-
[canEdit, eventDefinition._scope],
148-
);
149-
150-
const eventProcedureId = eventDefinition?.event_procedure || undefined;
151-
152-
const eventDefinitionType = getConditionPlugin(eventDefinition.config.type);
153-
const isNew = action === 'create';
154-
155-
const allSteps = [
156-
{
157-
key: STEP_KEYS.EVENT_DETAILS,
158-
title: 'Event Details',
159-
component: (
160-
<EventDetailsForm {...defaultStepProps} eventDefinitionEventProcedure={eventProcedureId} canEdit={canEdit} />
161-
),
162-
},
163-
{
164-
key: STEP_KEYS.CONDITION,
165-
title: eventDefinitionType?.displayName ?? 'Condition',
166-
component: <EventConditionForm {...defaultStepProps} canEdit={canEditCondition} />,
167-
},
168-
{
169-
key: STEP_KEYS.FIELDS,
170-
title: 'Fields',
171-
component: <FieldsForm {...defaultStepProps} canEdit={canEdit} />,
172-
},
173-
{
174-
key: STEP_KEYS.NOTIFICATIONS,
175-
title: 'Notifications',
176-
component: <NotificationsForm {...defaultStepProps} notifications={notifications} defaults={defaults} />,
177-
},
178-
{
179-
key: STEP_KEYS.SHARE,
180-
title: 'Share',
181-
component: <ShareForm {...defaultStepProps} />,
182-
},
183-
{
184-
key: STEP_KEYS.SUMMARY,
185-
title: 'Summary',
186-
component: (
187-
<EventDefinitionSummary
188-
eventDefinition={eventDefinition}
189-
currentUser={currentUser}
190-
notifications={notifications}
191-
validation={validation}
192-
/>
193-
),
194-
},
195-
];
196-
197-
const steps = allSteps.filter((step) => {
198-
if (step.key === STEP_KEYS.FIELDS && hideFieldsStep) return false;
199-
if (step.key === STEP_KEYS.SHARE && !isNew) return false;
200-
201-
return true;
202-
});
203-
20491
const currentStepKeys = steps.map((step) => step.key);
20592
const activeStepIndex = currentStepKeys.indexOf(activeStep);
20693

graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionFormContainer.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ jest.mock('stores/event-notifications/EventNotificationsStore', () => ({
153153
EventNotificationsActions: { listAll: jest.fn() },
154154
EventNotificationsStore: {
155155
listen: () => jest.fn(),
156+
listAll: jest.fn(() => Promise.resolve({ notifications: mockEventNotifications })),
156157
getInitialState: () => ({
157158
all: mockEventNotifications,
158159
allLegacyTypes: [],

0 commit comments

Comments
 (0)