Skip to content

Commit

Permalink
added categories for log types
Browse files Browse the repository at this point in the history
Signed-off-by: Amardeepsingh Siglani <amardeep7194@gmail.com>
  • Loading branch information
amsiglan committed Oct 5, 2023
1 parent 8a7bf7d commit 0dadcb5
Show file tree
Hide file tree
Showing 16 changed files with 248 additions and 82 deletions.
21 changes: 21 additions & 0 deletions public/components/Utility/LogCategoryOption.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { EuiTitle } from '@elastic/eui';
import React, { useEffect, useRef } from 'react';

export const LogCategoryOptionView: React.FC<{ categoryName: string }> = ({ categoryName }) => {
const inputRef = useRef<HTMLHeadingElement | null>(null);

useEffect(() => {
inputRef.current?.closest('button.euiFilterSelectItem')?.setAttribute('disabled', 'true');
}, [inputRef.current]);

return (
<EuiTitle size="xxs">
<h4 ref={inputRef}>{categoryName}</h4>
</EuiTitle>
);
};
14 changes: 9 additions & 5 deletions public/pages/Correlations/containers/CreateCorrelationRule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { CoreServicesContext } from '../../../components/core_services';
import { RouteComponentProps, useParams } from 'react-router-dom';
import { validateName } from '../../../utils/validation';
import { FieldMappingService, IndexService } from '../../../services';
import { errorNotificationToast } from '../../../utils/helpers';
import { errorNotificationToast, getLogTypeOptions } from '../../../utils/helpers';

export interface CreateCorrelationRuleProps {
indexService: IndexService;
Expand Down Expand Up @@ -103,6 +103,7 @@ export const CreateCorrelationRule: React.FC<CreateCorrelationRuleProps> = (
...correlationRuleStateDefaultValue,
});
const [action, setAction] = useState<CorrelationRuleAction>('Create');
const [logTypeOptions, setLogTypeOptions] = useState<any[]>([]);

useEffect(() => {
if (props.history.location.state?.rule) {
Expand All @@ -119,6 +120,12 @@ export const CreateCorrelationRule: React.FC<CreateCorrelationRuleProps> = (
setAction('Edit');
setInitialRuleValues();
}

const setupLogTypeOptions = async () => {
const options = await getLogTypeOptions();
setLogTypeOptions(options);
};
setupLogTypeOptions();
}, []);

const submit = async (values: any) => {
Expand Down Expand Up @@ -274,10 +281,7 @@ export const CreateCorrelationRule: React.FC<CreateCorrelationRuleProps> = (
isInvalid={isInvalidInputForQuery('logType')}
placeholder="Select a log type"
data-test-subj={'rule_type_dropdown'}
options={ruleTypes.map(({ label }) => ({
value: label.toLowerCase(),
label,
}))}
options={logTypeOptions}
singleSelection={{ asPlainText: true }}
onChange={(e) => {
props.handleChange(`queries[${queryIdx}].logType`)(
Expand Down
8 changes: 2 additions & 6 deletions public/pages/Correlations/utils/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ import {
CorrelationRuleQuery,
} from '../../../../types';
import { Search } from '@opensearch-project/oui/src/eui_components/basic_table';
import { ruleTypes } from '../../Rules/utils/constants';
import { FieldClause } from '@opensearch-project/oui/src/eui_components/search_bar/query/ast';
import { formatRuleType } from '../../../utils/helpers';
import { formatRuleType, getLogTypeFilterOptions } from '../../../utils/helpers';

export const getCorrelationRulesTableColumns = (
onRuleNameClick: (rule: CorrelationRule) => void,
Expand Down Expand Up @@ -110,10 +109,7 @@ export const getCorrelationRulesTableSearchConfig = (
field: 'logTypes',
name: 'Log Types',
multiSelect: 'or',
options: ruleTypes.map(({ value, label }) => ({
value,
name: label,
})),
options: getLogTypeFilterOptions(),
},
],
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { RuleItem } from '../DetectionRules/types/interfaces';
import { ruleTypes } from '../../../../../Rules/utils/constants';
import ConfigureFieldMapping from '../../../ConfigureFieldMapping';
import { ConfigureFieldMappingProps } from '../../../ConfigureFieldMapping/containers/ConfigureFieldMapping';
import { getLogTypeOptions } from '../../../../../../utils/helpers';

interface DetectorTypeProps {
detectorType: string;
Expand All @@ -30,18 +31,23 @@ interface DetectorTypeState {
}

export default class DetectorType extends Component<DetectorTypeProps, DetectorTypeState> {
private detectorTypeOptions: { value: string; label: string }[];
private detectorTypeOptions: { value: string; label: string }[] = [];
constructor(props: DetectorTypeProps) {
super(props);

this.detectorTypeOptions = ruleTypes.map(({ label }) => ({ value: label, label }));
const detectorTypeIds = this.detectorTypeOptions.map((option) => option.value);
this.state = {
fieldTouched: false,
detectorTypeIds,
detectorTypeIds: [],
};
}

async componentDidMount(): Promise<void> {
this.detectorTypeOptions = await getLogTypeOptions();
this.setState({
detectorTypeIds: ruleTypes.map((option) => option.value),
});
}

onChange = (detectorType: string) => {
this.setState({ fieldTouched: true });
this.props.onDetectorTypeChange(detectorType);
Expand All @@ -66,7 +72,13 @@ export default class DetectorType extends Component<DetectorTypeProps, DetectorT
const { detectorType } = this.props;

return (
<ContentPanel title={'Detection'} titleSize={'m'}>
<ContentPanel
title={'Detection'}
subTitleText={
'The available detection rules are automatically populated based on your selected log type. Use the toggles to select detection rules for this detector'
}
titleSize={'m'}
>
<EuiFormRow
label={
<div>
Expand Down
8 changes: 3 additions & 5 deletions public/pages/Detectors/containers/Detectors/Detectors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
capitalizeFirstLetter,
errorNotificationToast,
formatRuleType,
getLogTypeFilterOptions,
renderTime,
} from '../../../../utils/helpers';
import { CoreServicesContext } from '../../../../components/core_services';
Expand Down Expand Up @@ -298,11 +299,11 @@ export default class Detectors extends Component<DetectorsProps, DetectorsState>
detectorHits.map((detector) => (detector._source.enabled ? 'Active' : 'Inactive'))
),
];
const logType = [...new Set(detectorHits.map((detector) => detector._source.detector_type))];
const search = {
box: {
placeholder: 'Search threat detectors',
schema: true,
incremental: true,
},
filters: [
{
Expand All @@ -319,10 +320,7 @@ export default class Detectors extends Component<DetectorsProps, DetectorsState>
type: 'field_value_selection',
field: 'logType',
name: 'Log type',
options: logType.map((logType) => ({
value: logType,
name: formatRuleType(logType),
})),
options: getLogTypeFilterOptions(),
multiSelect: 'or',
} as FieldValueSelectionFilterConfigType,
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,7 @@ exports[`<Detectors /> spec renders the component 1`] = `
search={
Object {
"box": Object {
"incremental": true,
"placeholder": "Search threat detectors",
"schema": true,
},
Expand All @@ -598,12 +599,7 @@ exports[`<Detectors /> spec renders the component 1`] = `
"field": "logType",
"multiSelect": "or",
"name": "Log type",
"options": Array [
Object {
"name": "-",
"value": "detector_type",
},
],
"options": Array [],
"type": "field_value_selection",
},
],
Expand All @@ -628,6 +624,7 @@ exports[`<Detectors /> spec renders the component 1`] = `
<EuiSearchBar
box={
Object {
"incremental": true,
"placeholder": "Search threat detectors",
"schema": Object {
"fields": Object {
Expand Down Expand Up @@ -669,12 +666,7 @@ exports[`<Detectors /> spec renders the component 1`] = `
"field": "logType",
"multiSelect": "or",
"name": "Log type",
"options": Array [
Object {
"name": "-",
"value": "detector_type",
},
],
"options": Array [],
"type": "field_value_selection",
},
]
Expand All @@ -697,18 +689,18 @@ exports[`<Detectors /> spec renders the component 1`] = `
className="euiFlexItem euiSearchBar__searchHolder"
>
<EuiSearchBox
incremental={false}
incremental={true}
isInvalid={false}
onSearch={[Function]}
placeholder="Search threat detectors"
query=""
>
<EuiFieldSearch
aria-label="This is a search bar. After typing your query, hit enter to filter the results lower in the page."
aria-label="This is a search bar. As you type, the results lower in the page will automatically filter."
compressed={false}
defaultValue=""
fullWidth={true}
incremental={false}
incremental={true}
inputRef={[Function]}
isClearable={true}
isInvalid={false}
Expand All @@ -732,7 +724,7 @@ exports[`<Detectors /> spec renders the component 1`] = `
isInvalid={false}
>
<input
aria-label="This is a search bar. After typing your query, hit enter to filter the results lower in the page."
aria-label="This is a search bar. As you type, the results lower in the page will automatically filter."
className="euiFieldSearch euiFieldSearch--fullWidth"
defaultValue=""
onKeyUp={[Function]}
Expand Down Expand Up @@ -800,12 +792,7 @@ exports[`<Detectors /> spec renders the component 1`] = `
"field": "logType",
"multiSelect": "or",
"name": "Log type",
"options": Array [
Object {
"name": "-",
"value": "detector_type",
},
],
"options": Array [],
"type": "field_value_selection",
},
]
Expand Down Expand Up @@ -975,12 +962,7 @@ exports[`<Detectors /> spec renders the component 1`] = `
"field": "logType",
"multiSelect": "or",
"name": "Log type",
"options": Array [
Object {
"name": "-",
"value": "detector_type",
},
],
"options": Array [],
"type": "field_value_selection",
}
}
Expand Down
36 changes: 31 additions & 5 deletions public/pages/LogTypes/components/LogTypeForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ import {
EuiFlexItem,
EuiFormRow,
EuiSpacer,
EuiSuperSelect,
EuiTextArea,
} from '@elastic/eui';
import { LogTypeItem } from '../../../../types';
import React from 'react';
import { LOG_TYPE_NAME_REGEX, validateName } from '../../../utils/validation';
import { NotificationsStart } from 'opensearch-dashboards/public';
import { useState } from 'react';
import { logTypeCategoryOptions } from '../../../utils/constants';

export interface LogTypeFormProps {
logTypeDetails: LogTypeItem;
Expand All @@ -40,17 +42,21 @@ export const LogTypeForm: React.FC<LogTypeFormProps> = ({
onConfirm,
}) => {
const [nameError, setNameError] = useState('');
const [categoryError, setCategoryError] = useState('');
const [categoryTouched, setCategoryTouched] = useState(false);

const updateErrors = (details = logTypeDetails) => {
const updateErrors = (details: LogTypeItem, onSubmit = false) => {
const nameInvalid = !validateName(details.name, LOG_TYPE_NAME_REGEX, false /* shouldTrim */);
const categoryInvalid = (categoryTouched || onSubmit) && !details.category;
setNameError(nameInvalid ? 'Invalid name' : '');
setCategoryError(categoryInvalid ? 'Select category to assign' : '');

return { nameInvalid };
return { nameInvalid, categoryInvalid };
};
const onConfirmClicked = () => {
const { nameInvalid } = updateErrors();
const { nameInvalid, categoryInvalid } = updateErrors(logTypeDetails, true);

if (nameInvalid) {
if (nameInvalid || categoryInvalid) {
notifications?.toasts.addDanger({
title: `Failed to ${confirmButtonText.toLowerCase()}`,
text: `Fix the marked errors.`,
Expand Down Expand Up @@ -83,7 +89,6 @@ export const LogTypeForm: React.FC<LogTypeFormProps> = ({
setLogTypeDetails(newLogType);
updateErrors(newLogType);
}}
placeholder="Enter name for the log type"
readOnly={!isEditMode}
disabled={isEditMode && !!logTypeDetails.detectionRulesCount}
/>
Expand Down Expand Up @@ -111,6 +116,27 @@ export const LogTypeForm: React.FC<LogTypeFormProps> = ({
readOnly={!isEditMode}
/>
</EuiFormRow>
<EuiSpacer />
<EuiFormRow label="Category" isInvalid={!!categoryError} error={categoryError}>
<EuiSuperSelect
options={logTypeCategoryOptions.map((option) => ({
...option,
disabled: !isEditMode || (isEditMode && !!logTypeDetails.detectionRulesCount),
}))}
valueOfSelected={logTypeDetails?.category}
onChange={(value) => {
const newLogType = {
...logTypeDetails,
category: value,
};
setCategoryTouched(true);
setLogTypeDetails(newLogType);
updateErrors(newLogType);
}}
hasDividers
itemLayoutAlign="top"
></EuiSuperSelect>
</EuiFormRow>
{isEditMode ? (
<EuiBottomBar>
<EuiFlexGroup gutterSize="s" justifyContent="flexEnd">
Expand Down
1 change: 1 addition & 0 deletions public/pages/LogTypes/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ export const defaultLogType: LogTypeBase = {
description: '',
source: 'Custom',
tags: null,
category: '',
};
17 changes: 17 additions & 0 deletions public/pages/LogTypes/utils/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { LogType } from '../../../../types';
import { capitalize } from 'lodash';
import { Search } from '@opensearch-project/oui/src/eui_components/basic_table';
import { ruleSource } from '../../Rules/utils/constants';
import { logTypesByCategories } from '../../../utils/constants';

export const getLogTypesTableColumns = (
showDetails: (id: string) => void,
Expand All @@ -27,6 +28,11 @@ export const getLogTypesTableColumns = (
name: 'Description',
truncateText: false,
},
{
field: 'category',
name: 'Category',
truncateText: false,
},
{
field: 'source',
name: 'Source',
Expand Down Expand Up @@ -60,6 +66,17 @@ export const getLogTypesTableSearchConfig = (): Search => {
schema: true,
},
filters: [
{
type: 'field_value_selection',
field: 'category',
name: 'Category',
multiSelect: 'or',
options: Object.keys(logTypesByCategories)
.map((category) => ({
value: category,
}))
.sort((a, b) => (a.value < b.value ? -1 : a.value > b.value ? 1 : 0)),
},
{
type: 'field_value_selection',
field: 'source',
Expand Down
Loading

0 comments on commit 0dadcb5

Please sign in to comment.