diff --git a/graylog2-web-interface/src/@types/graylog-web-plugin/index.d.ts b/graylog2-web-interface/src/@types/graylog-web-plugin/index.d.ts
index 4c8e1040b5..59250ef87f 100644
--- a/graylog2-web-interface/src/@types/graylog-web-plugin/index.d.ts
+++ b/graylog2-web-interface/src/@types/graylog-web-plugin/index.d.ts
@@ -137,13 +137,30 @@ type DataTiering = {
}>,
}
+type FieldValueProvider = {
+ type: string,
+ displayName: string,
+ formComponent: React.ComponentType,
+ summaryComponent: React.ComponentType,
+ defaultConfig: {
+ template?: string,
+ table_name?: string,
+ key_field?: string,
+ },
+ requiredFields: {
+ template?: string,
+ table_name?: string,
+ key_field?: string,
+ },
+}
declare module 'graylog-web-plugin/plugin' {
interface PluginExports {
navigation?: Array;
dataTiering?: Array
defaultNavigation?: Array;
navigationItems?: Array;
- globalNotifications?: Array
+ globalNotifications?: Array;
+ fieldValueProviders?:Array;
// Global context providers allow to fetch and process data once
// and provide the result for all components in your plugin.
globalContextProviders?: Array>>,
diff --git a/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventConditionForm.tsx b/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventConditionForm.tsx
index b44647e5bf..a838034e27 100644
--- a/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventConditionForm.tsx
+++ b/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventConditionForm.tsx
@@ -25,10 +25,10 @@ import { Select } from 'components/common';
import { Clearfix, Col, ControlLabel, FormGroup, HelpBlock, Row } from 'components/bootstrap';
import { HelpPanel } from 'components/event-definitions/common/HelpPanel';
import type User from 'logic/users/User';
-import { getPathnameWithoutId } from 'util/URLUtils';
import useSendTelemetry from 'logic/telemetry/useSendTelemetry';
import useLocation from 'routing/useLocation';
import { TELEMETRY_EVENT_TYPE } from 'logic/telemetry/Constants';
+import { getPathnameWithoutId } from 'util/URLUtils';
import styles from './EventConditionForm.css';
@@ -143,9 +143,10 @@ const EventConditionForm = ({ action, entityTypes, eventDefinition, validation,
Configure how Graylog should create Events of this kind. You can later use those Events as input on other
Conditions, making it possible to build powerful Conditions based on others.
-
- Condition Type
+
+ Condition Type
.
*/
import type { SyntheticEvent } from 'react';
-import React, { useEffect, useState } from 'react';
+import * as React from 'react';
import PropTypes from 'prop-types';
-import last from 'lodash/last';
import defaultTo from 'lodash/defaultTo';
import { PluginStore } from 'graylog-web-plugin/plugin';
import styled from 'styled-components';
-import URI from 'urijs';
-import QS from 'qs';
import { getPathnameWithoutId } from 'util/URLUtils';
-import { Button, Col, Row } from 'components/bootstrap';
-import { ModalSubmit, Wizard } from 'components/common';
+import { Col, Row } from 'components/bootstrap';
+import { Wizard } from 'components/common';
import type { EventNotification } from 'stores/event-notifications/EventNotificationsStore';
-import type { EventDefinition } from 'components/event-definitions/event-definitions-types';
+import type { EventDefinition, EventDefinitionFormControlsProps } from 'components/event-definitions/event-definitions-types';
import type User from 'logic/users/User';
-import useQuery from 'routing/useQuery';
-import useHistory from 'routing/useHistory';
import useSendTelemetry from 'logic/telemetry/useSendTelemetry';
import useLocation from 'routing/useLocation';
import { TELEMETRY_EVENT_TYPE } from 'logic/telemetry/Constants';
+import EventDefinitionFormControls from 'components/event-definitions/event-definition-form/EventDefinitionFormControls';
import EventDetailsForm from './EventDetailsForm';
import EventConditionForm from './EventConditionForm';
@@ -42,7 +38,10 @@ import FieldsForm from './FieldsForm';
import NotificationsForm from './NotificationsForm';
import EventDefinitionSummary from './EventDefinitionSummary';
-const STEP_KEYS = ['event-details', 'condition', 'fields', 'notifications', 'summary'];
+const WizardContainer = styled.div`
+ margin-bottom: 10px;
+`;
+export const STEP_KEYS = ['event-details', 'condition', 'fields', 'notifications', 'summary'];
const STEP_TELEMETRY_KEYS = [
TELEMETRY_EVENT_TYPE.EVENTDEFINITION_DETAILS.STEP_CLICKED,
TELEMETRY_EVENT_TYPE.EVENTDEFINITION_CONDITION.STEP_CLICKED,
@@ -59,11 +58,8 @@ const getConditionPlugin = (type: string | undefined) => {
return PluginStore.exports('eventDefinitionTypes').find((edt) => edt.type === type) || {};
};
-const WizardContainer = styled.div`
- margin-bottom: 10px;
-`;
-
type Props = {
+ activeStep: string,
action: 'edit' | 'create',
eventDefinition: EventDefinition,
currentUser: User,
@@ -77,48 +73,40 @@ type Props = {
notifications: Array,
defaults: { default_backlog_size: number },
onChange: (key: string, value: unknown) => void,
+ onChangeStep: (step: string) => void,
onCancel: () => void,
onSubmit: () => void
canEdit: boolean,
+ formControls?: React.ComponentType
}
const EventDefinitionForm = ({
action,
- eventDefinition,
- currentUser,
- validation,
- entityTypes,
- notifications,
- defaults,
- onChange,
- onCancel,
- onSubmit,
+ activeStep,
canEdit,
+ currentUser,
+ defaults,
+ entityTypes,
+ eventDefinition,
+ formControls: FormControls,
+ notifications,
+ onCancel,
+ onChange,
+ onChangeStep,
+ onSubmit,
+ validation,
}: Props) => {
- const { step } = useQuery();
- const [activeStep, setActiveStep] = useState(step as string || STEP_KEYS[0]);
- const history = useHistory();
const { pathname } = useLocation();
const sendTelemetry = useSendTelemetry();
- useEffect(() => {
- const currentUrl = new URI(window.location.href);
- const queryParameters = QS.parse(currentUrl.query());
-
- if (queryParameters.step !== activeStep) {
- const newUrl = currentUrl.removeSearch('step').addQuery('step', activeStep);
- history.replace(newUrl.resource());
- }
- }, [activeStep, history]);
+ const activeStepIndex = STEP_KEYS.indexOf(activeStep);
const handleSubmit = (event: SyntheticEvent) => {
if (event) {
event.preventDefault();
}
- if (activeStep === last(STEP_KEYS)) {
- onSubmit();
- }
+ onSubmit();
};
const defaultStepProps = {
@@ -170,7 +158,7 @@ const EventDefinitionForm = ({
},
];
- const handleStepChange = (nextStep) => {
+ const handleStepChange = (nextStep: string) => {
sendTelemetry(STEP_TELEMETRY_KEYS[STEP_KEYS.indexOf(nextStep)], {
app_pathname: getPathnameWithoutId(pathname),
app_section: (action === 'create') ? 'new-event-definition' : 'edit-event-definition',
@@ -178,59 +166,31 @@ const EventDefinitionForm = ({
current_step: steps[STEP_KEYS.indexOf(activeStep)].title,
});
- setActiveStep(nextStep);
+ onChangeStep(nextStep);
};
- const renderButtons = () => {
- if (activeStep === last(STEP_KEYS)) {
- return (
-
- );
- }
+ const openPrevPage = () => {
+ sendTelemetry(TELEMETRY_EVENT_TYPE.EVENTDEFINITION_PREVIOUS_CLICKED, {
+ app_pathname: getPathnameWithoutId(pathname),
+ app_section: (action === 'create') ? 'new-event-definition' : 'edit-event-definition',
+ app_action_value: 'previous-button',
+ current_step: steps[activeStepIndex].title,
+ });
- const activeStepIndex = STEP_KEYS.indexOf(activeStep);
+ const previousStep = activeStepIndex > 0 ? STEP_KEYS[activeStepIndex - 1] : undefined;
+ onChangeStep(previousStep);
+ };
- const handlePreviousClick = () => {
- sendTelemetry(TELEMETRY_EVENT_TYPE.EVENTDEFINITION_PREVIOUS_CLICKED, {
- app_pathname: getPathnameWithoutId(pathname),
- app_section: (action === 'create') ? 'new-event-definition' : 'edit-event-definition',
- app_action_value: 'previous-button',
- current_step: steps[activeStepIndex].title,
- });
+ const openNextPage = () => {
+ sendTelemetry(TELEMETRY_EVENT_TYPE.EVENTDEFINITION_NEXT_CLICKED, {
+ app_pathname: getPathnameWithoutId(pathname),
+ app_section: (action === 'create') ? 'new-event-definition' : 'edit-event-definition',
+ app_action_value: 'next-button',
+ current_step: steps[activeStepIndex].title,
+ });
- const previousStep = activeStepIndex > 0 ? STEP_KEYS[activeStepIndex - 1] : undefined;
- setActiveStep(previousStep);
- };
-
- const handleNextClick = () => {
- sendTelemetry(TELEMETRY_EVENT_TYPE.EVENTDEFINITION_NEXT_CLICKED, {
- app_pathname: getPathnameWithoutId(pathname),
- app_section: (action === 'create') ? 'new-event-definition' : 'edit-event-definition',
- app_action_value: 'next-button',
- current_step: steps[activeStepIndex].title,
- });
-
- const nextStep = STEP_KEYS[activeStepIndex + 1];
- setActiveStep(nextStep);
- };
-
- return (
-
-
- Previous
-
-
-
- Next
-
-
-
- );
+ const nextStep = STEP_KEYS[activeStepIndex + 1];
+ onChangeStep(nextStep);
};
return (
@@ -245,7 +205,13 @@ const EventDefinitionForm = ({
containerClassName=""
hidePreviousNextButtons />
- {renderButtons()}
+
);
@@ -266,6 +232,7 @@ EventDefinitionForm.propTypes = {
EventDefinitionForm.defaultProps = {
action: 'edit',
+ formControls: EventDefinitionFormControls,
};
export default EventDefinitionForm;
diff --git a/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionFormContainer.test.tsx b/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionFormContainer.test.tsx
index 0b69e5918e..efafa592e0 100644
--- a/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionFormContainer.test.tsx
+++ b/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionFormContainer.test.tsx
@@ -194,6 +194,12 @@ jest.mock('logic/telemetry/useSendTelemetry');
jest.mock('hooks/useScopePermissions');
jest.mock('hooks/useCurrentUser');
+jest.mock('components/perspectives/hooks/useActivePerspective', () => () => ({
+ id: 'security',
+ title: 'Security',
+ welcomeRoute: '/security',
+}));
+
describe('EventDefinitionFormContainer', () => {
beforeEach(() => {
asMock(useLocation).mockImplementation(() => ({ pathname: '/event-definitions', search: '', hash: '', state: null, key: 'mock-key' }));
@@ -226,18 +232,18 @@ describe('EventDefinitionFormContainer', () => {
it('should render Filters & Aggregation form enabled', async () => {
render( );
-
- const tab = await screen.findByRole('button', { name: /filter & aggregation/i });
+ const tab = await screen.findByRole('button', { name: /condition/i });
userEvent.click(tab);
+ const conditionTypeSelect = await screen.findByLabelText('Condition Type');
- expect(screen.getByRole('textbox', { name: /search query/i })).toBeEnabled();
+ expect(conditionTypeSelect).toBeInTheDocument();
});
it('Filters & Aggregation should not be accessible for immutable entities', async () => {
asMock(useScopePermissions).mockImplementation(() => exampleEntityScopeImmutable);
render( );
- const tab = await screen.findByRole('button', { name: /filter & aggregation/i });
+ const tab = await screen.findByRole('button', { name: /condition/i });
userEvent.click(tab);
expect(screen.getByText(/cannot be edited/i)).toBeVisible();
diff --git a/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionFormContainer.tsx b/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionFormContainer.tsx
index 4e0e328333..adf7960df1 100644
--- a/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionFormContainer.tsx
+++ b/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionFormContainer.tsx
@@ -16,11 +16,9 @@
*/
import React, { useCallback, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
-import { useNavigate } from 'react-router-dom';
import { PluginStore } from 'graylog-web-plugin/plugin';
import cloneDeep from 'lodash/cloneDeep';
-import Routes from 'routing/Routes';
import { useStore } from 'stores/connect';
import EventDefinitionPriorityEnum from 'logic/alerts/EventDefinitionPriorityEnum';
import { ConfirmLeaveDialog, Spinner } from 'components/common';
@@ -28,8 +26,7 @@ import { AvailableEventDefinitionTypesStore } from 'stores/event-definitions/Ava
import { ConfigurationsActions } from 'stores/configurations/ConfigurationsStore';
import { EventDefinitionsActions } from 'stores/event-definitions/EventDefinitionsStore';
import { EventNotificationsActions, EventNotificationsStore } from 'stores/event-notifications/EventNotificationsStore';
-import 'components/event-notifications/event-notification-types';
-import type { EventDefinition } from 'components/event-definitions/event-definitions-types';
+import type { EventDefinition, EventDefinitionFormControlsProps } from 'components/event-definitions/event-definitions-types';
import useCurrentUser from 'hooks/useCurrentUser';
import useEventDefinitionConfigFromLocalStorage from 'components/event-definitions/hooks/useEventDefinitionConfigFromLocalStorage';
import { getPathnameWithoutId } from 'util/URLUtils';
@@ -38,7 +35,7 @@ import useLocation from 'routing/useLocation';
import { TELEMETRY_EVENT_TYPE } from 'logic/telemetry/Constants';
import useScopePermissions from 'hooks/useScopePermissions';
-import EventDefinitionForm from './EventDefinitionForm';
+import EventDefinitionForm, { STEP_KEYS } from './EventDefinitionForm';
const fetchNotifications = () => {
EventNotificationsActions.listAll();
@@ -47,7 +44,12 @@ const fetchNotifications = () => {
type Props = {
action: 'edit' | 'create',
eventDefinition: EventDefinition,
+ formControls?: React.ComponentType,
+ initialStep?: string,
+ onCancel?: () => void
+ onChangeStep?: (step: string) => void,
onEventDefinitionChange: (nextEventDefinition: EventDefinition) => void,
+ onSubmit?: () => void,
}
const getConditionPlugin = (edType): any => {
@@ -58,7 +60,17 @@ const getConditionPlugin = (edType): any => {
return PluginStore.exports('eventDefinitionTypes').find((eventDefinitionType) => eventDefinitionType.type === edType) || {};
};
-const EventDefinitionFormContainer = ({ action, eventDefinition: eventDefinitionInitial, onEventDefinitionChange }: Props) => {
+const EventDefinitionFormContainer = ({
+ action,
+ eventDefinition: eventDefinitionInitial,
+ formControls,
+ initialStep,
+ onCancel,
+ onChangeStep,
+ onEventDefinitionChange,
+ onSubmit,
+}: Props) => {
+ const [activeStep, setActiveStep] = useState(initialStep);
const [eventDefinition, setEventDefinition] = useState(eventDefinitionInitial);
const [validation, setValidation] = useState({ errors: {} });
const [eventsClusterConfig, setEventsClusterConfig] = useState(undefined);
@@ -69,7 +81,6 @@ const EventDefinitionFormContainer = ({ action, eventDefinition: eventDefinition
const entityTypes = useStore(AvailableEventDefinitionTypesStore);
const notifications = useStore(EventNotificationsStore);
const currentUser = useCurrentUser();
- const navigate = useNavigate();
const { pathname } = useLocation();
const sendTelemetry = useSendTelemetry();
@@ -111,7 +122,13 @@ const EventDefinitionFormContainer = ({ action, eventDefinition: eventDefinition
const handleSubmitSuccessResponse = () => {
setIsDirty(false);
- navigate(Routes.ALERTS.DEFINITIONS.LIST);
+
+ onSubmit();
+ };
+
+ const showValidationErrors = (errors: { errors: unknown }) => {
+ setValidation(errors);
+ setActiveStep(STEP_KEYS[STEP_KEYS.length - 1]);
};
const handleSubmitFailureResponse = (errorResponse) => {
@@ -119,7 +136,7 @@ const EventDefinitionFormContainer = ({ action, eventDefinition: eventDefinition
if (errorResponse.status === 400) {
if (body && body.failed) {
- setValidation(body);
+ showValidationErrors(body);
return;
}
@@ -128,7 +145,7 @@ const EventDefinitionFormContainer = ({ action, eventDefinition: eventDefinition
if (body.message.includes('org.graylog.events.conditions.Expression')
|| body.message.includes('org.graylog.events.conditions.Expr')
|| body.message.includes('org.graylog.events.processor.aggregation.AggregationSeries')) {
- setValidation({
+ showValidationErrors({
errors: { conditions: ['Aggregation condition is not valid'] },
});
@@ -136,7 +153,7 @@ const EventDefinitionFormContainer = ({ action, eventDefinition: eventDefinition
}
if (body.message.includes('embryonic')) {
- setValidation({
+ showValidationErrors({
errors: { query_parameters: ['Query parameters must be declared'] },
});
}
@@ -173,7 +190,12 @@ const EventDefinitionFormContainer = ({ action, eventDefinition: eventDefinition
app_action_value: 'cancel-button',
});
- navigate(Routes.ALERTS.DEFINITIONS.LIST);
+ onCancel();
+ };
+
+ const changeStep = (step: string) => {
+ onChangeStep?.(step);
+ setActiveStep(step);
};
if (isLoading || loadingScopePermissions) {
@@ -186,16 +208,19 @@ const EventDefinitionFormContainer = ({ action, eventDefinition: eventDefinition
)}
+ validation={validation} />
>
);
};
@@ -223,6 +248,11 @@ EventDefinitionFormContainer.defaultProps = {
notifications: [],
alert: false,
},
+ formControls: undefined,
+ initialStep: STEP_KEYS[0],
+ onCancel: undefined,
+ onSubmit: undefined,
+ onChangeStep: undefined,
onEventDefinitionChange: () => {},
};
diff --git a/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionFormControls.tsx b/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionFormControls.tsx
new file mode 100644
index 0000000000..e4e7327fd7
--- /dev/null
+++ b/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionFormControls.tsx
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 Graylog, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * .
+ */
+
+import React from 'react';
+
+import { ModalSubmit } from 'components/common';
+import { Button } from 'components/bootstrap';
+import type { EventDefinitionFormControlsProps } from 'components/event-definitions/event-definitions-types';
+
+const EventDefinitionFormControls = ({
+ action,
+ activeStepIndex,
+ onCancel,
+ onOpenNextPage,
+ onOpenPrevPage,
+ onSubmit,
+ steps,
+}: EventDefinitionFormControlsProps) => {
+ if (activeStepIndex === steps.length - 1) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+ Previous
+
+
+
+ Next
+
+
+
+ );
+};
+
+export default EventDefinitionFormControls;
diff --git a/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionSummary.tsx b/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionSummary.tsx
index a4e3bc1724..8924d7abdd 100644
--- a/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionSummary.tsx
+++ b/graylog2-web-interface/src/components/event-definitions/event-definition-form/EventDefinitionSummary.tsx
@@ -35,10 +35,6 @@ import type { EventDefinition } from '../event-definitions-types';
import commonStyles from '../common/commonStyles.css';
import { SYSTEM_EVENT_DEFINITION_TYPE } from '../constants';
-// Import built-in plugins
-import 'components/event-definitions/event-definition-types';
-import 'components/event-notifications/event-notification-types';
-
type Props = {
eventDefinition: Omit,
notifications: Array,
diff --git a/graylog2-web-interface/src/components/event-definitions/event-definition-form/FieldsForm.tsx b/graylog2-web-interface/src/components/event-definitions/event-definition-form/FieldsForm.tsx
index f26e46748d..815b43f723 100644
--- a/graylog2-web-interface/src/components/event-definitions/event-definition-form/FieldsForm.tsx
+++ b/graylog2-web-interface/src/components/event-definitions/event-definition-form/FieldsForm.tsx
@@ -29,9 +29,6 @@ import HoverForHelp from 'components/common/HoverForHelp';
import FieldForm from './FieldForm';
import FieldsList from './FieldsList';
-// Import built-in Field Value Providers
-import './field-value-providers';
-
import type { EventDefinition } from '../event-definitions-types';
import commonStyles from '../common/commonStyles.css';
diff --git a/graylog2-web-interface/src/components/event-definitions/event-definition-form/field-value-providers/index.js b/graylog2-web-interface/src/components/event-definitions/event-definition-form/field-value-providers/bindings.ts
similarity index 93%
rename from graylog2-web-interface/src/components/event-definitions/event-definition-form/field-value-providers/index.js
rename to graylog2-web-interface/src/components/event-definitions/event-definition-form/field-value-providers/bindings.ts
index 244a6772d0..99aa0bbb07 100644
--- a/graylog2-web-interface/src/components/event-definitions/event-definition-form/field-value-providers/index.js
+++ b/graylog2-web-interface/src/components/event-definitions/event-definition-form/field-value-providers/bindings.ts
@@ -14,15 +14,13 @@
* along with this program. If not, see
* .
*/
-import { PluginManifest, PluginStore } from 'graylog-web-plugin/plugin';
-
import TemplateFieldValueProviderForm from './TemplateFieldValueProviderForm';
import TemplateFieldValueProviderSummary from './TemplateFieldValueProviderSummary';
import LookupTableFieldValueProviderForm from './LookupTableFieldValueProviderForm';
import LookupTableFieldValueProviderFormContainer from './LookupTableFieldValueProviderFormContainer';
import LookupTableFieldValueProviderSummary from './LookupTableFieldValueProviderSummary';
-PluginStore.register(new PluginManifest({}, {
+export default {
fieldValueProviders: [
{
type: TemplateFieldValueProviderForm.type,
@@ -41,4 +39,4 @@ PluginStore.register(new PluginManifest({}, {
requiredFields: LookupTableFieldValueProviderForm.requiredFields,
},
],
-}));
+};
diff --git a/graylog2-web-interface/src/components/event-definitions/event-definition-types/FilterForm.tsx b/graylog2-web-interface/src/components/event-definitions/event-definition-types/FilterForm.tsx
index f83c484010..8a583aaade 100644
--- a/graylog2-web-interface/src/components/event-definitions/event-definition-types/FilterForm.tsx
+++ b/graylog2-web-interface/src/components/event-definitions/event-definition-types/FilterForm.tsx
@@ -14,6 +14,7 @@
* along with this program. If not, see
* .
*/
+
import * as React from 'react';
import { useCallback, useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
@@ -30,6 +31,10 @@ import union from 'lodash/union';
import moment from 'moment';
import { OrderedMap } from 'immutable';
+import { getPathnameWithoutId } from 'util/URLUtils';
+import { isPermitted } from 'util/PermissionsMixin';
+import * as FormsUtils from 'util/FormsUtils';
+import { naturalSortIgnoreCase } from 'util/SortUtils';
import FormWarningsContext from 'contexts/FormWarningsContext';
import { useStore } from 'stores/connect';
import Store from 'logic/local-storage/Store';
@@ -40,21 +45,18 @@ import Search from 'views/logic/search/Search';
import { extractDurationAndUnit } from 'components/common/TimeUnitInput';
import { Alert, ButtonToolbar, ControlLabel, FormGroup, HelpBlock, Input } from 'components/bootstrap';
import RelativeTime from 'components/common/RelativeTime';
-import { naturalSortIgnoreCase } from 'util/SortUtils';
-import * as FormsUtils from 'util/FormsUtils';
-import { isPermitted } from 'util/PermissionsMixin';
+import type { LookupTableParameterJson } from 'views/logic/parameters/LookupTableParameter';
import LookupTableParameter from 'views/logic/parameters/LookupTableParameter';
import { LookupTablesActions, LookupTablesStore } from 'stores/lookup-tables/LookupTablesStore';
import validateQuery from 'views/components/searchbar/queryvalidation/validateQuery';
import generateId from 'logic/generateId';
import parseSearch from 'views/logic/slices/parseSearch';
import useLocation from 'routing/useLocation';
-import { getPathnameWithoutId } from 'util/URLUtils';
import { TELEMETRY_EVENT_TYPE } from 'logic/telemetry/Constants';
import useSendTelemetry from 'logic/telemetry/useSendTelemetry';
import type User from 'logic/users/User';
import useUserDateTime from 'hooks/useUserDateTime';
-import type { EventDefinition } from 'components/event-definitions/event-definition-types';
+import type { EventDefinition } from 'components/event-definitions/event-definitions-types';
import type { Stream } from 'stores/streams/StreamsStore';
import type { QueryValidationState } from 'views/components/searchbar/queryvalidation/types';
import { indicesInWarmTier, isSearchingWarmTier } from 'views/components/searchbar/queryvalidation/warmTierValidation';
@@ -64,18 +66,19 @@ import commonStyles from '../common/commonStyles.css';
export const PLUGGABLE_CONTROLS_HIDDEN_KEY = 'pluggableSearchBarControlsAreHidden';
export const TIME_UNITS = ['HOURS', 'MINUTES', 'SECONDS'];
-
+type LookupTableParameterJsonEmbryonic = Partial & {
+ embryonic?: boolean,
+}
const LOOKUP_PERMISSIONS = [
'lookuptables:read',
];
-const buildNewParameter = (name: string) => ({
+const buildNewParameter = (name: string): LookupTableParameterJsonEmbryonic => ({
name: name,
embryonic: true,
type: 'lut-parameter-v1',
data_type: 'any',
title: 'new title',
- // has no binding, no need to set binding property
});
type Props = {
@@ -353,7 +356,7 @@ const FilterForm = ({
const parameterButtons = queryParameters.map((queryParam) => (
@@ -363,7 +366,7 @@ const FilterForm = ({
return null;
}
- const hasEmbryonicParameters = !isEmpty(queryParameters.filter((param) => (param.embryonic)));
+ const hasEmbryonicParameters = !isEmpty(queryParameters.filter((param : LookupTableParameterJsonEmbryonic) => (param.embryonic)));
return (
diff --git a/graylog2-web-interface/src/components/event-definitions/event-definition-types/index.js b/graylog2-web-interface/src/components/event-definitions/event-definition-types/bindings.js
similarity index 91%
rename from graylog2-web-interface/src/components/event-definitions/event-definition-types/index.js
rename to graylog2-web-interface/src/components/event-definitions/event-definition-types/bindings.js
index 67deac62b8..d2aaef40b3 100644
--- a/graylog2-web-interface/src/components/event-definitions/event-definition-types/index.js
+++ b/graylog2-web-interface/src/components/event-definitions/event-definition-types/bindings.js
@@ -14,13 +14,12 @@
* along with this program. If not, see
* .
*/
-import { PluginManifest, PluginStore } from 'graylog-web-plugin/plugin';
import FilterAggregationFormContainer from './FilterAggregationFormContainer';
import FilterAggregationForm from './FilterAggregationForm';
import FilterAggregationSummary from './FilterAggregationSummary';
-PluginStore.register(new PluginManifest({}, {
+export default {
eventDefinitionTypes: [
{
type: 'aggregation-v1',
@@ -33,4 +32,4 @@ PluginStore.register(new PluginManifest({}, {
defaultConfig: FilterAggregationForm.defaultConfig,
},
],
-}));
+};
diff --git a/graylog2-web-interface/src/components/event-definitions/event-definitions-types.ts b/graylog2-web-interface/src/components/event-definitions/event-definitions-types.ts
index c4b1a84ac6..6c05983ad3 100644
--- a/graylog2-web-interface/src/components/event-definitions/event-definitions-types.ts
+++ b/graylog2-web-interface/src/components/event-definitions/event-definitions-types.ts
@@ -14,6 +14,10 @@
* along with this program. If not, see
* .
*/
+import { type SyntheticEvent } from 'react';
+
+import type { Steps } from 'components/common/Wizard';
+import type { LookupTableParameterJson } from 'views/logic/parameters/LookupTableParameter';
type Provider = {
type: string,
@@ -29,8 +33,9 @@ type FieldSpec = {
};
type Notification = {
- notification_id: number,
-};
+ notification_id: string,
+ notification_parameters: string
+}
export type Scheduler = {
data: {
@@ -57,29 +62,51 @@ export type SearchFilter = {
};
export type EventDefinition = {
+ _scope: string,
id: string,
- config?: {
- type: string,
- execute_every_ms?: number,
- search_within_ms?: number,
- event_limit?: number,
- sigma_rule_id?: string,
- streams?: Array
- filters?: Array,
- },
title: string,
- description?: string,
- matched_at?: string,
- priority?: number,
- key_spec?: Array
- field_spec?: FieldSpec,
- notification_settings?: {
- backlog_size: number,
- grace_period_ms: number,
- }
- notifications?: Array,
- _scope?: string,
- scheduler?: Scheduler,
+ description: string,
+ priority: number,
+ alert: boolean,
state?: 'ENABLED' | 'DISABLED',
+ config: {
+ type: string,
+ query: string,
+ query_parameters: LookupTableParameterJson[],
+ filters: SearchFilter[],
+ streams: string[],
+ group_by: string[],
+ _is_scheduled: boolean,
+ series: Array<{field: string, id: string, type: string}>,
+ conditions: {
+ expression: string | null | {},
+ },
+ search_within_ms: number,
+ execute_every_ms: number,
+ },
+ field_spec: FieldSpec,
+ key_spec: string[],
+ notification_settings: {
+ grace_period_ms: number,
+ backlog_size: number,
+ },
+ notifications: Array,
remediation_steps?: string,
-};
+ storage: Array<{
+ type: string,
+ streams: number[] | string[],
+ }>,
+ updated_at: string | null,
+ matched_at?: string,
+ scheduler?: Scheduler,
+}
+
+export type EventDefinitionFormControlsProps = {
+ action: 'edit' | 'create',
+ activeStepIndex: number,
+ onCancel: () => void,
+ onOpenNextPage: () => void,
+ onOpenPrevPage: () => void,
+ onSubmit: (event: SyntheticEvent) => void,
+ steps: Steps,
+}
diff --git a/graylog2-web-interface/src/components/event-definitions/event-definitions/EventDefinitionsContainer.tsx b/graylog2-web-interface/src/components/event-definitions/event-definitions/EventDefinitionsContainer.tsx
index 6d510c35dd..cc6fc0c6cd 100644
--- a/graylog2-web-interface/src/components/event-definitions/event-definitions/EventDefinitionsContainer.tsx
+++ b/graylog2-web-interface/src/components/event-definitions/event-definitions/EventDefinitionsContainer.tsx
@@ -20,7 +20,6 @@ import { useState, useMemo, useCallback } from 'react';
import { EntityDataTable, NoSearchResult, PaginatedList, QueryHelper, RelativeTime, SearchForm, Spinner } from 'components/common';
import type { Sort } from 'stores/PaginationTypes';
import usePaginationQueryParameter from 'hooks/usePaginationQueryParameter';
-import 'components/event-definitions/event-definition-types';
import { Link } from 'components/common/router';
import Routes from 'routing/Routes';
import type { ColumnRenderers } from 'components/common/EntityDataTable';
diff --git a/graylog2-web-interface/src/components/event-notifications/event-notification-form/EventNotificationFormContainer.jsx b/graylog2-web-interface/src/components/event-notifications/event-notification-form/EventNotificationFormContainer.jsx
index c7019c1091..fd18229c42 100644
--- a/graylog2-web-interface/src/components/event-notifications/event-notification-form/EventNotificationFormContainer.jsx
+++ b/graylog2-web-interface/src/components/event-notifications/event-notification-form/EventNotificationFormContainer.jsx
@@ -26,10 +26,6 @@ import withHistory from 'routing/withHistory';
import EventNotificationForm from './EventNotificationForm';
-// Import built-in Event Notification Types
-
-import '../event-notification-types';
-
const initialValidation = {
errors: {},
};
diff --git a/graylog2-web-interface/src/components/event-notifications/event-notification-types/index.js b/graylog2-web-interface/src/components/event-notifications/event-notification-types/bindings.ts
similarity index 95%
rename from graylog2-web-interface/src/components/event-notifications/event-notification-types/index.js
rename to graylog2-web-interface/src/components/event-notifications/event-notification-types/bindings.ts
index 4929b25bae..b6712cad33 100644
--- a/graylog2-web-interface/src/components/event-notifications/event-notification-types/index.js
+++ b/graylog2-web-interface/src/components/event-notifications/event-notification-types/bindings.ts
@@ -14,8 +14,6 @@
* along with this program. If not, see
* .
*/
-import { PluginManifest, PluginStore } from 'graylog-web-plugin/plugin';
-
import EmailNotificationFormContainer from './EmailNotificationFormContainer';
import EmailNotificationForm from './EmailNotificationForm';
import EmailNotificationSummary from './EmailNotificationSummary';
@@ -32,7 +30,7 @@ import HttpNotificationDetails from '../event-notification-details/HttpNotificat
import LegacyNotificationDetails from '../event-notification-details/LegacyNotificationDetails';
import HttpNotificationDetailsV2 from '../event-notification-details/HttpNotificationDetailsV2';
-PluginStore.register(new PluginManifest({}, {
+export default {
eventNotificationTypes: [
{
type: 'email-notification-v1',
@@ -67,4 +65,4 @@ PluginStore.register(new PluginManifest({}, {
defaultConfig: LegacyNotificationForm.defaultConfig,
},
],
-}));
+};
diff --git a/graylog2-web-interface/src/components/event-notifications/event-notifications/EventNotificationsContainer.tsx b/graylog2-web-interface/src/components/event-notifications/event-notifications/EventNotificationsContainer.tsx
index 2c9efbc9a3..fb7f003905 100644
--- a/graylog2-web-interface/src/components/event-notifications/event-notifications/EventNotificationsContainer.tsx
+++ b/graylog2-web-interface/src/components/event-notifications/event-notifications/EventNotificationsContainer.tsx
@@ -38,9 +38,6 @@ import BulkActions from './BulkActions';
import useEventNotifications from '../hooks/useEventNotifications';
import useNotificationTest from '../hooks/useNotificationTest';
-// Import built-in Event Notification Types
-import '../event-notification-types';
-
const customColumnRenderers = (testResults: TestResults): ColumnRenderers => ({
attributes: {
title: {
diff --git a/graylog2-web-interface/src/components/events/events/EventsContainer.jsx b/graylog2-web-interface/src/components/events/events/EventsContainer.jsx
index 3203ce9f18..4eabe9b713 100644
--- a/graylog2-web-interface/src/components/events/events/EventsContainer.jsx
+++ b/graylog2-web-interface/src/components/events/events/EventsContainer.jsx
@@ -30,8 +30,6 @@ import withPaginationQueryParameter from 'components/common/withPaginationQueryP
import Events, { PAGE_SIZES, EVENTS_MAX_OFFSET_LIMIT } from './Events';
-import 'components/event-definitions/event-definition-types';
-
const LOCAL_STORAGE_ITEM = 'events-last-search';
const SEARCH_DEBOUNCE_THRESHOLD = 500;
diff --git a/graylog2-web-interface/src/components/events/events/hooks/useEventDefinition.tsx b/graylog2-web-interface/src/components/events/events/hooks/useEventDefinition.tsx
index af0e49cca0..ae9528b6b7 100644
--- a/graylog2-web-interface/src/components/events/events/hooks/useEventDefinition.tsx
+++ b/graylog2-web-interface/src/components/events/events/hooks/useEventDefinition.tsx
@@ -16,10 +16,10 @@
*/
import { useQuery } from '@tanstack/react-query';
-import type { EventDefinition } from 'logic/alerts/types';
import fetch from 'logic/rest/FetchProvider';
import { qualifyUrl } from 'util/URLUtils';
import UserNotification from 'preflight/util/UserNotification';
+import type { EventDefinition } from 'components/event-definitions/event-definitions-types';
export const fetchEventDefinitionDetails = async (eventDefinitionId: string): Promise => (
fetch('GET', qualifyUrl(`/events/definitions/${eventDefinitionId}`))
diff --git a/graylog2-web-interface/src/hooks/useAlertAndEventDefinitionData.tsx b/graylog2-web-interface/src/hooks/useAlertAndEventDefinitionData.tsx
index d932ca22e2..24cb87d950 100644
--- a/graylog2-web-interface/src/hooks/useAlertAndEventDefinitionData.tsx
+++ b/graylog2-web-interface/src/hooks/useAlertAndEventDefinitionData.tsx
@@ -23,7 +23,7 @@ import Routes from 'routing/Routes';
import useParams from 'routing/useParams';
import type { Event } from 'components/events/events/types';
import type { EventDefinitionAggregation } from 'hooks/useEventDefinition';
-import type { EventDefinition } from 'logic/alerts/types';
+import type { EventDefinition } from 'components/event-definitions/event-definitions-types';
const useAlertAndEventDefinitionData = () => {
const { pathname: path } = useLocation();
diff --git a/graylog2-web-interface/src/hooks/useEventDefinition.tsx b/graylog2-web-interface/src/hooks/useEventDefinition.tsx
index 27329c879a..28ca06fb86 100644
--- a/graylog2-web-interface/src/hooks/useEventDefinition.tsx
+++ b/graylog2-web-interface/src/hooks/useEventDefinition.tsx
@@ -21,7 +21,7 @@ import isEqual from 'lodash/isEqual';
import UserNotification from 'util/UserNotification';
import fetch from 'logic/rest/FetchProvider';
import { qualifyUrl } from 'util/URLUtils';
-import type { EventDefinition } from 'logic/alerts/types';
+import type { EventDefinition } from 'components/event-definitions/event-definitions-types';
import type FetchError from 'logic/errors/FetchError';
export type ValueExpr = '>' | '<' | '>=' | '<=' | '==';
diff --git a/graylog2-web-interface/src/index.tsx b/graylog2-web-interface/src/index.tsx
index f8257957ad..892b4d4cbf 100644
--- a/graylog2-web-interface/src/index.tsx
+++ b/graylog2-web-interface/src/index.tsx
@@ -28,6 +28,9 @@ import ViewsBindings from 'views/bindings';
import ThreatIntelBindings from 'threatintel/bindings';
import AwsBindings from 'aws/bindings';
import IntegrationsBindings from 'integrations/bindings';
+import EventDefinitionsBindings from 'components/event-definitions/event-definition-types/bindings';
+import EventNotificationsBindings from 'components/event-notifications/event-notification-types/bindings';
+import FieldValueProvidersBindings from 'components/event-definitions/event-definition-form/field-value-providers/bindings';
import CancellablePromise from 'logic/rest/CancellablePromise';
import TelemetryInit from 'logic/telemetry/TelemetryInit';
import LoginQueryClientProvider from 'contexts/LoginQueryClientProvider';
@@ -44,6 +47,9 @@ PluginStore.register(new PluginManifest({}, ViewsBindings));
PluginStore.register(new PluginManifest({}, ThreatIntelBindings));
PluginStore.register(new PluginManifest({}, AwsBindings));
PluginStore.register(new PluginManifest({}, IntegrationsBindings));
+PluginStore.register(new PluginManifest({}, EventDefinitionsBindings));
+PluginStore.register(new PluginManifest({}, EventNotificationsBindings));
+PluginStore.register(new PluginManifest({}, FieldValueProvidersBindings));
PluginStore.register(new PluginManifest({}, PerspectivesBindings));
PluginStore.register(new PluginManifest({}, NavigationBindings));
PluginStore.register(new PluginManifest({}, SecurityBindings));
diff --git a/graylog2-web-interface/src/logic/alerts/types.ts b/graylog2-web-interface/src/logic/alerts/types.ts
deleted file mode 100644
index 7b579d6994..0000000000
--- a/graylog2-web-interface/src/logic/alerts/types.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2020 Graylog, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * .
- */
-
-import type { ParameterJson } from 'views/logic/parameters/Parameter';
-import type { SearchFilter } from 'components/event-definitions/event-definitions-types';
-
-export type EventDefinition = {
- _scope: string,
- id: string,
- title: string,
- description: string,
- priority: number,
- alert: boolean,
- config: {
- type: string,
- query: string,
- query_parameters: ParameterJson[],
- filters: SearchFilter[],
- streams: string[],
- group_by: string[],
- series: Array<{field: string, id: string, type: string}>,
- conditions: {
- expression: string | null | {},
- },
- search_within_ms: number,
- execute_every_ms: number,
- },
- field_spec: {},
- key_spec: string[],
- notification_settings: {
- grace_period_ms: number,
- backlog_size: number,
- },
- notifications: Array<{ notification_id: string, notification_parameters: string}>,
- storage: [
- {
- type: string,
- streams: number[] | string[],
- }
- ],
- updated_at: string | null
-}
diff --git a/graylog2-web-interface/src/pages/CreateEventDefinitionPage.tsx b/graylog2-web-interface/src/pages/CreateEventDefinitionPage.tsx
index d915054236..48283252f5 100644
--- a/graylog2-web-interface/src/pages/CreateEventDefinitionPage.tsx
+++ b/graylog2-web-interface/src/pages/CreateEventDefinitionPage.tsx
@@ -40,6 +40,10 @@ const CreateEventDefinitionPage = () => {
const pageTitle = useMemo(() => (eventDefinitionTitle ? `New Event Definition "${eventDefinitionTitle}"` : 'New Event Definition'), [eventDefinitionTitle]);
+ const goToOverview = useCallback(() => {
+ navigate(Routes.ALERTS.DEFINITIONS.LIST);
+ }, [navigate]);
+
useEffect(() => {
if (!isPermitted(currentUser.permissions, 'eventdefinitions:create')) {
navigate(Routes.NOTFOUND);
@@ -62,7 +66,10 @@ const CreateEventDefinitionPage = () => {
-
+
diff --git a/graylog2-web-interface/src/pages/EditEventDefinitionPage.tsx b/graylog2-web-interface/src/pages/EditEventDefinitionPage.tsx
index 8cd23dfd91..29d9076e14 100644
--- a/graylog2-web-interface/src/pages/EditEventDefinitionPage.tsx
+++ b/graylog2-web-interface/src/pages/EditEventDefinitionPage.tsx
@@ -14,8 +14,9 @@
* along with this program. If not, see
* .
*/
-import React from 'react';
-import { useParams } from 'react-router-dom';
+import React, { useCallback } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
+import URI from 'urijs';
import EventsPageNavigation from 'components/events/EventsPageNavigation';
import { Col, Row } from 'components/bootstrap';
@@ -28,14 +29,21 @@ import useCurrentUser from 'hooks/useCurrentUser';
import { EventDefinitionsActions } from 'stores/event-definitions/EventDefinitionsStore';
import type { EventDefinition } from 'components/event-definitions/event-definitions-types';
import useHistory from 'routing/useHistory';
+import useQuery from 'routing/useQuery';
import StreamPermissionErrorPage from './StreamPermissionErrorPage';
const EditEventDefinitionPage = () => {
const params = useParams<{definitionId?: string}>();
+ const { step } = useQuery();
const currentUser = useCurrentUser();
const [eventDefinition, setEventDefinition] = React.useState(undefined);
const history = useHistory();
+ const navigate = useNavigate();
+
+ const goToOverview = useCallback(() => {
+ navigate(Routes.ALERTS.DEFINITIONS.LIST);
+ }, [navigate]);
React.useEffect(() => {
if (isPermitted(currentUser.permissions, `eventdefinitions:edit:${params.definitionId}`)) {
@@ -71,6 +79,11 @@ const EditEventDefinitionPage = () => {
const missingStreams = streamsWithMissingPermissions();
+ const updateURLStepQueryParam = (newStep: string) => {
+ const newUrl = new URI(window.location.href).removeSearch('step').addQuery('step', newStep);
+ history.replace(newUrl.resource());
+ };
+
if (missingStreams.length > 0) {
return ;
}
@@ -101,7 +114,12 @@ const EditEventDefinitionPage = () => {
-
+
diff --git a/graylog2-web-interface/src/pages/ShowEventNotificationPage.tsx b/graylog2-web-interface/src/pages/ShowEventNotificationPage.tsx
index ee329ba37b..0e639c8f54 100644
--- a/graylog2-web-interface/src/pages/ShowEventNotificationPage.tsx
+++ b/graylog2-web-interface/src/pages/ShowEventNotificationPage.tsx
@@ -29,7 +29,6 @@ import EventNotificationDetails from 'components/event-notifications/event-notif
import EventNotificationActionLinks from 'components/event-notifications/event-notification-details/EventNotificationActionLinks';
import type { EventNotification } from 'stores/event-notifications/EventNotificationsStore';
import { EventNotificationsActions } from 'stores/event-notifications/EventNotificationsStore';
-import 'components/event-notifications/event-notification-types';
import EventsPageNavigation from 'components/events/EventsPageNavigation';
import useHistory from '../routing/useHistory';
diff --git a/graylog2-web-interface/src/views/logic/views/UseCreateViewForEvent.ts b/graylog2-web-interface/src/views/logic/views/UseCreateViewForEvent.ts
index ed41eaad81..b34ed9a2bb 100644
--- a/graylog2-web-interface/src/views/logic/views/UseCreateViewForEvent.ts
+++ b/graylog2-web-interface/src/views/logic/views/UseCreateViewForEvent.ts
@@ -21,7 +21,7 @@ import uniq from 'lodash/uniq';
import View from 'views/logic/views/View';
import type { AbsoluteTimeRange, ElasticsearchQueryString, RelativeTimeRangeStartOnly } from 'views/logic/queries/Query';
import type { Event } from 'components/events/events/types';
-import type { EventDefinition } from 'logic/alerts/types';
+import type { EventDefinition, SearchFilter } from 'components/event-definitions/event-definitions-types';
import QueryGenerator from 'views/logic/queries/QueryGenerator';
import Search from 'views/logic/search/Search';
import { matchesDecoratorStream } from 'views/logic/views/ViewStateGenerator';
@@ -46,7 +46,6 @@ import { concatQueryStrings, escape } from 'views/logic/queries/QueryHelper';
import HighlightingRule, { randomColor } from 'views/logic/views/formatting/highlighting/HighlightingRule';
import { exprToConditionMapper } from 'views/logic/ExpressionConditionMappers';
import FormattingSettings from 'views/logic/views/formatting/FormattingSettings';
-import type { SearchFilter } from 'components/event-definitions/event-definitions-types';
const AGGREGATION_WIDGET_HEIGHT = 3;
diff --git a/graylog2-web-interface/src/views/logic/views/UseCreateViewForEventDefinition.ts b/graylog2-web-interface/src/views/logic/views/UseCreateViewForEventDefinition.ts
index 4126f38b3c..1f73714cbf 100644
--- a/graylog2-web-interface/src/views/logic/views/UseCreateViewForEventDefinition.ts
+++ b/graylog2-web-interface/src/views/logic/views/UseCreateViewForEventDefinition.ts
@@ -17,7 +17,7 @@
import { useMemo } from 'react';
-import type { EventDefinition } from 'logic/alerts/types';
+import type { EventDefinition } from 'components/event-definitions/event-definitions-types';
import type { EventDefinitionAggregation } from 'hooks/useEventDefinition';
import type { ElasticsearchQueryString, RelativeTimeRangeStartOnly } from 'views/logic/queries/Query';
import { ViewGenerator } from 'views/logic/views/UseCreateViewForEvent';
diff --git a/graylog2-web-interface/test/fixtures/eventDefinition.ts b/graylog2-web-interface/test/fixtures/eventDefinition.ts
index d97287dae3..1ecc44104e 100644
--- a/graylog2-web-interface/test/fixtures/eventDefinition.ts
+++ b/graylog2-web-interface/test/fixtures/eventDefinition.ts
@@ -29,7 +29,9 @@ export const simpleEventDefinition = {
streams: ['stream-id-1'],
type: 'aggregation-v1',
filters: [],
+ _is_scheduled: true,
},
+ updated_at: '2024-02-26T15:32:24.666Z',
description: '',
field_spec: {},
id: 'event-definition-1-id',
diff --git a/graylog2-web-interface/test/helpers/mocking/EventAndEventDefinitions_mock.ts b/graylog2-web-interface/test/helpers/mocking/EventAndEventDefinitions_mock.ts
index 48699fd675..2b0da0a836 100644
--- a/graylog2-web-interface/test/helpers/mocking/EventAndEventDefinitions_mock.ts
+++ b/graylog2-web-interface/test/helpers/mocking/EventAndEventDefinitions_mock.ts
@@ -17,7 +17,7 @@
import Immutable from 'immutable';
import type { Event } from 'components/events/events/types';
-import type { EventDefinition } from 'logic/alerts/types';
+import type { EventDefinition } from 'components/event-definitions/event-definitions-types';
import type { EventDefinitionAggregation } from 'hooks/useEventDefinition';
import QueryGenerator from 'views/logic/queries/QueryGenerator';
import Search from 'views/logic/search/Search';
@@ -84,6 +84,7 @@ export const mockEventDefinitionTwoAggregations:EventDefinition = {
type: 'aggregation-v1',
query: 'http_method: GET',
query_parameters: [],
+ _is_scheduled: true,
streams: [
'001',
],