Skip to content

Commit

Permalink
Communicate to users when the detector is initializing (opensearch-pr…
Browse files Browse the repository at this point in the history
…oject#487)

* [FEATURE] Communicate to users when detector is initializing opensearch-project#227

Signed-off-by: Jovan Cvetkovic <[email protected]>

* [FEATURE] Communicate to users when detector is initializing opensearch-project#227

Signed-off-by: Jovan Cvetkovic <[email protected]>

* [FEATURE] Communicate to users when detector is initializing opensearch-project#227

Signed-off-by: Jovan Cvetkovic <[email protected]>

* [FEATURE] Communicate to users when detector is initializing opensearch-project#227

Signed-off-by: Jovan Cvetkovic <[email protected]>

* Common data store for the rules opensearch-project#474

Signed-off-by: Jovan Cvetkovic <[email protected]>

* [FEATURE] Communicate to users when detector is initializing opensearch-project#227

Signed-off-by: Jovan Cvetkovic <[email protected]>

* [FEATURE] Communicate to users when detector is initializing opensearch-project#227

Signed-off-by: Jovan Cvetkovic <[email protected]>

* [FEATURE] Communicate to users when detector is initializing opensearch-project#227

Signed-off-by: Jovan Cvetkovic <[email protected]>

* [FEATURE] Communicate to users when detector is initializing opensearch-project#227

Signed-off-by: Jovan Cvetkovic <[email protected]>

* [FEATURE] Communicate to users when detector is initializing opensearch-project#227

Signed-off-by: Jovan Cvetkovic <[email protected]>

* Communicate to users when the detector is initializing opensearch-project#487

Signed-off-by: Jovan Cvetkovic <[email protected]>

* Code review

Signed-off-by: Jovan Cvetkovic <[email protected]>

---------

Signed-off-by: Jovan Cvetkovic <[email protected]>
  • Loading branch information
jovancacvetkovic authored Mar 23, 2023
1 parent 7fcfb5a commit 068d03e
Show file tree
Hide file tree
Showing 29 changed files with 480 additions and 248 deletions.
12 changes: 0 additions & 12 deletions models/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,6 @@ export interface Rule {
detection: string;
}

export interface Detector {
id?: string;
type: string;
detector_type: string;
name: string;
enabled: boolean;
createdBy: string;
schedule: PeriodSchedule;
inputs: DetectorInput[];
triggers: AlertCondition[];
}

export interface PeriodSchedule {
period: {
interval: number;
Expand Down
101 changes: 31 additions & 70 deletions public/pages/CreateDetector/containers/CreateDetector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@ import React, { Component } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSteps } from '@elastic/eui';
import DefineDetector from '../components/DefineDetector/containers/DefineDetector';
import { createDetectorSteps } from '../utils/constants';
import { createDetectorSteps, PENDING_DETECTOR_ID } from '../utils/constants';
import {
BREADCRUMBS,
EMPTY_DEFAULT_DETECTOR,
OS_NOTIFICATION_PLUGIN,
PLUGIN_NAME,
ROUTES,
logTypesWithDashboards,
pendingDashboardCreations,
} from '../../../utils/constants';
import ConfigureFieldMapping from '../components/ConfigureFieldMapping';
import ConfigureAlerts from '../components/ConfigureAlerts';
import { Detector, FieldMapping } from '../../../../models/interfaces';
import { FieldMapping } from '../../../../models/interfaces';
import { EuiContainedStepProps } from '@elastic/eui/src/components/steps/steps';
import { CoreServicesContext } from '../../../components/core_services';
import { DetectorCreationStep } from '../models/types';
Expand All @@ -32,20 +30,18 @@ import {
RuleItemInfo,
} from '../components/DefineDetector/components/DetectionRules/types/interfaces';
import { NotificationsStart } from 'opensearch-dashboards/public';
import {
errorNotificationToast,
getPlugins,
successNotificationToast,
} from '../../../utils/helpers';
import { getPlugins } from '../../../utils/helpers';
import { Detector } from '../../../../types';
import { DataStore } from '../../../store/DataStore';

interface CreateDetectorProps extends RouteComponentProps {
isEdit: boolean;
services: BrowserServices;
history: RouteComponentProps['history'];
notifications: NotificationsStart;
}

interface CreateDetectorState {
export interface CreateDetectorState {
currentStep: DetectorCreationStep;
detector: Detector;
fieldMappings: FieldMapping[];
Expand All @@ -61,6 +57,11 @@ export default class CreateDetector extends Component<CreateDetectorProps, Creat

constructor(props: CreateDetectorProps) {
super(props);

let detectorState = {}; // if there is detector state in history, then use it to populate all the fields
const historyState = this.props.history.location.state as any;
if (historyState) detectorState = historyState.detectorState;

this.state = {
currentStep: DetectorCreationStep.DEFINE_DETECTOR,
detector: EMPTY_DEFAULT_DETECTOR,
Expand All @@ -75,6 +76,7 @@ export default class CreateDetector extends Component<CreateDetectorProps, Creat
rulesState: { page: { index: 0 }, allRules: [] },
plugins: [],
loadingRules: false,
...detectorState,
};
}

Expand Down Expand Up @@ -106,73 +108,32 @@ export default class CreateDetector extends Component<CreateDetectorProps, Creat
this.setState({ fieldMappings });
};

onCreateClick = async () => {
onCreateClick = () => {
const { creatingDetector, detector, fieldMappings } = this.state;
if (creatingDetector) {
return;
}

this.setState({ creatingDetector: true });
try {
const createMappingsRes = await this.props.services.fieldMappingService.createMappings(
detector.inputs[0].detector_input.indices[0],
detector.detector_type,
fieldMappings
);
if (!createMappingsRes.ok) {
errorNotificationToast(
this.props.notifications,
'create',
'detector',
'Double check the field mappings and try again.'
);
} else {
const createDetectorRes = await this.props.services.detectorsService.createDetector(
detector
);
if (createDetectorRes.ok) {
successNotificationToast(
this.props.notifications,
'created',
`detector, "${detector.name}"`
);
// Create the dashboard
let createDashboardPromise;
if (logTypesWithDashboards.has(detector.detector_type)) {
createDashboardPromise = this.createDashboard(
detector.name,
detector.detector_type,
createDetectorRes.response._id,
detector.inputs[0].detector_input.indices
);
pendingDashboardCreations[createDetectorRes.response._id] = createDashboardPromise;
}
this.props.history.push(`${ROUTES.DETECTOR_DETAILS}/${createDetectorRes.response._id}`);
} else {
errorNotificationToast(
this.props.notifications,
'create',
'detector',
createDetectorRes.error
);
}
}
} catch (error: any) {
errorNotificationToast(this.props.notifications, 'create', 'detector', error);
}

const fieldsMappingPromise = this.props.services.fieldMappingService.createMappings(
detector.inputs[0].detector_input.indices[0],
detector.detector_type,
fieldMappings
);

const createDetectorPromise = this.props.services.detectorsService.createDetector(detector);

// set detector pending state, this will be used in detector details page
DataStore.detectors.setPendingState({
pendingRequests: [fieldsMappingPromise, createDetectorPromise],
detectorState: { ...this.state },
});

this.setState({ creatingDetector: false });
};

private createDashboard = (
detectorName: string,
logType: string,
detectorId: string,
inputIndices: string[]
) => {
return this.props.services.savedObjectsService
.createSavedObject(detectorName, logType, detectorId, inputIndices)
.catch((error: any) => {
console.error(error);
});
// navigate to detector details
this.props.history.push(`${ROUTES.DETECTOR_DETAILS}/${PENDING_DETECTOR_ID}`);
};

onNextClick = () => {
Expand Down
2 changes: 2 additions & 0 deletions public/pages/CreateDetector/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ export const createDetectorSteps: Record<DetectorCreationStep, DetectorCreationS
step: 4,
},
};

export const PENDING_DETECTOR_ID = 'pending_detector_id';
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import React from 'react';
import { ContentPanel } from '../../../../components/ContentPanel';
import { createTextDetailsGroup, parseSchedule } from '../../../../utils/helpers';
import moment from 'moment';
import { Detector } from '../../../../../models/interfaces';
import { DEFAULT_EMPTY_DATA } from '../../../../utils/constants';
import { Detector } from '../../../../../types';

export interface DetectorBasicDetailsViewProps {
detector: Detector;
Expand All @@ -18,6 +18,7 @@ export interface DetectorBasicDetailsViewProps {
enabled_time?: number;
last_update_time?: number;
onEditClicked: () => void;
isEditable: boolean;
}

export const DetectorBasicDetailsView: React.FC<DetectorBasicDetailsViewProps> = ({
Expand All @@ -28,6 +29,7 @@ export const DetectorBasicDetailsView: React.FC<DetectorBasicDetailsViewProps> =
children,
dashboardId,
onEditClicked,
isEditable = true,
}) => {
const { name, detector_type, inputs, schedule } = detector;
const detectorSchedule = parseSchedule(schedule);
Expand Down Expand Up @@ -55,11 +57,15 @@ export const DetectorBasicDetailsView: React.FC<DetectorBasicDetailsViewProps> =
return (
<ContentPanel
title={'Detector details'}
actions={[
<EuiButton onClick={onEditClicked} data-test-subj={'edit-detector-basic-details'}>
Edit
</EuiButton>,
]}
actions={
isEditable
? [
<EuiButton onClick={onEditClicked} data-test-subj={'edit-detector-basic-details'}>
Edit
</EuiButton>,
]
: null
}
>
<EuiSpacer size={'l'} />
{createTextDetailsGroup(firstTextDetailsGroupEntries, 4)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@ import React, { useContext, useEffect, useState } from 'react';
import { EuiAccordion, EuiButton, EuiSpacer, EuiText } from '@elastic/eui';
import { RuleItem } from '../../../CreateDetector/components/DefineDetector/components/DetectionRules/types/interfaces';
import { ServicesContext } from '../../../../services';
import { Detector } from '../../../../../models/interfaces';
import { RuleInfo } from '../../../../../server/models/interfaces';
import { errorNotificationToast, translateToRuleItems } from '../../../../utils/helpers';
import { NotificationsStart } from 'opensearch-dashboards/public';
import { RulesTable } from '../../../Rules/components/RulesTable/RulesTable';
import { RuleTableItem } from '../../../Rules/utils/helpers';
import { RuleViewerFlyout } from '../../../Rules/components/RuleViewerFlyout/RuleViewerFlyout';
import { DataStore } from '../../../../store/DataStore';
import { Detector } from '../../../../../types';

export interface DetectorRulesViewProps {
detector: Detector;
rulesCanFold?: boolean;
onEditClicked: (enabledRules: RuleItem[], allRuleItems: RuleItem[]) => void;
notifications: NotificationsStart;
isEditable: boolean;
}

const mapRuleItemToRuleTableItem = (ruleItem: RuleItem): RuleTableItem => {
Expand Down Expand Up @@ -49,14 +50,16 @@ export const DetectorRulesView: React.FC<DetectorRulesViewProps> = (props) => {
const [enabledRuleItems, setEnabledRuleItems] = useState<RuleItem[]>([]);
const [allRuleItems, setAllRuleItems] = useState<RuleItem[]>([]);
const [loading, setLoading] = useState(false);
const actions = [
<EuiButton
onClick={() => props.onEditClicked(enabledRuleItems, allRuleItems)}
data-test-subj={'edit-detector-rules'}
>
Edit
</EuiButton>,
];
const actions = props.isEditable
? [
<EuiButton
onClick={() => props.onEditClicked(enabledRuleItems, allRuleItems)}
data-test-subj={'edit-detector-rules'}
>
Edit
</EuiButton>,
]
: null;
const services = useContext(ServicesContext);

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ exports[`<DetectorRulesView /> spec renders the component 1`] = `
"type": "detector",
}
}
isEditable={true}
notifications={
Object {
"toasts": Object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ import React, { useCallback, useContext, useEffect, useMemo, useState } from 're
import { EuiBasicTableColumn, EuiButton, EuiInMemoryTable } from '@elastic/eui';
import { FieldMappingsTableItem } from '../../../CreateDetector/models/interfaces';
import { ServicesContext } from '../../../../services';
import { Detector, FieldMapping } from '../../../../../models/interfaces';
import { FieldMapping } from '../../../../../models/interfaces';
import { errorNotificationToast } from '../../../../utils/helpers';
import { NotificationsStart } from 'opensearch-dashboards/public';
import { Detector } from '../../../../../types';

export interface FieldMappingsViewProps {
detector: Detector;
existingMappings?: FieldMapping[];
editFieldMappings: () => void;
notifications: NotificationsStart;
isEditable: boolean;
}

const columns: EuiBasicTableColumn<FieldMappingsTableItem>[] = [
Expand All @@ -36,13 +38,17 @@ export const FieldMappingsView: React.FC<FieldMappingsViewProps> = ({
existingMappings,
editFieldMappings,
notifications,
isEditable = true,
}) => {
const actions = useMemo(
() => [
<EuiButton onClick={editFieldMappings} data-test-subj={'edit-detector-field-mappings'}>
Edit
</EuiButton>,
],
() =>
isEditable
? [
<EuiButton onClick={editFieldMappings} data-test-subj={'edit-detector-field-mappings'}>
Edit
</EuiButton>,
]
: null,
[]
);
const [fieldMappingItems, setFieldMappingItems] = useState<FieldMappingsTableItem[]>([]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { Detector, PeriodSchedule } from '../../../../../models/interfaces';
import { PeriodSchedule } from '../../../../../models/interfaces';
import React, { useContext, useEffect, useState } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import DetectorBasicDetailsForm from '../../../CreateDetector/components/DefineDetector/components/DetectorDetails';
Expand All @@ -25,6 +25,7 @@ import { ServerResponse } from '../../../../../server/models/types';
import { NotificationsStart } from 'opensearch-dashboards/public';
import { errorNotificationToast, successNotificationToast } from '../../../../utils/helpers';
import { CoreServicesContext } from '../../../../components/core_services';
import { Detector } from '../../../../../types';

export interface UpdateDetectorBasicDetailsProps
extends RouteComponentProps<any, any, { detectorHit: DetectorHit }> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import React, { Component } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle, EuiText } from '@elastic/eui';
import { Detector, FieldMapping } from '../../../../../models/interfaces';
import { FieldMapping } from '../../../../../models/interfaces';
import FieldMappingService from '../../../../services/FieldMappingService';
import { DetectorHit, SearchDetectorsResponse } from '../../../../../server/models/interfaces';
import { BREADCRUMBS, EMPTY_DEFAULT_DETECTOR, ROUTES } from '../../../../utils/constants';
Expand All @@ -16,6 +16,7 @@ import { NotificationsStart } from 'opensearch-dashboards/public';
import { errorNotificationToast, successNotificationToast } from '../../../../utils/helpers';
import EditFieldMappings from '../../containers/FieldMappings/EditFieldMapping';
import { CoreServicesContext } from '../../../../components/core_services';
import { Detector } from '../../../../../types';

export interface UpdateFieldMappingsProps
extends RouteComponentProps<any, any, { detectorHit: DetectorHit }> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
import React, { useCallback, useContext, useEffect, useState } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { RuleItem } from '../../../CreateDetector/components/DefineDetector/components/DetectionRules/types/interfaces';
import { Detector } from '../../../../../models/interfaces';
import { DetectionRulesTable } from '../../../CreateDetector/components/DefineDetector/components/DetectionRules/DetectionRulesTable';
import { BREADCRUMBS, EMPTY_DEFAULT_DETECTOR, ROUTES } from '../../../../utils/constants';
import { ServicesContext } from '../../../../services';
Expand All @@ -24,6 +23,7 @@ import { RuleTableItem } from '../../../Rules/utils/helpers';
import { RuleViewerFlyout } from '../../../Rules/components/RuleViewerFlyout/RuleViewerFlyout';
import { ContentPanel } from '../../../../components/ContentPanel';
import { DataStore } from '../../../../store/DataStore';
import { Detector } from '../../../../../types';

export interface UpdateDetectorRulesProps
extends RouteComponentProps<
Expand Down
Loading

0 comments on commit 068d03e

Please sign in to comment.