diff --git a/public/pages/Alerts/components/AlertFlyout/AlertFlyout.tsx b/public/pages/Alerts/components/AlertFlyout/AlertFlyout.tsx index 06f45e239..1d3d26864 100644 --- a/public/pages/Alerts/components/AlertFlyout/AlertFlyout.tsx +++ b/public/pages/Alerts/components/AlertFlyout/AlertFlyout.tsx @@ -33,6 +33,7 @@ import { Detector } from '../../../../../models/interfaces'; import { parseAlertSeverityToOption } from '../../../CreateDetector/components/ConfigureAlerts/utils/helpers'; import { Finding } from '../../../Findings/models/interfaces'; import { NotificationsStart } from 'opensearch-dashboards/public'; +import { RulesViewModelActor } from '../../../Rules/models/RulesViewModelActor'; export interface AlertFlyoutProps { alertItem: AlertItem; @@ -54,9 +55,13 @@ export interface AlertFlyoutState { } export class AlertFlyout extends React.Component { + private rulesViewModelActor: RulesViewModelActor; + constructor(props: AlertFlyoutProps) { super(props); + this.rulesViewModelActor = new RulesViewModelActor(props.ruleService); + this.state = { acknowledged: props.alertItem.state === ALERT_STATE.ACKNOWLEDGED, findingItems: [], @@ -98,50 +103,22 @@ export class AlertFlyout extends React.Component { - const { notifications, ruleService } = this.props; + const { notifications } = this.props; try { const { findingItems } = this.state; const ruleIds: string[] = []; findingItems.forEach((finding) => { finding.queries.forEach((query) => ruleIds.push(query.id)); }); - const body = { - from: 0, - size: 5000, - query: { - nested: { - path: 'rule', - query: { - terms: { - _id: ruleIds, - }, - }, - }, - }, - }; if (ruleIds.length > 0) { - const prePackagedResponse = await ruleService.getRules(true, body); - const customResponse = await ruleService.getRules(false, body); + const rulesResponse = await this.rulesViewModelActor.fetchRules({ + _id: ruleIds, + }); const allRules: { [id: string]: RuleSource } = {}; - if (prePackagedResponse.ok) { - prePackagedResponse.response.hits.hits.forEach( - (hit) => (allRules[hit._id] = hit._source) - ); - } else { - errorNotificationToast( - notifications, - 'retrieve', - 'pre-packaged rules', - prePackagedResponse.error - ); - } - if (customResponse.ok) { - customResponse.response.hits.hits.forEach((hit) => (allRules[hit._id] = hit._source)); - } else { - errorNotificationToast(notifications, 'retrieve', 'custom rules', customResponse.error); - } + rulesResponse.forEach((hit) => (allRules[hit._id] = hit._source)); + this.setState({ rules: allRules }); } } catch (e: any) { diff --git a/public/pages/Findings/components/FindingDetailsFlyout.tsx b/public/pages/Findings/components/FindingDetailsFlyout.tsx index 4a5715cee..d7d6c2d56 100644 --- a/public/pages/Findings/components/FindingDetailsFlyout.tsx +++ b/public/pages/Findings/components/FindingDetailsFlyout.tsx @@ -92,6 +92,7 @@ export default class FindingDetailsFlyout extends Component< source: fullRule.source, ruleInfo: { _source: fullRule, + prePackaged: fullRule.prePackaged, } as RuleItemInfoBase, }, }); diff --git a/public/pages/Findings/containers/Findings/Findings.tsx b/public/pages/Findings/containers/Findings/Findings.tsx index 93f75103c..dfeab74b0 100644 --- a/public/pages/Findings/containers/Findings/Findings.tsx +++ b/public/pages/Findings/containers/Findings/Findings.tsx @@ -53,6 +53,7 @@ import { DetectorHit, RuleSource } from '../../../../../server/models/interfaces import { NotificationsStart } from 'opensearch-dashboards/public'; import { DateTimeFilter } from '../../../Overview/models/interfaces'; import { ChartContainer } from '../../../../components/Charts/ChartContainer'; +import { RulesViewModelActor } from '../../../Rules/models/RulesViewModelActor'; interface FindingsProps extends RouteComponentProps { detectorService: DetectorsService; @@ -98,10 +99,12 @@ export const groupByOptions = [ class Findings extends Component { static contextType = CoreServicesContext; + private rulesViewModelActor: RulesViewModelActor; constructor(props: FindingsProps) { super(props); + this.rulesViewModelActor = new RulesViewModelActor(props.ruleService); const { dateTimeFilter = { startTime: DEFAULT_DATE_RANGE.start, @@ -192,42 +195,15 @@ class Findings extends Component { }; getRules = async (ruleIds: string[]) => { - const { notifications, ruleService } = this.props; + const { notifications } = this.props; try { - const body = { - from: 0, - size: 5000, - query: { - nested: { - path: 'rule', - query: { - terms: { - _id: ruleIds, - }, - }, - }, - }, - }; - - const prePackagedResponse = await ruleService.getRules(true, body); - const customResponse = await ruleService.getRules(false, body); - - const allRules: { [id: string]: any } = {}; - if (prePackagedResponse.ok) { - prePackagedResponse.response.hits.hits.forEach((hit) => (allRules[hit._id] = hit._source)); - } else { - errorNotificationToast( - notifications, - 'retrieve', - 'pre-packaged rules', - prePackagedResponse.error - ); - } - if (customResponse.ok) { - customResponse.response.hits.hits.forEach((hit) => (allRules[hit._id] = hit._source)); - } else { - errorNotificationToast(notifications, 'retrieve', 'custom rules', customResponse.error); - } + const rulesResponse = await this.rulesViewModelActor.fetchRules({ + _id: ruleIds, + }); + + const allRules: { [id: string]: RuleSource } = {}; + rulesResponse.forEach((hit) => (allRules[hit._id] = hit._source)); + this.setState({ rules: allRules }); } catch (e) { errorNotificationToast(notifications, 'retrieve', 'rules', e); diff --git a/public/pages/Overview/utils/__snapshots__/helper.test.ts.snap b/public/pages/Overview/utils/__snapshots__/helper.test.ts.snap new file mode 100644 index 000000000..488b0cb22 --- /dev/null +++ b/public/pages/Overview/utils/__snapshots__/helper.test.ts.snap @@ -0,0 +1,452 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`helper utilities spec tests getAlertsVisualizationSpec function - snapshot test: should match alerts spec 1`] = ` +Object { + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "config": Object { + "legend": Object { + "labelColor": "#343741", + "labelFont": "\\"Inter UI\\", -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Helvetica, Arial, sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\"", + "labelFontSize": 14, + "rowPadding": 6, + "titleColor": "#1a1c21", + "titleFontSize": 14, + "titleFontWeight": 600, + "titleLineHeight": 21, + "titlePadding": 10, + }, + "view": Object { + "stroke": "transparent", + }, + }, + "data": Object { + "values": Array [], + }, + "description": "Alerts data overview", + "layer": Array [ + Object { + "encoding": Object { + "color": Object { + "field": "", + "scale": Object { + "range": Array [ + "#54B399", + "#6092C0", + "#D36086", + "#9170B8", + "#CA8EAE", + "#D6BF57", + "#B9A888", + "#DA8B45", + "#AA6556", + "#E7664C", + ], + }, + "title": "Alert severity", + }, + "opacity": Object { + "condition": Object { + "selection": "series", + "value": 1, + }, + "value": 0.2, + }, + "tooltip": Array [ + Object { + "aggregate": "sum", + "axis": Object { + "grid": true, + }, + "field": "alert", + "title": "Alerts", + "type": "quantitative", + }, + Object { + "field": "time", + "format": "%Y-%m-%d %H:%M:%S", + "timeUnit": Object { + "step": 1, + "unit": "yearmonthdatehoursminutes", + }, + "title": "Time", + "type": "temporal", + }, + Object { + "field": "", + "title": "Alert severity", + }, + ], + "x": Object { + "axis": Object { + "format": "%Y-%m-%d %H:%M", + "grid": false, + }, + "field": "time", + "scale": Object { + "domain": undefined, + }, + "timeUnit": Object { + "step": 1, + "unit": "yearmonthdatehoursminutes", + }, + "title": "", + "type": "temporal", + }, + "y": Object { + "aggregate": "sum", + "axis": Object { + "grid": true, + }, + "field": "alert", + "title": "Count", + "type": "quantitative", + }, + }, + "mark": Object { + "clip": true, + "type": "bar", + }, + "selection": Object { + "series": Object { + "bind": "legend", + "encodings": Array [ + "color", + ], + "on": "click", + "type": "multi", + }, + }, + }, + ], +} +`; + +exports[`helper utilities spec tests getFindingsVisualizationSpec function - snapshot test: should match findings spec 1`] = ` +Object { + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "config": Object { + "legend": Object { + "labelColor": "#343741", + "labelFont": "\\"Inter UI\\", -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Helvetica, Arial, sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\"", + "labelFontSize": 14, + "rowPadding": 6, + "titleColor": "#1a1c21", + "titleFontSize": 14, + "titleFontWeight": 600, + "titleLineHeight": 21, + "titlePadding": 10, + }, + "view": Object { + "stroke": "transparent", + }, + }, + "data": Object { + "values": Array [], + }, + "description": "Findings data overview", + "layer": Array [ + Object { + "encoding": Object { + "color": Object { + "field": "", + "scale": Object { + "range": Array [ + "#54B399", + "#6092C0", + "#D36086", + "#9170B8", + "#CA8EAE", + "#D6BF57", + "#B9A888", + "#DA8B45", + "#AA6556", + "#E7664C", + ], + }, + "title": "Rule severity", + }, + "opacity": Object { + "condition": Object { + "selection": "series", + "value": 1, + }, + "value": 0.2, + }, + "tooltip": Array [ + Object { + "aggregate": "sum", + "axis": Object { + "grid": true, + }, + "field": "finding", + "title": "Findings", + "type": "quantitative", + }, + Object { + "field": "time", + "format": "%Y-%m-%d %H:%M:%S", + "timeUnit": Object { + "step": 1, + "unit": "yearmonthdatehoursminutes", + }, + "title": "Time", + "type": "temporal", + }, + Object { + "field": "", + "title": "Rule severity", + }, + ], + "x": Object { + "axis": Object { + "format": "%Y-%m-%d %H:%M", + "grid": false, + }, + "field": "time", + "scale": Object { + "domain": undefined, + }, + "timeUnit": Object { + "step": 1, + "unit": "yearmonthdatehoursminutes", + }, + "title": "", + "type": "temporal", + }, + "y": Object { + "aggregate": "sum", + "axis": Object { + "grid": true, + }, + "field": "finding", + "title": "Count", + "type": "quantitative", + }, + }, + "mark": Object { + "clip": true, + "type": "bar", + }, + "selection": Object { + "series": Object { + "bind": "legend", + "encodings": Array [ + "color", + ], + "on": "click", + "type": "multi", + }, + }, + }, + ], +} +`; + +exports[`helper utilities spec tests getOverviewVisualizationSpec function - snapshot test: should match overview spec 1`] = ` +Object { + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "config": Object { + "legend": Object { + "labelColor": "#343741", + "labelFont": "\\"Inter UI\\", -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Helvetica, Arial, sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\"", + "labelFontSize": 14, + "rowPadding": 6, + "titleColor": "#1a1c21", + "titleFontSize": 14, + "titleFontWeight": 600, + "titleLineHeight": 21, + "titlePadding": 10, + }, + "view": Object { + "stroke": "transparent", + }, + }, + "data": Object { + "values": Array [], + }, + "description": "Plot showing average data with raw values in the background.", + "layer": Array [ + Object { + "encoding": Object { + "color": Object { + "scale": null, + "value": "#6092C0", + }, + "tooltip": Array [ + Object { + "aggregate": "sum", + "axis": Object { + "grid": true, + }, + "field": "finding", + "title": "Findings", + "type": "quantitative", + }, + Object { + "field": "time", + "format": "%Y-%m-%d %H:%M:%S", + "timeUnit": Object { + "step": 1, + "unit": "yearmonthdatehoursminutes", + }, + "title": "Time", + "type": "temporal", + }, + ], + "x": Object { + "axis": Object { + "format": "%Y-%m-%d %H:%M", + "grid": false, + }, + "field": "time", + "scale": Object { + "domain": undefined, + }, + "timeUnit": Object { + "step": 1, + "unit": "yearmonthdatehoursminutes", + }, + "title": "", + "type": "temporal", + }, + "y": Object { + "aggregate": "sum", + "axis": Object { + "grid": true, + }, + "field": "finding", + "title": "Count", + "type": "quantitative", + }, + }, + "mark": Object { + "clip": true, + "type": "bar", + }, + }, + Object { + "encoding": Object { + "tooltip": Array [ + Object { + "aggregate": "sum", + "axis": Object { + "grid": true, + }, + "field": "alert", + "title": "Alerts", + "type": "quantitative", + }, + Object { + "field": "time", + "format": "%Y-%m-%d %H:%M:%S", + "timeUnit": Object { + "step": 1, + "unit": "yearmonthdatehoursminutes", + }, + "title": "Time", + "type": "temporal", + }, + ], + "x": Object { + "axis": Object { + "format": "%Y-%m-%d %H:%M", + "grid": false, + }, + "band": 0.5, + "field": "time", + "scale": Object { + "domain": undefined, + }, + "timeUnit": Object { + "step": 1, + "unit": "yearmonthdatehoursminutes", + }, + "title": "", + "type": "temporal", + }, + "y": Object { + "aggregate": "sum", + "axis": Object { + "grid": true, + }, + "field": "alert", + "title": "Count", + "type": "quantitative", + }, + }, + "mark": Object { + "clip": true, + "color": "#ff0000", + "interpolate": "monotone", + "point": Object { + "color": "#ff0000", + "fill": "white", + "filled": false, + "size": 50, + }, + "type": "line", + }, + }, + ], +} +`; + +exports[`helper utilities spec tests getVisualizationSpec function - snapshot test: should match visualization spec 1`] = ` +Object { + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "config": Object { + "legend": Object { + "labelColor": "#343741", + "labelFont": "\\"Inter UI\\", -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Helvetica, Arial, sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\"", + "labelFontSize": 14, + "rowPadding": 6, + "titleColor": "#1a1c21", + "titleFontSize": 14, + "titleFontWeight": 600, + "titleLineHeight": 21, + "titlePadding": 10, + }, + "view": Object { + "stroke": "transparent", + }, + }, + "data": Object { + "values": Array [ + Object { + "xField": 1, + "yField": 1, + }, + ], + }, + "description": "Visualization", + "layer": Array [ + Object { + "encoding": Object { + "opacity": Object { + "condition": Object { + "selection": "series", + "value": 1, + }, + "value": 0.2, + }, + }, + "selection": Object { + "series": Object { + "bind": "legend", + "encodings": Array [ + "color", + ], + "on": "click", + "type": "multi", + }, + }, + "x": Object { + "field": "xField", + }, + "y": Object { + "field": "yField", + }, + }, + ], +} +`; diff --git a/public/pages/Overview/utils/helper.test.ts b/public/pages/Overview/utils/helper.test.ts index 87735bec5..f5c7f413f 100644 --- a/public/pages/Overview/utils/helper.test.ts +++ b/public/pages/Overview/utils/helper.test.ts @@ -1,11 +1,56 @@ -import { getChartTimeUnit, TimeUnits } from './helpers'; +import { + addInteractiveLegends, + DateOpts, + getAlertsVisualizationSpec, + getChartTimeUnit, + getDomainRange, + getFindingsVisualizationSpec, + getOverviewVisualizationSpec, + getTimeTooltip, + getTimeWithMinPrecision, + getVisualizationSpec, + getXAxis, + getYAxis, + legendSelectionCfg, + parseDateString, + TimeUnits, +} from './helpers'; +import _ from 'lodash'; +import dateMath from '@elastic/datemath'; +import { DEFAULT_DATE_RANGE } from '../../../utils/constants'; +import moment from 'moment'; describe('helper utilities spec', () => { + const description = 'Visualization'; + const defaultTimeUnit = { + timeUnit: { unit: 'yearmonthdatehoursminutes', step: 1 }, + dateFormat: '%Y-%m-%d %H:%M', + }; + const layer = { + x: { + field: 'xField', + }, + y: { + field: 'yField', + }, + }; + + const data = [ + { + xField: 1, + yField: 1, + }, + ]; + + const dateOpts: DateOpts = { + timeUnit: { + unit: 'yearmonthdatehoursminutes', + step: 1, + }, + dateFormat: '%Y-%m-%d %H:%M', + }; + describe('tests getChartTimeUnit function', () => { - const defaultTimeUnit = { - timeUnit: { unit: 'yearmonthdatehoursminutes', step: 1 }, - dateFormat: '%Y-%m-%d %H:%M', - }; it(' - function should return default timeUnit if fn params are invalid', () => { const timeUnits = getChartTimeUnit('', ''); expect(timeUnits.dateFormat).toBe(defaultTimeUnit.dateFormat); @@ -72,4 +117,105 @@ describe('helper utilities spec', () => { }); } }); + + describe('tests addInteractiveLegends function', () => { + const result = _.defaultsDeep(layer, legendSelectionCfg); + it(' - function should return updated layer', () => { + expect(addInteractiveLegends(layer)).toBe(result); + }); + }); + + describe('tests parseDateString function', () => { + it(' - function should return datetime in ms', () => { + const time = moment(10); + jest.spyOn(dateMath, 'parse').mockReturnValue(time); + expect(parseDateString(DEFAULT_DATE_RANGE.start)).toBe(time.milliseconds()); + }); + }); + + describe('tests getYAxis function', () => { + it(' - function should return Y axis config', () => { + const yAxisConfig = getYAxis('xField', 'Y axis title', false); + const expectedYAxisConfig = { + aggregate: 'sum', + field: 'xField', + type: 'quantitative', + title: 'Y axis title', + axis: { grid: false }, + }; + const isEqual = _.isEqual(yAxisConfig, expectedYAxisConfig); + expect(isEqual).toBe(true); + }); + }); + + describe('tests getXAxis function', () => { + it(' - function should return X axis config', () => { + const xAxisConfig = getXAxis(dateOpts, {}); + const expectedXAxisConfig = { + timeUnit: dateOpts.timeUnit, + field: 'time', + title: '', + type: 'temporal', + axis: { grid: false, format: dateOpts.dateFormat }, + scale: { + domain: dateOpts.domain, + }, + }; + const isEqual = _.isEqual(xAxisConfig, expectedXAxisConfig); + expect(isEqual).toBe(true); + }); + }); + + describe('tests getTimeTooltip function', () => { + it(' - function should return time tooltip config', () => { + const tooltip = getTimeTooltip(dateOpts); + const expectedTooltip = { + timeUnit: dateOpts.timeUnit, + field: 'time', + type: 'temporal', + title: 'Time', + format: '%Y-%m-%d %H:%M:%S', + }; + const isEqual = _.isEqual(tooltip, expectedTooltip); + expect(isEqual).toBe(true); + }); + }); + + describe('tests getVisualizationSpec function', () => { + const result = getVisualizationSpec(description, data, [layer]); + it(' - snapshot test', () => { + expect(result).toMatchSnapshot('should match visualization spec'); + }); + }); + + describe('tests getOverviewVisualizationSpec function', () => { + const result = getOverviewVisualizationSpec([], '', dateOpts); + it(' - snapshot test', () => { + expect(result).toMatchSnapshot('should match overview spec'); + }); + }); + + describe('tests getFindingsVisualizationSpec function', () => { + const result = getFindingsVisualizationSpec([], '', dateOpts); + it(' - snapshot test', () => { + expect(result).toMatchSnapshot('should match findings spec'); + }); + }); + + describe('tests getAlertsVisualizationSpec function', () => { + const result = getAlertsVisualizationSpec([], '', dateOpts); + it(' - snapshot test', () => { + expect(result).toMatchSnapshot('should match alerts spec'); + }); + }); + + describe('tests getTimeWithMinPrecision function', () => { + const result = getTimeWithMinPrecision('2022/12/01 01:01:01'); + it(' - test should be with ms and seconds eq to 0', () => { + const ms = new Date(result).getMilliseconds(); + const seconds = new Date(result).getSeconds(); + expect(ms).toBe(0); + expect(seconds).toBe(0); + }); + }); }); diff --git a/public/pages/Overview/utils/helpers.ts b/public/pages/Overview/utils/helpers.ts index d72c7a8ec..09f32a95d 100644 --- a/public/pages/Overview/utils/helpers.ts +++ b/public/pages/Overview/utils/helpers.ts @@ -29,7 +29,7 @@ export type DateOpts = { /** * Legend selection config for the chart layer */ -const legendSelectionCfg = { +export const legendSelectionCfg = { selection: { series: { type: 'multi', @@ -91,7 +91,7 @@ export const getTimeTooltip = (dateOpts: DateOpts) => ({ format: '%Y-%m-%d %H:%M:%S', }); -function getVisualizationSpec(description: string, data: any, layers: any[]): TopLevelSpec { +export function getVisualizationSpec(description: string, data: any, layers: any[]): TopLevelSpec { return { config: { view: { stroke: 'transparent' }, @@ -397,7 +397,7 @@ export function getChartTimeUnit( * Adds interactive legends to the chart layer * @param layer */ -const addInteractiveLegends = (layer: any) => _.defaultsDeep(layer, legendSelectionCfg); +export const addInteractiveLegends = (layer: any) => _.defaultsDeep(layer, legendSelectionCfg); export const getDomainRange = ( range: string[] = [DEFAULT_DATE_RANGE.start, DEFAULT_DATE_RANGE.end], diff --git a/public/pages/Rules/containers/Rules/Rules.tsx b/public/pages/Rules/containers/Rules/Rules.tsx index 843a530e2..43e6b9603 100644 --- a/public/pages/Rules/containers/Rules/Rules.tsx +++ b/public/pages/Rules/containers/Rules/Rules.tsx @@ -24,7 +24,9 @@ export interface RulesProps extends RouteComponentProps { export const Rules: React.FC = (props) => { const services = useContext(ServicesContext) as BrowserServices; const context = useContext(CoreServicesContext); - const rulesViewModelActor = useMemo(() => new RulesViewModelActor(services), [services]); + const rulesViewModelActor = useMemo(() => new RulesViewModelActor(services.ruleService), [ + services, + ]); const [allRules, setAllRules] = useState([]); const [flyoutData, setFlyoutData] = useState(undefined); const [loading, setLoading] = useState(false); diff --git a/public/pages/Rules/models/RulesViewModelActor.ts b/public/pages/Rules/models/RulesViewModelActor.ts index 01141e752..d7afaaeb8 100644 --- a/public/pages/Rules/models/RulesViewModelActor.ts +++ b/public/pages/Rules/models/RulesViewModelActor.ts @@ -5,9 +5,9 @@ import { load, safeDump } from 'js-yaml'; import { RuleInfo } from '../../../../server/models/interfaces'; -import { BrowserServices } from '../../../models/interfaces'; import { RuleItemInfoBase } from './types'; -import { ruleTypes } from "../utils/constants"; +import { RuleService } from '../../../services'; +import { ruleTypes } from '../utils/constants'; export interface RulesViewModel { allRules: RuleItemInfoBase[]; @@ -16,7 +16,7 @@ export interface RulesViewModel { export class RulesViewModelActor { private rulesViewModel: RulesViewModel; - constructor(private readonly services: BrowserServices) { + constructor(private readonly service: RuleService) { this.rulesViewModel = { allRules: [], }; @@ -26,29 +26,35 @@ export class RulesViewModelActor { return this.rulesViewModel.allRules; } - public async fetchRules(): Promise { - let prePackagedRules = await this.getRules(true); - let customRules = await this.getRules(false); + public async fetchRules(terms?: { [key: string]: string[] }): Promise { + let prePackagedRules = await this.getRules(true, terms); + let customRules = await this.getRules(false, terms); prePackagedRules = this.extractAndAddDetection(prePackagedRules); customRules = this.extractAndAddDetection(customRules); - this.rulesViewModel.allRules = customRules.concat(prePackagedRules); return this.rulesViewModel.allRules; } - private async getRules(prePackaged: boolean): Promise { - const getRulesRes = await this.services.ruleService.getRules(prePackaged, { + private async getRules( + prePackaged: boolean, + terms?: { + [key: string]: string[]; + } + ): Promise { + const getRulesRes = await this.service.getRules(prePackaged, { from: 0, size: 5000, query: { nested: { path: 'rule', query: { - terms: { - "rule.category": ruleTypes, - } + terms: terms + ? terms + : { + 'rule.category': ruleTypes, + }, }, }, }, @@ -57,6 +63,10 @@ export class RulesViewModelActor { if (getRulesRes?.ok) { return getRulesRes.response.hits.hits.map((hit) => ({ ...hit, + _source: { + ...hit._source, + prePackaged, + }, prePackaged, })); }