Skip to content

Commit 0dfb2c4

Browse files
Aaron Caldwellchrisronline
authored andcommitted
[Maps] Add 'crossed' & 'exited' events to tracking alert (elastic#82463)
1 parent cd07732 commit 0dfb2c4

File tree

4 files changed

+85
-27
lines changed

4 files changed

+85
-27
lines changed

x-pack/plugins/stack_alerts/public/alert_types/geo_threshold/query_builder/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ export const GeoThresholdAlertTypeExpression: React.FunctionComponent<AlertTypeP
326326
}
327327
fullWidth
328328
onChange={(e) => setAlertParams('trackingEvent', e.target.value)}
329-
options={[conditionOptions[0]]} // TODO: Make all options avab. before merge
329+
options={conditionOptions}
330330
/>
331331
</div>
332332
</EuiFormRow>

x-pack/plugins/stack_alerts/public/alert_types/geo_threshold/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Query } from '../../../../../../src/plugins/data/common';
99
export enum TrackingEvent {
1010
entered = 'entered',
1111
exited = 'exited',
12+
crossed = 'crossed',
1213
}
1314

1415
export interface GeoThresholdAlertParams {

x-pack/plugins/stack_alerts/server/alert_types/geo_threshold/geo_threshold.ts

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,14 @@ export function getMovedEntities(
144144
[]
145145
)
146146
// Do not track entries to or exits from 'other'
147-
.filter((entityMovementDescriptor: EntityMovementDescriptor) =>
148-
trackingEvent === 'entered'
149-
? entityMovementDescriptor.currLocation.shapeId !== OTHER_CATEGORY
150-
: entityMovementDescriptor.prevLocation.shapeId !== OTHER_CATEGORY
151-
)
147+
.filter((entityMovementDescriptor: EntityMovementDescriptor) => {
148+
if (trackingEvent !== 'crossed') {
149+
return trackingEvent === 'entered'
150+
? entityMovementDescriptor.currLocation.shapeId !== OTHER_CATEGORY
151+
: entityMovementDescriptor.prevLocation.shapeId !== OTHER_CATEGORY;
152+
}
153+
return true;
154+
})
152155
);
153156
}
154157

@@ -254,27 +257,36 @@ export const getGeoThresholdExecutor = (log: Logger) =>
254257
movedEntities.forEach(({ entityName, currLocation, prevLocation }) => {
255258
const toBoundaryName = shapesIdsNamesMap[currLocation.shapeId] || currLocation.shapeId;
256259
const fromBoundaryName = shapesIdsNamesMap[prevLocation.shapeId] || prevLocation.shapeId;
257-
services
258-
.alertInstanceFactory(`${entityName}-${toBoundaryName || currLocation.shapeId}`)
259-
.scheduleActions(ActionGroupId, {
260-
entityId: entityName,
261-
timeOfDetection: new Date(currIntervalEndTime).getTime(),
262-
crossingLine: `LINESTRING (${prevLocation.location[0]} ${prevLocation.location[1]}, ${currLocation.location[0]} ${currLocation.location[1]})`,
260+
let alertInstance;
261+
if (params.trackingEvent === 'entered') {
262+
alertInstance = `${entityName}-${toBoundaryName || currLocation.shapeId}`;
263+
} else if (params.trackingEvent === 'exited') {
264+
alertInstance = `${entityName}-${fromBoundaryName || prevLocation.shapeId}`;
265+
} else {
266+
// == 'crossed'
267+
alertInstance = `${entityName}-${fromBoundaryName || prevLocation.shapeId}-${
268+
toBoundaryName || currLocation.shapeId
269+
}`;
270+
}
271+
services.alertInstanceFactory(alertInstance).scheduleActions(ActionGroupId, {
272+
entityId: entityName,
273+
timeOfDetection: new Date(currIntervalEndTime).getTime(),
274+
crossingLine: `LINESTRING (${prevLocation.location[0]} ${prevLocation.location[1]}, ${currLocation.location[0]} ${currLocation.location[1]})`,
263275

264-
toEntityLocation: `POINT (${currLocation.location[0]} ${currLocation.location[1]})`,
265-
toEntityDateTime: currLocation.date,
266-
toEntityDocumentId: currLocation.docId,
276+
toEntityLocation: `POINT (${currLocation.location[0]} ${currLocation.location[1]})`,
277+
toEntityDateTime: currLocation.date,
278+
toEntityDocumentId: currLocation.docId,
267279

268-
toBoundaryId: currLocation.shapeId,
269-
toBoundaryName,
280+
toBoundaryId: currLocation.shapeId,
281+
toBoundaryName,
270282

271-
fromEntityLocation: `POINT (${prevLocation.location[0]} ${prevLocation.location[1]})`,
272-
fromEntityDateTime: prevLocation.date,
273-
fromEntityDocumentId: prevLocation.docId,
283+
fromEntityLocation: `POINT (${prevLocation.location[0]} ${prevLocation.location[1]})`,
284+
fromEntityDateTime: prevLocation.date,
285+
fromEntityDocumentId: prevLocation.docId,
274286

275-
fromBoundaryId: prevLocation.shapeId,
276-
fromBoundaryName,
277-
});
287+
fromBoundaryId: prevLocation.shapeId,
288+
fromBoundaryName,
289+
});
278290
});
279291

280292
// Combine previous results w/ current results for state of next run

x-pack/plugins/stack_alerts/server/alert_types/geo_threshold/tests/geo_threshold.test.ts

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ describe('geo_threshold', () => {
9999
});
100100

101101
describe('getMovedEntities', () => {
102-
const trackingEvent = 'entered';
103102
it('should return empty array if only movements were within same shapes', async () => {
104103
const currLocationArr = [
105104
{
@@ -133,7 +132,7 @@ describe('geo_threshold', () => {
133132
shapeLocationId: 'sameShape2',
134133
},
135134
];
136-
const movedEntities = getMovedEntities(currLocationArr, prevLocationArr, trackingEvent);
135+
const movedEntities = getMovedEntities(currLocationArr, prevLocationArr, 'entered');
137136
expect(movedEntities).toEqual([]);
138137
});
139138

@@ -170,7 +169,7 @@ describe('geo_threshold', () => {
170169
shapeLocationId: 'thisOneDidntMove',
171170
},
172171
];
173-
const movedEntities = getMovedEntities(currLocationArr, prevLocationArr, trackingEvent);
172+
const movedEntities = getMovedEntities(currLocationArr, prevLocationArr, 'entered');
174173
expect(movedEntities.length).toEqual(1);
175174
});
176175

@@ -193,7 +192,7 @@ describe('geo_threshold', () => {
193192
shapeLocationId: 'oldShapeLocation',
194193
},
195194
];
196-
const movedEntities = getMovedEntities(currLocationArr, prevLocationArr, trackingEvent);
195+
const movedEntities = getMovedEntities(currLocationArr, prevLocationArr, 'entered');
197196
expect(movedEntities).toEqual([]);
198197
});
199198

@@ -219,5 +218,51 @@ describe('geo_threshold', () => {
219218
const movedEntities = getMovedEntities(currLocationArr, prevLocationArr, 'exited');
220219
expect(movedEntities).toEqual([]);
221220
});
221+
222+
it('should not ignore "crossed" results from "other"', async () => {
223+
const currLocationArr = [
224+
{
225+
dateInShape: '2020-09-28T18:01:41.190Z',
226+
docId: 'N-ng1XQB6yyY-xQxnGSM',
227+
entityName: '936',
228+
location: [-82.8814151789993, 41.62806099653244],
229+
shapeLocationId: 'newShapeLocation',
230+
},
231+
];
232+
const prevLocationArr = [
233+
{
234+
dateInShape: '2020-08-28T18:01:41.190Z',
235+
docId: 'N-ng1XQB6yyY-xQxnGSM',
236+
entityName: '936',
237+
location: [-82.8814151789993, 40.62806099653244],
238+
shapeLocationId: OTHER_CATEGORY,
239+
},
240+
];
241+
const movedEntities = getMovedEntities(currLocationArr, prevLocationArr, 'crossed');
242+
expect(movedEntities.length).toEqual(1);
243+
});
244+
245+
it('should not ignore "crossed" results to "other"', async () => {
246+
const currLocationArr = [
247+
{
248+
dateInShape: '2020-08-28T18:01:41.190Z',
249+
docId: 'N-ng1XQB6yyY-xQxnGSM',
250+
entityName: '936',
251+
location: [-82.8814151789993, 40.62806099653244],
252+
shapeLocationId: OTHER_CATEGORY,
253+
},
254+
];
255+
const prevLocationArr = [
256+
{
257+
dateInShape: '2020-09-28T18:01:41.190Z',
258+
docId: 'N-ng1XQB6yyY-xQxnGSM',
259+
entityName: '936',
260+
location: [-82.8814151789993, 41.62806099653244],
261+
shapeLocationId: 'newShapeLocation',
262+
},
263+
];
264+
const movedEntities = getMovedEntities(currLocationArr, prevLocationArr, 'crossed');
265+
expect(movedEntities.length).toEqual(1);
266+
});
222267
});
223268
});

0 commit comments

Comments
 (0)