Skip to content

Commit

Permalink
Add delay offset
Browse files Browse the repository at this point in the history
  • Loading branch information
Aaron Caldwell committed Oct 2, 2020
1 parent e2a305f commit b9d75bd
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export const ParamsSchema = schema.object({
boundaryIndexId: schema.string({ minLength: 1 }),
boundaryGeoField: schema.string({ minLength: 1 }),
boundaryNameField: schema.maybe(schema.string({ minLength: 1 })),
delayOffsetWithUnits: schema.maybe(schema.string({ minLength: 1 })),
});

export interface GeoThresholdParams {
Expand All @@ -168,6 +169,7 @@ export interface GeoThresholdParams {
boundaryIndexId: string;
boundaryGeoField: string;
boundaryNameField?: string;
delayOffsetWithUnits?: string;
}

export function getAlertType(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,27 @@ export function getMovedEntities(
);
}

function getOffsetTime(delayOffsetWithUnits: string, oldTime: Date): Date {
const timeUnit = delayOffsetWithUnits.slice(-1);
const time = delayOffsetWithUnits.slice(0, -1);

const adjustedDate = new Date(oldTime.getTime());
if (timeUnit === 's') {
adjustedDate.setSeconds(adjustedDate.getSeconds() - time);
} else if (timeUnit === 'm') {
adjustedDate.setMinutes(adjustedDate.getMinutes() - time);
} else if (timeUnit === 'h') {
adjustedDate.setHours(adjustedDate.getHours() - time);
} else if (timeUnit === 'd') {
adjustedDate.setDate(adjustedDate.getDate() - time);
}
return adjustedDate;
}

export const getGeoThresholdExecutor = ({ logger: log }: { logger: Logger }) =>
async function ({
previousStartedAt: currIntervalStartTime,
startedAt: currIntervalEndTime,
previousStartedAt,
startedAt,
services,
params,
alertId,
Expand All @@ -171,6 +188,7 @@ export const getGeoThresholdExecutor = ({ logger: log }: { logger: Logger }) =>
boundaryIndexId: string;
boundaryGeoField: string;
boundaryNameField?: string;
delayOffsetWithUnits?: string;
};
alertId: string;
state: AlertTypeState;
Expand All @@ -189,9 +207,18 @@ export const getGeoThresholdExecutor = ({ logger: log }: { logger: Logger }) =>

const executeEsQuery = await executeEsQueryFactory(params, services, log, shapesFilters);

let currIntervalStartTime = previousStartedAt;
let currIntervalEndTime = startedAt;
if (params.delayOffsetWithUnits) {
if (currIntervalStartTime) {
currIntervalStartTime = getOffsetTime(params.delayOffsetWithUnits, currIntervalStartTime);
}
currIntervalEndTime = getOffsetTime(params.delayOffsetWithUnits, currIntervalEndTime);
}

// Start collecting data only on the first cycle
if (!currIntervalStartTime) {
log.info(`alert ${GEO_THRESHOLD_ID}:${alertId} alert initialized. Collecting data`);
log.debug(`alert ${GEO_THRESHOLD_ID}:${alertId} alert initialized. Collecting data`);
// Consider making first time window configurable?
const tempPreviousEndTime = new Date(currIntervalEndTime);
tempPreviousEndTime.setMinutes(tempPreviousEndTime.getMinutes() - 5);
Expand All @@ -204,6 +231,8 @@ export const getGeoThresholdExecutor = ({ logger: log }: { logger: Logger }) =>
params.dateField,
params.geoField
),
shapesFilters,
shapesIdsNamesMap,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ describe('alertType', () => {
boundaryIndexId: 'testIndex',
boundaryGeoField: 'testField',
boundaryNameField: 'testField',
delayOffsetWithUnits: 'testOffset',
};

expect(alertType.validate?.params?.validate(params)).toBeTruthy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,18 @@
*/

import React, { Fragment, useEffect, useState } from 'react';
import { EuiCallOut, EuiFormRow, EuiSelect, EuiSpacer, EuiTitle } from '@elastic/eui';
import {
EuiCallOut,
EuiFieldNumber,
EuiFlexGrid,
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiIconTip,
EuiSelect,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { AlertTypeParamsExpressionProps } from '../../../../../types';
Expand All @@ -16,6 +27,7 @@ import { EntityIndexExpression } from './expressions/entity_index_expression';
import { EntityByExpression } from './expressions/entity_by_expression';
import { BoundaryIndexExpression } from './expressions/boundary_index_expression';
import { IIndexPattern } from '../../../../../../../../../src/plugins/data/common/index_patterns';
import { getTimeOptions } from '../../../../../common/lib/get_time_options';

const DEFAULT_VALUES = {
TRACKING_EVENT: '',
Expand All @@ -29,13 +41,30 @@ const DEFAULT_VALUES = {
BOUNDARY_INDEX_ID: '',
BOUNDARY_GEO_FIELD: '',
BOUNDARY_NAME_FIELD: '',
DELAY_OFFSET_WITH_UNITS: '0m',
};

const conditionOptions = Object.keys(TrackingEvent).map((key) => ({
text: (TrackingEvent as any)[key],
value: (TrackingEvent as any)[key],
}));

const labelForDelayOffset = (
<>
<FormattedMessage
id="xpack.triggersActionsUI.geoThreshold.delayOffset"
defaultMessage="Delayed evaluation offset"
/>{' '}
<EuiIconTip
position="right"
type="questionInCircle"
content={i18n.translate('xpack.triggersActionsUI.geoThreshold.delayOffsetTooltip', {
defaultMessage: 'Evaluate alerts on a delayed cycle to adjust for data latency',
})}
/>
</>
);

export const GeoThresholdAlertTypeExpression: React.FunctionComponent<AlertTypeParamsExpressionProps<
GeoThresholdAlertParams,
AlertsContextValue
Expand All @@ -52,6 +81,7 @@ export const GeoThresholdAlertTypeExpression: React.FunctionComponent<AlertTypeP
boundaryIndexId,
boundaryGeoField,
boundaryNameField,
delayOffsetWithUnits,
} = alertParams;

const [indexPattern, _setIndexPattern] = useState<IIndexPattern>({
Expand Down Expand Up @@ -86,6 +116,12 @@ export const GeoThresholdAlertTypeExpression: React.FunctionComponent<AlertTypeP
}
}
};
const [delayOffset, _setDelayOffset] = useState<number>(0);
function setDelayOffset(_delayOffset: number) {
setAlertParams('delayOffsetWithUnits', `${_delayOffset}${delayOffsetUnit}`);
_setDelayOffset(_delayOffset);
}
const [delayOffsetUnit, setDelayOffsetUnit] = useState<string>('m');

const hasExpressionErrors = false;
const expressionErrorMessage = i18n.translate(
Expand All @@ -110,6 +146,7 @@ export const GeoThresholdAlertTypeExpression: React.FunctionComponent<AlertTypeP
boundaryIndexId: boundaryIndexId ?? DEFAULT_VALUES.BOUNDARY_INDEX_ID,
boundaryGeoField: boundaryGeoField ?? DEFAULT_VALUES.BOUNDARY_GEO_FIELD,
boundaryNameField: boundaryNameField ?? DEFAULT_VALUES.BOUNDARY_NAME_FIELD,
delayOffsetWithUnits: delayOffsetWithUnits ?? DEFAULT_VALUES.DELAY_OFFSET_WITH_UNITS,
});
if (!alertsContext.dataIndexPatterns) {
return;
Expand All @@ -122,6 +159,9 @@ export const GeoThresholdAlertTypeExpression: React.FunctionComponent<AlertTypeP
const _boundaryIndexPattern = await alertsContext.dataIndexPatterns.get(boundaryIndexId);
setBoundaryIndexPattern(_boundaryIndexPattern);
}
if (delayOffsetWithUnits) {
setDelayOffset(delayOffsetWithUnits.replace(/\D/g, ''));
}
};
initToDefaultParams();
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand All @@ -137,6 +177,54 @@ export const GeoThresholdAlertTypeExpression: React.FunctionComponent<AlertTypeP
</Fragment>
) : null}
<EuiSpacer size="l" />
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.triggersActionsUI.geoThreshold.selectOffset"
defaultMessage="Select offset (optional):"
/>
</h5>
</EuiTitle>
<EuiSpacer size="m" />
<EuiFlexGrid columns={2}>
<EuiFlexItem>
<EuiFormRow
fullWidth
compressed
label={labelForDelayOffset}
// isInvalid={errors.delayOffset.length > 0}
// error={errors.delayOffset}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiFieldNumber
fullWidth
min={0}
// isInvalid={errors.delayOffset.length > 0}
compressed
value={delayOffset || 0}
name="delayOffset"
onChange={(e) => {
setDelayOffset(+e.target.value);
}}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiSelect
fullWidth
compressed
value={delayOffsetUnit}
options={getTimeOptions(alertInterval ?? 1)}
onChange={(e) => {
setDelayOffsetUnit(e.target.value);
}}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGrid>
<EuiSpacer size="m" />
<EuiTitle size="xs">
<h5>
<FormattedMessage
Expand Down

0 comments on commit b9d75bd

Please sign in to comment.