Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ const EventConditionForm = ({
const eventDefinitionTypes = usePluginEntities('eventDefinitionTypes');
const filteredDefinitionTypes = eventDefinitionTypes.filter((type) => type.useCondition());

const currentConditionPlugin = useMemo(
() => eventDefinitionTypes.find((edt) => edt.type === eventDefinition.config.type),
[eventDefinitionTypes, eventDefinition.config.type],
);

const getConditionPlugin = useCallback(
(type: string) => {
if (type === undefined) {
Expand Down Expand Up @@ -109,10 +114,15 @@ const EventConditionForm = ({
[filteredDefinitionTypes],
);

const formattedEventDefinitionTypes = useMemo(
() => sortedEventDefinitionTypes.map((type) => ({ label: type.displayName, value: type.type })),
[sortedEventDefinitionTypes],
);
const formattedEventDefinitionTypes = useMemo(() => {
const options = sortedEventDefinitionTypes.map((type) => ({ label: type.displayName, value: type.type }));

if (currentConditionPlugin && !options.some((o) => o.value === currentConditionPlugin.type)) {
options.push({ label: currentConditionPlugin.displayName, value: currentConditionPlugin.type });
}

return options;
}, [sortedEventDefinitionTypes, currentConditionPlugin]);

const handleEventDefinitionTypeChange = (nextType: string) => {
sendTelemetry(TELEMETRY_EVENT_TYPE.EVENTDEFINITION_CONDITION.TYPE_SELECTED, {
Expand Down Expand Up @@ -141,15 +151,11 @@ const EventConditionForm = ({
[action, eventDefinition.config.type],
);

const eventDefinitionType = useMemo(
() => getConditionPlugin(eventDefinition.config.type),
[eventDefinition.config.type, getConditionPlugin],
);
const isSystemEventDefinition = eventDefinition.config.type === SYSTEM_EVENT_DEFINITION_TYPE;
const canEditCondition = canEdit && !isSystemEventDefinition;

const eventDefinitionTypeComponent = eventDefinitionType?.formComponent
? React.createElement(eventDefinitionType.formComponent, {
const eventDefinitionTypeComponent = currentConditionPlugin?.formComponent
? React.createElement(currentConditionPlugin.formComponent, {
action,
entityTypes,
currentUser,
Expand Down Expand Up @@ -192,20 +198,17 @@ const EventConditionForm = ({
</Col>

{canEditCondition && !disabledSelect && (
<Col md={5} lg={5} lgOffset={1}>
<HelpPanel className={styles.conditionTypesInfo} title="Available Conditions">
<ConditionTypeDescriptions eventDefinitionTypes={sortedEventDefinitionTypes} />
</HelpPanel>
</Col>
)}
<Clearfix />
{canEditCondition && eventDefinitionTypeComponent && (
<>
<Col md={5} lg={5} lgOffset={1}>
<HelpPanel className={styles.conditionTypesInfo} title="Available Conditions">
<ConditionTypeDescriptions eventDefinitionTypes={sortedEventDefinitionTypes} />
</HelpPanel>
</Col>
<Clearfix />

{eventDefinitionTypeComponent && (
<>
<hr className={styles.hr} />
<Col md={12}>{eventDefinitionTypeComponent}</Col>
</>
)}
<hr className={styles.hr} />
<Col md={12}>{eventDefinitionTypeComponent}</Col>
</>
)}
</Row>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,7 @@ const EventDetailsForm = ({ eventDefinition, eventDefinitionEventProcedure, vali
data: { valid: validSecurityLicense },
} = usePluggableLicenseCheck('/license/security');

const readOnly = useMemo(
() => !canEdit || isSystemEventDefinition(eventDefinition) || eventDefinition.config.type === 'sigma-v1',
[canEdit, eventDefinition],
);
const readOnly = useMemo(() => !canEdit || isSystemEventDefinition(eventDefinition), [canEdit, eventDefinition]);
const showEventProcedureSummary = useMemo(
() => !!eventDefinitionEventProcedure && !showAddEventProcedureForm && validSecurityLicense,
[eventDefinitionEventProcedure, showAddEventProcedureForm, validSecurityLicense],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ import * as React from 'react';
import { useContext } from 'react';
import isEmpty from 'lodash/isEmpty';
import upperFirst from 'lodash/upperFirst';
import styled from 'styled-components';

import { describeExpression } from 'util/CronUtils';
import { Link } from 'components/common';
import { Alert } from 'components/bootstrap';
import { DataWell } from 'components/lookup-tables/layout-componets';
import { extractDurationAndUnit } from 'components/common/TimeUnitInput';
import { isPermitted } from 'util/PermissionsMixin';
import { naturalSortIgnoreCase } from 'util/SortUtils';
Expand All @@ -40,6 +42,16 @@ import styles from './FilterAggregationSummary.css';

import LinkToReplaySearch from '../replay-search/LinkToReplaySearch';

const StyledDataWell = styled(DataWell)`
line-height: 1.8;
white-space: pre;
font-family: monospace;
font-size: medium;
color: ${({ theme }) => (theme.mode === 'light' ? 'darkslateblue' : 'lightsteelblue')};
overflow: auto;
text-wrap: auto;
`;

const StreamOrId = ({ streamOrId }: { streamOrId: Stream | string }) => {
if (typeof streamOrId === 'string') {
return (
Expand Down Expand Up @@ -89,7 +101,7 @@ type Props = {
};

const SearchFilters = ({ filters }: { filters: EventDefinition['config']['filters'] }) => {
if (!filters || filters.length === 0) {
if (!filters || filters?.length === 0) {
return <dd>No filters configured</dd>;
}

Expand All @@ -112,12 +124,12 @@ type StreamsProps = {
};

const Streams = ({ streams, streamIds, streamIdsWithMissingPermission }: StreamsProps) => {
if ((!streamIds || streamIds.length === 0) && streamIdsWithMissingPermission.length <= 0) {
if ((!streamIds || streamIds?.length === 0) && streamIdsWithMissingPermission?.length <= 0) {
return <>No Streams selected, searches in all Streams</>;
}

const warning =
streamIdsWithMissingPermission.length > 0 ? (
streamIdsWithMissingPermission?.length > 0 ? (
<Alert bsStyle="warning">
Missing Stream Permissions for:
<br />
Expand Down Expand Up @@ -178,7 +190,7 @@ const FilterAggregationSummary = ({ config, currentUser, definitionId = undefine
};

const renderStreamCategories = () => {
if (!streamCategories || streamCategories.length === 0) return null;
if (!streamCategories || streamCategories?.length === 0) return null;

const renderedCategories = streamCategories.map((s) => <StreamOrId key={s} streamOrId={s} />);

Expand All @@ -195,8 +207,10 @@ const FilterAggregationSummary = ({ config, currentUser, definitionId = undefine
<dt>Type</dt>
<dd>{upperFirst(conditionType)}</dd>
<dt>Search Query</dt>
<dd>{query || '*'}</dd>
{queryParameters.length > 0 && <QueryParameters queryParameters={queryParameters} />}
<dd>
<StyledDataWell>{query || '*'}</StyledDataWell>
</dd>
{queryParameters?.length > 0 && <QueryParameters queryParameters={queryParameters} />}
<dt>Search Filters</dt>
<SearchFilters filters={config.filters} />
<dt>Streams</dt>
Expand Down Expand Up @@ -242,7 +256,7 @@ const FilterAggregationSummary = ({ config, currentUser, definitionId = undefine
{conditionType === 'aggregation' && (
<>
<dt>Group by Field(s)</dt>
<dd>{groupBy && groupBy.length > 0 ? groupBy.join(', ') : 'No Group by configured'}</dd>
<dd>{groupBy && groupBy?.length > 0 ? groupBy.join(', ') : 'No Group by configured'}</dd>
<dt>Create Events if</dt>
<dd>
{validationResults.isValid ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import useLocation from 'routing/useLocation';
import { TELEMETRY_EVENT_TYPE } from 'logic/telemetry/Constants';
import useSelectedEntities from 'components/common/EntityDataTable/hooks/useSelectedEntities';
import { MoreActions } from 'components/common/EntityDataTable';
import usePluginEntities from 'hooks/usePluginEntities';
import { useTableFetchContext } from 'components/common/PaginatedEntityTable';
import usePluggableEntitySharedActions from 'hooks/usePluggableEntitySharedActions';

Expand All @@ -42,10 +41,6 @@ import {
isSigmaEventDefinition,
} from '../event-definitions-types';

type SigmaEventDefinitionConfig = EventDefinition['config'] & {
sigma_rule_id: string;
};

type Props = {
eventDefinition: EventDefinition;
};
Expand Down Expand Up @@ -84,7 +79,6 @@ const EventDefinitionActions = ({ eventDefinition }: Props) => {
const [showDialog, setShowDialog] = useState(false);
const [dialogType, setDialogType] = useState(null);
const [showEntityShareModal, setShowEntityShareModal] = useState(false);
const [showSigmaModal, setShowSigmaModal] = useState(false);
const { pathname } = useLocation();
const sendTelemetry = useSendTelemetry();
const navigate = useNavigate();
Expand All @@ -99,21 +93,9 @@ const EventDefinitionActions = ({ eventDefinition }: Props) => {
return 'System Event Definition cannot be deleted';
}

if (isSigmaEventDefinition(eventDefinition)) {
return 'Sigma Rules must be deleted from the Sigma Rules page';
}

return undefined;
};

const pluggableSigmaModal = usePluginEntities('eventDefinitions.components.editSigmaModal').find(
(entity: { key: string }) => entity.key === 'coreSigmaModal',
);

const CoreSigmaModal = pluggableSigmaModal
? (pluggableSigmaModal.component as React.FC<{ ruleId: string; onCancel: () => void; onConfirm: () => void }>)
: null;

const updateState = ({ show, type, definition }) => {
setShowDialog(show);
setDialogType(type);
Expand Down Expand Up @@ -233,18 +215,7 @@ const EventDefinitionActions = ({ eventDefinition }: Props) => {
}
};

const onEditEventDefinition = () => {
if (isSigmaEventDefinition(eventDefinition)) {
setShowSigmaModal(true);
} else {
navigate(Routes.ALERTS.DEFINITIONS.edit(eventDefinition.id));
}
};

const onSigmaModalClose = () => {
refetchEventDefinitions();
setShowSigmaModal(false);
};
const onEditEventDefinition = () => navigate(Routes.ALERTS.DEFINITIONS.edit(eventDefinition.id));

const isEnabled = eventDefinition?.state === 'ENABLED';

Expand All @@ -258,11 +229,13 @@ const EventDefinitionActions = ({ eventDefinition }: Props) => {
bsSize="xsmall"
/>
<MoreActions>
<IfPermitted permissions={`eventdefinitions:edit:${eventDefinition.id}`}>
<MenuItem onClick={onEditEventDefinition} data-testid="edit-button">
Edit
</MenuItem>
</IfPermitted>
{(!isSigmaEventDefinition(eventDefinition) || showActions()) && (
<IfPermitted permissions={`eventdefinitions:edit:${eventDefinition.id}`}>
<MenuItem onClick={onEditEventDefinition} data-testid="edit-button">
Edit
</MenuItem>
</IfPermitted>
)}
<IfPermitted permissions="eventdefinitions:create">
{!isSystemEventDefinition(eventDefinition) && !isSigmaEventDefinition(eventDefinition) && (
<MenuItem onClick={() => handleAction(DIALOG_TYPES.COPY, eventDefinition)}>Duplicate</MenuItem>
Expand All @@ -287,10 +260,10 @@ const EventDefinitionActions = ({ eventDefinition }: Props) => {
<IfPermitted permissions={`eventdefinitions:delete:${eventDefinition.id}`}>
<MenuItem divider />
<DeleteMenuItem
disabled={isSystemEventDefinition(eventDefinition) || isSigmaEventDefinition(eventDefinition)}
disabled={isSystemEventDefinition(eventDefinition)}
title={getDeleteActionTitle()}
onClick={
isSystemEventDefinition(eventDefinition) || isSigmaEventDefinition(eventDefinition)
isSystemEventDefinition(eventDefinition)
? undefined
: () => handleAction(DIALOG_TYPES.DELETE, eventDefinition)
}
Expand Down Expand Up @@ -335,13 +308,6 @@ const EventDefinitionActions = ({ eventDefinition }: Props) => {
onClose={() => setShowEntityShareModal(false)}
/>
)}
{showSigmaModal && CoreSigmaModal && (
<CoreSigmaModal
ruleId={(eventDefinition.config as SigmaEventDefinitionConfig).sigma_rule_id}
onCancel={onSigmaModalClose}
onConfirm={onSigmaModalClose}
/>
)}
{pluggableActionModals}
</>
);
Expand Down
31 changes: 20 additions & 11 deletions graylog2-web-interface/src/pages/ViewEventDefinitionPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ import type { Permission } from 'graylog-web-plugin/plugin';

import Routes from 'routing/Routes';
import usePluginEntities from 'hooks/usePluginEntities';
import mockAction from 'helpers/mocking/MockAction';
import MockStore from 'helpers/mocking/StoreMock';
import mockAction from 'helpers/mocking/MockAction';
import mockComponent from 'helpers/mocking/MockComponent';
import { simpleEventDefinition as mockEventDefinition } from 'fixtures/eventDefinition';
import { adminUser } from 'fixtures/users';
import { asMock } from 'helpers/mocking';
import useCurrentUser from 'hooks/useCurrentUser';
import { useGetEventDefinition } from 'components/event-definitions/hooks/useEventDefinitions';
import useGetPermissionsByScope from 'hooks/useScopePermissions';

import ViewEventDefinitionPage from './ViewEventDefinitionPage';

Expand All @@ -41,18 +43,12 @@ jest.mock('react-router-dom', () => ({
}));

jest.mock('hooks/useCurrentUser');
jest.mock('components/event-definitions/hooks/useEventDefinitions');
jest.mock('hooks/useScopePermissions');

jest.mock('stores/event-definitions/EventDefinitionsStore', () => ({
EventDefinitionsActions: {
get: mockAction(
jest.fn(() =>
Promise.resolve({
event_definition: mockEventDefinition,
context: { scheduler: { is_scheduled: true } },
is_mutable: true,
}),
),
),
copy: mockAction(jest.fn(() => Promise.resolve({ id: 'new-id' }))),
},
}));

Expand All @@ -71,6 +67,19 @@ jest.mock('hooks/usePluginEntities');
describe('<ViewEventDefinitionPage />', () => {
beforeEach(() => {
asMock(useCurrentUser).mockReturnValue(defaultUser);
asMock(useGetEventDefinition).mockReturnValue({
data: {
eventDefinition: mockEventDefinition,
context: { scheduler: { is_scheduled: true } },
is_mutable: true,
},
isFetching: false,
});
asMock(useGetPermissionsByScope).mockReturnValue({
loadingScopePermissions: false,
scopePermissions: { is_mutable: true, is_deletable: true },
checkPermissions: () => true,
});
asMock(usePluginEntities).mockImplementation(
(entityKey) =>
({
Expand All @@ -90,7 +99,7 @@ describe('<ViewEventDefinitionPage />', () => {
it('should display the event definition page', async () => {
render(<ViewEventDefinitionPage />);

await screen.findByText(/View Event Definition/);
await screen.findByText(/View "Event Definition 1" Event Definition/);
});

it('should display event details when permitted', async () => {
Expand Down
Loading
Loading