Skip to content

Commit

Permalink
Unit tests for public components opensearch-project#383
Browse files Browse the repository at this point in the history
[BUG] Detector Edit | Custom rule are not selected on update rules opensearch-project#406

Signed-off-by: Jovan Cvetkovic <[email protected]>
  • Loading branch information
jovancvetkovic3006 committed Feb 16, 2023
1 parent 67e02f2 commit e83a24f
Show file tree
Hide file tree
Showing 35 changed files with 1,170 additions and 3 deletions.
2 changes: 2 additions & 0 deletions public/models/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
RuleService,
NotificationsService,
IndexPatternsService,
UebaService,
} from '../services';

export interface BrowserServices {
Expand All @@ -25,6 +26,7 @@ export interface BrowserServices {
ruleService: RuleService;
notificationsService: NotificationsService;
indexPatternsService: IndexPatternsService;
uebaService: UebaService;
}

export interface RuleOptions {
Expand Down
72 changes: 72 additions & 0 deletions public/pages/Main/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ import { EditRule } from '../Rules/containers/EditRule/EditRule';
import { ImportRule } from '../Rules/containers/ImportRule/ImportRule';
import { DuplicateRule } from '../Rules/containers/DuplicateRule/DuplicateRule';
import { DateTimeFilter } from '../Overview/models/interfaces';
import { Ueba } from '../Ueba/containers/Ueba/Ueba';
import { ViewAggregators } from '../Ueba/containers/ViewAggregators/ViewAggregators';
import { ViewInferences } from '../Ueba/containers/ViewInferences/ViewInferences';
import { CreateInference } from '../Ueba/containers/CreateInference/CreateInference';
import { CreateAggregator } from '../Ueba/containers/CreateAggregator/CreateAggregator';

enum Navigation {
SecurityAnalytics = 'Security Analytics',
Expand All @@ -43,6 +48,7 @@ enum Navigation {
Rules = 'Rules',
Overview = 'Overview',
Alerts = 'Alerts',
Ueba = 'UEBA',
}

/**
Expand Down Expand Up @@ -76,6 +82,7 @@ const navItemIndexByRoute: { [route: string]: number } = {
[ROUTES.ALERTS]: 3,
[ROUTES.DETECTORS]: 4,
[ROUTES.RULES]: 5,
[ROUTES.UEBA]: 6,
};

export default class Main extends Component<MainProps, MainState> {
Expand Down Expand Up @@ -211,6 +218,15 @@ export default class Main extends Component<MainProps, MainState> {
},
isSelected: this.state.selectedNavItemIndex === 5,
},
{
name: Navigation.Ueba,
id: 6,
onClick: () => {
this.setState({ selectedNavItemIndex: 6 });
history.push(ROUTES.UEBA);
},
isSelected: this.state.selectedNavItemIndex === 6,
},
],
},
];
Expand Down Expand Up @@ -407,6 +423,62 @@ export default class Main extends Component<MainProps, MainState> {
/>
)}
/>
<Route
path={`${ROUTES.UEBA}`}
exact={true}
render={(props: RouteComponentProps<any, any, any>) => (
<Ueba
{...props}
services={services}
history={props.history}
notifications={core?.notifications}
/>
)}
/>
<Route
path={`${ROUTES.UEBA_VIEW_AGGREGATORS}`}
render={(props: RouteComponentProps<any, any, any>) => (
<ViewAggregators
{...props}
services={services}
history={props.history}
notifications={core?.notifications}
/>
)}
/>
<Route
path={`${ROUTES.UEBA_VIEW_INFERENCES}`}
render={(props: RouteComponentProps<any, any, any>) => (
<ViewInferences
{...props}
services={services}
history={props.history}
notifications={core?.notifications}
/>
)}
/>
<Route
path={`${ROUTES.UEBA_CREATE_INFERENCE}`}
render={(props: RouteComponentProps<any, any, any>) => (
<CreateInference
{...props}
services={services}
history={props.history}
notifications={core?.notifications}
/>
)}
/>
<Route
path={`${ROUTES.UEBA_CREATE_AGGREGATOR}`}
render={(props: RouteComponentProps<any, any, any>) => (
<CreateAggregator
{...props}
services={services}
history={props.history}
notifications={core?.notifications}
/>
)}
/>
<Redirect from={'/'} to={landingPage} />
</Switch>
</EuiPageBody>
Expand Down
4 changes: 2 additions & 2 deletions public/pages/Overview/components/Widgets/TableWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import { TableWidgetItem, TableWidgetProps } from '../../models/types';

export class TableWidget<T extends TableWidgetItem> extends React.Component<TableWidgetProps<T>> {
render() {
const { columns, items, loading = false } = this.props;

const { columns, items, loading = false, search = undefined } = this.props;
return (
<EuiInMemoryTable<T>
compressed
Expand All @@ -19,6 +18,7 @@ export class TableWidget<T extends TableWidgetItem> extends React.Component<Tabl
itemId={(item: T) => `${item.id}`}
pagination={{ pageSize: 10, pageSizeOptions: [10] }}
loading={loading}
search={search}
/>
);
}
Expand Down
11 changes: 10 additions & 1 deletion public/pages/Overview/models/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@

import { EuiBasicTableColumn } from '@elastic/eui';
import { AlertItem, DetectorItem, FindingItem } from './interfaces';
import { AggregatorItem, InferenceItem } from '../../Ueba/models/interfaces';
import { DocumentsItem } from '../../Ueba/containers/Ueba/Ueba';

export type TableWidgetItem = FindingItem | AlertItem | DetectorItem;
export type TableWidgetItem =
| FindingItem
| AlertItem
| DetectorItem
| AggregatorItem
| DocumentsItem
| InferenceItem;

export type TableWidgetProps<T extends TableWidgetItem> = {
columns: EuiBasicTableColumn<T>[];
items: T[];
loading?: boolean;
search?: any;
};
99 changes: 99 additions & 0 deletions public/pages/Ueba/components/RecentWidgets/RecentAggregators.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { EuiBasicTableColumn, EuiButton, EuiToolTip, EuiButtonIcon } from '@elastic/eui';
import { ROUTES } from '../../../../utils/constants';
import React, { useCallback, useContext, useEffect, useState } from 'react';
import { NotificationsStart } from 'opensearch-dashboards/public';

import { WidgetContainer } from '../../../Overview/components/Widgets/WidgetContainer';
import { TableWidget } from '../../../Overview/components/Widgets/TableWidget';
import { ServicesContext } from '../../../../services';
import { AggregatorItem } from '../../models/interfaces';
import { UebaViewModelActor } from '../../models/UebaViewModelActor';
import { BrowserServices } from '../../../../models/interfaces';

export interface AggregatorsProps {
loading?: boolean;
openFlyout: Function;
services: BrowserServices;
notifications: NotificationsStart;
}

export const RecentAggregators: React.FC<AggregatorsProps> = ({
loading = false,
openFlyout,
notifications,
}) => {
const services = useContext(ServicesContext);
const uebaViewModelActor = services && new UebaViewModelActor(services, notifications);

const [aggregatorItems, setAggregatorItems] = useState<AggregatorItem[]>([]);

const actions = React.useMemo(
() => [<EuiButton href={`#${ROUTES.UEBA_VIEW_AGGREGATORS}`}>View aggregators</EuiButton>],
[]
);

const columns: EuiBasicTableColumn<AggregatorItem>[] = [
{
field: 'name',
name: 'Name',
sortable: true,
align: 'left',
},
{
field: 'description',
name: 'Description',
sortable: false,
align: 'left',
},
{
field: 'source_index',
name: 'Source index',
sortable: true,
align: 'left',
},
{
field: 'page_size',
name: 'Page size',
sortable: true,
align: 'left',
},
{
name: 'Details',
sortable: false,
actions: [
{
render: (aggregator: AggregatorItem) => (
<EuiToolTip content={'View details'}>
<EuiButtonIcon
aria-label={'View details'}
data-test-subj={`view-details-icon`}
iconType={'expand'}
onClick={() => openFlyout(aggregator)}
/>
</EuiToolTip>
),
},
],
},
];

const getAggregators = useCallback(async () => {
const aggregators = await uebaViewModelActor?.getAggregators();
aggregators && setAggregatorItems(aggregators);
}, [services]);

useEffect(() => {
getAggregators();
}, [getAggregators]);

return (
<WidgetContainer title={'Recent aggregators'} actions={actions}>
<TableWidget columns={columns} items={aggregatorItems} loading={loading} />
</WidgetContainer>
);
};
90 changes: 90 additions & 0 deletions public/pages/Ueba/components/RecentWidgets/RecentInferences.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { EuiBasicTableColumn, EuiButton, EuiToolTip, EuiButtonIcon } from '@elastic/eui';
import { ROUTES } from '../../../../utils/constants';
import React, { useCallback, useContext, useEffect, useState } from 'react';

import { WidgetContainer } from '../../../Overview/components/Widgets/WidgetContainer';
import { TableWidget } from '../../../Overview/components/Widgets/TableWidget';
import { InferenceItem } from '../../models/interfaces';
import { ServicesContext } from '../../../../services';

export interface InferenceProps {
loading?: boolean;
openFlyout: Function;
}

export const RecentInferences: React.FC<InferenceProps> = ({ loading = false, openFlyout }) => {
const services = useContext(ServicesContext);
const [inferenceItems, setInferenceItems] = useState<InferenceItem[]>([]);

const actions = React.useMemo(
() => [<EuiButton href={`#${ROUTES.UEBA_VIEW_INFERENCES}`}>View inferences</EuiButton>],
[]
);

const columns: EuiBasicTableColumn<InferenceItem>[] = [
{
field: 'name',
name: 'Name',
sortable: true,
align: 'left',
},
{
field: 'description',
name: 'Description',
sortable: false,
align: 'left',
},
{
field: 'type',
name: 'Type',
sortable: false,
align: 'left',
},
{
field: 'schedule',
name: 'Schedule',
sortable: false,
align: 'left',
},
{
name: 'Details',
sortable: false,
actions: [
{
render: (inference) => (
<EuiToolTip content={'View details'}>
<EuiButtonIcon
aria-label={'View details'}
data-test-subj={`view-details-icon`}
iconType={'expand'}
onClick={() => openFlyout(inference)}
/>
</EuiToolTip>
),
},
],
},
];

const getInferences = useCallback(async () => {
const inferencesResponse = await services?.uebaService.getInferences();
if (inferencesResponse?.ok) {
setInferenceItems(inferencesResponse?.response.hits.hits);
}
}, [services]);

useEffect(() => {
getInferences();
}, [getInferences]);

return (
<WidgetContainer title={'Recent inference models'} actions={actions}>
<TableWidget columns={columns} items={inferenceItems} loading={loading} />
</WidgetContainer>
);
};
18 changes: 18 additions & 0 deletions public/pages/Ueba/components/Summary/Summary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { useState } from 'react';
import { EuiFlexItem } from '@elastic/eui';

import { ChartContainer } from '../../../../components/Charts/ChartContainer';
import { WidgetContainer } from '../../../Overview/components/Widgets/WidgetContainer';
export interface SummaryProps {
loading: boolean;
}
export const Summary: React.FC<SummaryProps> = () => {
const [loading, setLoading] = useState(true);
return (
<WidgetContainer title="User entity behavior analytics" actions={[]}>
<EuiFlexItem>
<ChartContainer chartViewId={'ueba-view'} loading={loading} />
</EuiFlexItem>
</WidgetContainer>
);
};
26 changes: 26 additions & 0 deletions public/pages/Ueba/containers/CreateAggregator/CreateAggregator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { useContext, useEffect } from 'react';

import { NotificationsStart } from 'opensearch-dashboards/public';
import { BrowserServices } from '../../../../models/interfaces';
import { CoreServicesContext } from '../../../../components/core_services';
import { BREADCRUMBS } from '../../../../utils/constants';
import * as H from 'history';

export interface UebaProps {
services: BrowserServices;
notifications?: NotificationsStart;
history: H.History;
}

export const CreateAggregator: React.FC<UebaProps> = (props) => {
const context = useContext(CoreServicesContext);
useEffect(() => {
context?.chrome.setBreadcrumbs([
BREADCRUMBS.SECURITY_ANALYTICS,
BREADCRUMBS.UEBA,
BREADCRUMBS.UEBA_CREATE_AGGREGATOR,
]);
});

return <>Create aggregator</>;
};
Empty file.
Loading

0 comments on commit e83a24f

Please sign in to comment.