mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[Custom threshold] Add group by filters to the custom threshold view in app URL (#177016)
Resolves #173713
## Summary
This PR adds group by filters to the view in the app URL for the custom
threshold rule:

I also moved some types to the common folder and adjusted them to match
the reality.
## 🧪 How to test
- Create a custom threshold rule with group by
- One with persisted data view
- One with an ad-hoc data view
- Check the view in app link in the alerts table, you should also see
the group filters there.
- Check the view in app URL from the actions, it should also include the
group filters.
This commit is contained in:
parent
bf4b70ceb4
commit
637de1dff5
33 changed files with 303 additions and 144 deletions
|
@ -37,12 +37,12 @@ export const legacyExperimentalFieldMap = {
|
|||
},
|
||||
[ALERT_GROUP_FIELD]: {
|
||||
type: 'keyword',
|
||||
array: false,
|
||||
array: true,
|
||||
required: false,
|
||||
},
|
||||
[ALERT_GROUP_VALUE]: {
|
||||
type: 'keyword',
|
||||
array: false,
|
||||
array: true,
|
||||
required: false,
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -80,8 +80,8 @@ const ObservabilityApmAlertOptional = rt.partial({
|
|||
'kibana.alert.evaluation.values': schemaStringOrNumberArray,
|
||||
'kibana.alert.group': rt.array(
|
||||
rt.partial({
|
||||
field: schemaString,
|
||||
value: schemaString,
|
||||
field: schemaStringArray,
|
||||
value: schemaStringArray,
|
||||
})
|
||||
),
|
||||
labels: schemaUnknown,
|
||||
|
|
|
@ -78,8 +78,8 @@ const ObservabilityLogsAlertOptional = rt.partial({
|
|||
'kibana.alert.evaluation.values': schemaStringOrNumberArray,
|
||||
'kibana.alert.group': rt.array(
|
||||
rt.partial({
|
||||
field: schemaString,
|
||||
value: schemaString,
|
||||
field: schemaStringArray,
|
||||
value: schemaStringArray,
|
||||
})
|
||||
),
|
||||
});
|
||||
|
|
|
@ -78,8 +78,8 @@ const ObservabilityMetricsAlertOptional = rt.partial({
|
|||
'kibana.alert.evaluation.values': schemaStringOrNumberArray,
|
||||
'kibana.alert.group': rt.array(
|
||||
rt.partial({
|
||||
field: schemaString,
|
||||
value: schemaString,
|
||||
field: schemaStringArray,
|
||||
value: schemaStringArray,
|
||||
})
|
||||
),
|
||||
});
|
||||
|
|
|
@ -77,8 +77,8 @@ const ObservabilitySloAlertOptional = rt.partial({
|
|||
'kibana.alert.evaluation.values': schemaStringOrNumberArray,
|
||||
'kibana.alert.group': rt.array(
|
||||
rt.partial({
|
||||
field: schemaString,
|
||||
value: schemaString,
|
||||
field: schemaStringArray,
|
||||
value: schemaStringArray,
|
||||
})
|
||||
),
|
||||
'slo.id': schemaString,
|
||||
|
|
|
@ -81,8 +81,8 @@ const ObservabilityUptimeAlertOptional = rt.partial({
|
|||
'kibana.alert.evaluation.values': schemaStringOrNumberArray,
|
||||
'kibana.alert.group': rt.array(
|
||||
rt.partial({
|
||||
field: schemaString,
|
||||
value: schemaString,
|
||||
field: schemaStringArray,
|
||||
value: schemaStringArray,
|
||||
})
|
||||
),
|
||||
'monitor.id': schemaString,
|
||||
|
|
|
@ -123,12 +123,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -207,12 +207,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -291,12 +291,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -375,12 +375,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -447,12 +447,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -490,12 +490,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -533,12 +533,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -660,12 +660,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -9085,12 +9085,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -9394,12 +9394,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -9493,12 +9493,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -9592,12 +9592,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -9691,12 +9691,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
@ -9796,12 +9796,12 @@ Object {
|
|||
"type": "object",
|
||||
},
|
||||
"kibana.alert.group.field": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
"kibana.alert.group.value": Object {
|
||||
"array": false,
|
||||
"array": true,
|
||||
"required": false,
|
||||
"type": "keyword",
|
||||
},
|
||||
|
|
|
@ -48,7 +48,13 @@ describe('getViewInAppUrl', () => {
|
|||
logsExplorerLocator,
|
||||
startedAt,
|
||||
endedAt,
|
||||
filter: 'mockedFilter',
|
||||
searchConfiguration: {
|
||||
index: {},
|
||||
query: {
|
||||
language: '',
|
||||
query: 'mockedFilter',
|
||||
},
|
||||
},
|
||||
dataViewId: 'mockedDataViewId',
|
||||
};
|
||||
|
||||
|
@ -56,6 +62,7 @@ describe('getViewInAppUrl', () => {
|
|||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({
|
||||
dataset: args.dataViewId,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: 'mockedFilter and mockedCountFilter',
|
||||
language: 'kuery',
|
||||
|
@ -81,6 +88,7 @@ describe('getViewInAppUrl', () => {
|
|||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: 'mockedCountFilter',
|
||||
language: 'kuery',
|
||||
|
@ -93,13 +101,20 @@ describe('getViewInAppUrl', () => {
|
|||
logsExplorerLocator,
|
||||
startedAt,
|
||||
endedAt,
|
||||
filter: 'mockedFilter',
|
||||
searchConfiguration: {
|
||||
index: {},
|
||||
query: {
|
||||
language: '',
|
||||
query: 'mockedFilter',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: 'mockedFilter',
|
||||
language: 'kuery',
|
||||
|
@ -118,6 +133,7 @@ describe('getViewInAppUrl', () => {
|
|||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: '',
|
||||
language: 'kuery',
|
||||
|
@ -148,10 +164,86 @@ describe('getViewInAppUrl', () => {
|
|||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
query: '',
|
||||
language: 'kuery',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should call getRedirectUrl with filters if group and searchConfiguration filter are provided', () => {
|
||||
const args: GetViewInAppUrlArgs = {
|
||||
metrics: [
|
||||
{
|
||||
name: 'A',
|
||||
aggType: Aggregators.COUNT,
|
||||
filter: 'mockedCountFilter',
|
||||
},
|
||||
{
|
||||
name: 'A',
|
||||
aggType: Aggregators.AVERAGE,
|
||||
field: 'mockedAvgField',
|
||||
},
|
||||
],
|
||||
logsExplorerLocator,
|
||||
startedAt,
|
||||
endedAt,
|
||||
searchConfiguration: {
|
||||
index: {},
|
||||
query: {
|
||||
language: '',
|
||||
query: 'mockedFilter',
|
||||
},
|
||||
filter: [
|
||||
{
|
||||
meta: {},
|
||||
query: {
|
||||
term: {
|
||||
field: {
|
||||
value: 'justTesting',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
field: 'host.name',
|
||||
value: 'host-1',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [
|
||||
{
|
||||
meta: {},
|
||||
query: {
|
||||
term: {
|
||||
field: {
|
||||
value: 'justTesting',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
meta: {},
|
||||
query: {
|
||||
match_phrase: {
|
||||
'host.name': 'host-1',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
query: {
|
||||
query: 'mockedFilter',
|
||||
language: 'kuery',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,31 +5,39 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util';
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
import type { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { LogsExplorerLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util';
|
||||
import type { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { getGroupFilters } from './helpers/get_group';
|
||||
import { Group, SearchConfigurationWithExtractedReferenceType } from './types';
|
||||
import type { CustomThresholdExpressionMetric } from './types';
|
||||
|
||||
export interface GetViewInAppUrlArgs {
|
||||
searchConfiguration?: SearchConfigurationWithExtractedReferenceType;
|
||||
dataViewId?: string;
|
||||
endedAt?: string;
|
||||
startedAt?: string;
|
||||
filter?: string;
|
||||
groups?: Group[];
|
||||
logsExplorerLocator?: LocatorPublic<LogsExplorerLocatorParams>;
|
||||
metrics?: CustomThresholdExpressionMetric[];
|
||||
startedAt?: string;
|
||||
}
|
||||
|
||||
export const getViewInAppUrl = ({
|
||||
dataViewId,
|
||||
endedAt,
|
||||
startedAt = new Date().toISOString(),
|
||||
filter,
|
||||
groups,
|
||||
logsExplorerLocator,
|
||||
metrics = [],
|
||||
searchConfiguration,
|
||||
startedAt = new Date().toISOString(),
|
||||
}: GetViewInAppUrlArgs) => {
|
||||
if (!logsExplorerLocator) return '';
|
||||
|
||||
const dataset = searchConfiguration?.index.title ?? dataViewId;
|
||||
const searchConfigurationQuery = searchConfiguration?.query.query;
|
||||
const searchConfigurationFilters = searchConfiguration?.filter || [];
|
||||
const groupFilters = getGroupFilters(groups);
|
||||
const timeRange: TimeRange | undefined = getPaddedAlertTimeRange(startedAt, endedAt);
|
||||
timeRange.to = endedAt ? timeRange.to : 'now';
|
||||
|
||||
|
@ -39,17 +47,18 @@ export const getViewInAppUrl = ({
|
|||
};
|
||||
const isOneCountConditionWithFilter =
|
||||
metrics.length === 1 && metrics[0].aggType === 'count' && metrics[0].filter;
|
||||
if (filter && isOneCountConditionWithFilter) {
|
||||
query.query = `${filter} and ${metrics[0].filter}`;
|
||||
if (searchConfigurationQuery && isOneCountConditionWithFilter) {
|
||||
query.query = `${searchConfigurationQuery} and ${metrics[0].filter}`;
|
||||
} else if (isOneCountConditionWithFilter) {
|
||||
query.query = metrics[0].filter!;
|
||||
} else if (filter) {
|
||||
query.query = filter;
|
||||
} else if (searchConfigurationQuery) {
|
||||
query.query = searchConfigurationQuery;
|
||||
}
|
||||
|
||||
return logsExplorerLocator?.getRedirectUrl({
|
||||
dataset: dataViewId,
|
||||
dataset,
|
||||
timeRange,
|
||||
query,
|
||||
filters: [...searchConfigurationFilters, ...groupFilters],
|
||||
});
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { getGroupQueries, getGroupFilters } from './get_group';
|
||||
import { getGroupQueries, getGroupFilters, getGroups } from './get_group';
|
||||
|
||||
describe('getGroup', () => {
|
||||
describe('getGroupQueries', () => {
|
||||
|
@ -16,8 +16,8 @@ describe('getGroup', () => {
|
|||
];
|
||||
|
||||
expect(getGroupQueries(groups)).toEqual([
|
||||
{ term: { 'container.id': { value: 'container-0' } } },
|
||||
{ term: { 'host.name': { value: 'host-0' } } },
|
||||
{ match_phrase: { 'container.id': 'container-0' } },
|
||||
{ match_phrase: { 'host.name': 'host-0' } },
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -29,8 +29,8 @@ describe('getGroup', () => {
|
|||
const fieldName = 'custom.field';
|
||||
|
||||
expect(getGroupQueries(groups, fieldName)).toEqual([
|
||||
{ term: { 'custom.field': { value: 'container-0' } } },
|
||||
{ term: { 'custom.field': { value: 'host-0' } } },
|
||||
{ match_phrase: { 'custom.field': 'container-0' } },
|
||||
{ match_phrase: { 'custom.field': 'host-0' } },
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -51,11 +51,11 @@ describe('getGroup', () => {
|
|||
expect(getGroupFilters(groups)).toEqual([
|
||||
{
|
||||
meta: {},
|
||||
query: { term: { 'container.id': { value: 'container-0' } } },
|
||||
query: { match_phrase: { 'container.id': 'container-0' } },
|
||||
},
|
||||
{
|
||||
meta: {},
|
||||
query: { term: { 'host.name': { value: 'host-0' } } },
|
||||
query: { match_phrase: { 'host.name': 'host-0' } },
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
@ -70,11 +70,11 @@ describe('getGroup', () => {
|
|||
expect(getGroupFilters(groups, fieldName)).toEqual([
|
||||
{
|
||||
meta: {},
|
||||
query: { term: { 'custom.field': { value: 'container-0' } } },
|
||||
query: { match_phrase: { 'custom.field': 'container-0' } },
|
||||
},
|
||||
{
|
||||
meta: {},
|
||||
query: { term: { 'custom.field': { value: 'host-0' } } },
|
||||
query: { match_phrase: { 'custom.field': 'host-0' } },
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
@ -85,4 +85,21 @@ describe('getGroup', () => {
|
|||
expect(getGroupFilters(groups)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGroups', () => {
|
||||
it('should generate correct filter with default field name', () => {
|
||||
const fields = ['container.id', 'host.name'];
|
||||
const values = ['container-0', 'host-0'];
|
||||
const groups = [
|
||||
{ field: 'container.id', value: 'container-0' },
|
||||
{ field: 'host.name', value: 'host-0' },
|
||||
];
|
||||
|
||||
expect(getGroups(fields, values)).toEqual(groups);
|
||||
});
|
||||
|
||||
it('should return empty array if fields and values are empty', () => {
|
||||
expect(getGroups([], [])).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -22,10 +22,8 @@ export const getGroupQueries = (
|
|||
return (
|
||||
(groups &&
|
||||
groups.map((group) => ({
|
||||
term: {
|
||||
[groupFieldName || group.field]: {
|
||||
value: group.value,
|
||||
},
|
||||
match_phrase: {
|
||||
[groupFieldName || group.field]: group.value,
|
||||
},
|
||||
}))) ||
|
||||
[]
|
||||
|
@ -35,3 +33,10 @@ export const getGroupQueries = (
|
|||
export const getGroupFilters = (groups?: Group[], groupFieldName?: string): Filter[] => {
|
||||
return getGroupQueries(groups, groupFieldName).map((query) => ({ meta: {}, query }));
|
||||
};
|
||||
|
||||
export const getGroups = (fields: string[], values: string[]): Group[] => {
|
||||
return fields.map((_, index) => ({
|
||||
field: fields[index],
|
||||
value: values[index],
|
||||
}));
|
||||
};
|
|
@ -6,7 +6,8 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { SerializedSearchSourceFields } from '@kbn/data-plugin/common';
|
||||
import { DataViewSpec, SerializedSearchSourceFields } from '@kbn/data-plugin/common';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { TimeUnitChar } from '../utils/formatters/duration';
|
||||
|
||||
export const ThresholdFormatterTypeRT = rt.keyof({
|
||||
|
@ -110,6 +111,30 @@ export enum InfraFormatterType {
|
|||
percent = 'percent',
|
||||
}
|
||||
|
||||
export interface Group {
|
||||
field: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface SearchConfigurationType {
|
||||
index: SerializedSearchSourceFields;
|
||||
query: {
|
||||
query: string;
|
||||
language: string;
|
||||
};
|
||||
filter?: Filter[];
|
||||
}
|
||||
|
||||
export interface SearchConfigurationWithExtractedReferenceType {
|
||||
// Index will be a data view spec after extracting references
|
||||
index: DataViewSpec;
|
||||
query: {
|
||||
query: string;
|
||||
language: string;
|
||||
};
|
||||
filter?: Filter[];
|
||||
}
|
||||
|
||||
// Custom threshold alert types
|
||||
|
||||
// Alert fields['kibana.alert.group] type
|
||||
|
|
|
@ -7,10 +7,8 @@ Array [
|
|||
Object {
|
||||
"meta": Object {},
|
||||
"query": Object {
|
||||
"term": Object {
|
||||
"host.name": Object {
|
||||
"value": "host-1",
|
||||
},
|
||||
"match_phrase": Object {
|
||||
"host.name": "host-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -40,12 +40,12 @@ import moment from 'moment';
|
|||
import { AlertHistoryChart } from './alert_history';
|
||||
import { useLicense } from '../../../../hooks/use_license';
|
||||
import { useKibana } from '../../../../utils/kibana_react';
|
||||
import { getGroupFilters } from '../../../../../common/custom_threshold_rule/helpers/get_group';
|
||||
import { metricValueFormatter } from '../../../../../common/custom_threshold_rule/metric_value_formatter';
|
||||
import { AlertSummaryField } from '../../../..';
|
||||
import { AlertParams, MetricExpression } from '../../types';
|
||||
import { TIME_LABELS } from '../criterion_preview_chart/criterion_preview_chart';
|
||||
import { Threshold } from '../custom_threshold';
|
||||
import { getGroupFilters } from '../helpers/get_group';
|
||||
import { CustomThresholdRule, CustomThresholdAlert } from '../types';
|
||||
import { LogRateAnalysis } from './log_rate_analysis';
|
||||
import { Groups } from './groups';
|
||||
|
|
|
@ -25,9 +25,12 @@ import { i18n } from '@kbn/i18n';
|
|||
import { ALERT_GROUP, ALERT_GROUP_VALUE, type AlertConsumers } from '@kbn/rule-data-utils';
|
||||
import { useAlertsHistory } from '@kbn/observability-alert-details';
|
||||
import { convertTo } from '../../../../../common/utils/formatters';
|
||||
import {
|
||||
getGroupFilters,
|
||||
getGroupQueries,
|
||||
} from '../../../../../common/custom_threshold_rule/helpers/get_group';
|
||||
import { useKibana } from '../../../../utils/kibana_react';
|
||||
import { AlertParams } from '../../types';
|
||||
import { getGroupFilters, getGroupQueries } from '../helpers/get_group';
|
||||
import { RuleConditionChart } from '../rule_condition_chart/rule_condition_chart';
|
||||
import { CustomThresholdAlert, CustomThresholdRule } from '../types';
|
||||
|
||||
|
|
|
@ -117,10 +117,8 @@ Object {
|
|||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"groupByField": Object {
|
||||
"value": "groupByValue",
|
||||
},
|
||||
"match_phrase": Object {
|
||||
"groupByField": "groupByValue",
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -185,17 +183,13 @@ Object {
|
|||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"groupByField": Object {
|
||||
"value": "groupByValue",
|
||||
},
|
||||
"match_phrase": Object {
|
||||
"groupByField": "groupByValue",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"secondGroupByField": Object {
|
||||
"value": "secondGroupByValue",
|
||||
},
|
||||
"match_phrase": Object {
|
||||
"secondGroupByField": "secondGroupByValue",
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -211,10 +205,8 @@ Object {
|
|||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"term": Object {
|
||||
"groupByField": Object {
|
||||
"value": "groupByValue",
|
||||
},
|
||||
"match_phrase": Object {
|
||||
"groupByField": "groupByValue",
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -7,13 +7,15 @@
|
|||
|
||||
import { get } from 'lodash';
|
||||
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { getGroupFilters } from '../../helpers/get_group';
|
||||
import { getGroupFilters } from '../../../../../../common/custom_threshold_rule/helpers/get_group';
|
||||
import { Aggregators } from '../../../../../../common/custom_threshold_rule/types';
|
||||
import { buildEsQuery } from '../../../../../utils/build_es_query';
|
||||
import type {
|
||||
CustomThresholdExpressionMetric,
|
||||
Group,
|
||||
} from '../../../../../../common/custom_threshold_rule/types';
|
||||
import type { TopAlert } from '../../../../../typings/alerts';
|
||||
import type { CustomThresholdRuleTypeParams } from '../../../types';
|
||||
import type { CustomThresholdExpressionMetric } from '../../../../../../common/custom_threshold_rule/types';
|
||||
import type { Group } from '../../types';
|
||||
|
||||
const getKuery = (metrics: CustomThresholdExpressionMetric[], filter?: string) => {
|
||||
let query = '';
|
||||
|
|
|
@ -12,8 +12,3 @@ import { CustomThresholdAlertFields, CustomThresholdRuleTypeParams } from '../ty
|
|||
// TODO Use a generic props for app sections https://github.com/elastic/kibana/issues/152690
|
||||
export type CustomThresholdRule = Rule<CustomThresholdRuleTypeParams>;
|
||||
export type CustomThresholdAlert = TopAlert<CustomThresholdAlertFields>;
|
||||
|
||||
export interface Group {
|
||||
field: string;
|
||||
value: string;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import { lazy } from 'react';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { SerializedSearchSourceFields } from '@kbn/data-plugin/common';
|
||||
import {
|
||||
ALERT_GROUP_FIELD,
|
||||
ALERT_GROUP_VALUE,
|
||||
ALERT_REASON,
|
||||
ALERT_RULE_PARAMETERS,
|
||||
ALERT_START,
|
||||
|
@ -17,12 +19,14 @@ import {
|
|||
import type { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { LogsExplorerLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
|
||||
import type { MetricExpression } from '../components/custom_threshold/types';
|
||||
import type {
|
||||
CustomMetricExpressionParams,
|
||||
CustomThresholdExpressionMetric,
|
||||
SearchConfigurationWithExtractedReferenceType,
|
||||
} from '../../common/custom_threshold_rule/types';
|
||||
import type { MetricExpression } from '../components/custom_threshold/types';
|
||||
import { getViewInAppUrl } from '../../common/custom_threshold_rule/get_view_in_app_url';
|
||||
import { getGroups } from '../../common/custom_threshold_rule/helpers/get_group';
|
||||
import { SLO_ID_FIELD, SLO_INSTANCE_ID_FIELD } from '../../common/field_names/slo';
|
||||
import { ObservabilityRuleTypeRegistry } from './create_observability_rule_type_registry';
|
||||
import { SLO_BURN_RATE_RULE_TYPE_ID } from '../../common/constants';
|
||||
|
@ -83,7 +87,7 @@ const thresholdDefaultRecoveryMessage = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
const getDataViewId = (searchConfiguration?: SerializedSearchSourceFields) =>
|
||||
const getDataViewId = (searchConfiguration?: SearchConfigurationWithExtractedReferenceType) =>
|
||||
typeof searchConfiguration?.index === 'string'
|
||||
? searchConfiguration.index
|
||||
: searchConfiguration?.index?.title;
|
||||
|
@ -147,8 +151,9 @@ export const registerObservabilityRuleTypes = async (
|
|||
defaultRecoveryMessage: thresholdDefaultRecoveryMessage,
|
||||
requiresAppContext: false,
|
||||
format: ({ fields }) => {
|
||||
const groups = getGroups(fields[ALERT_GROUP_FIELD], fields[ALERT_GROUP_VALUE]);
|
||||
const searchConfiguration = fields[ALERT_RULE_PARAMETERS]?.searchConfiguration as
|
||||
| SerializedSearchSourceFields
|
||||
| SearchConfigurationWithExtractedReferenceType
|
||||
| undefined;
|
||||
const criteria = fields[ALERT_RULE_PARAMETERS]?.criteria as MetricExpression[];
|
||||
const metrics: CustomThresholdExpressionMetric[] =
|
||||
|
@ -158,11 +163,12 @@ export const registerObservabilityRuleTypes = async (
|
|||
return {
|
||||
reason: fields[ALERT_REASON] ?? '-',
|
||||
link: getViewInAppUrl({
|
||||
metrics,
|
||||
startedAt: fields[ALERT_START],
|
||||
logsExplorerLocator,
|
||||
filter: (searchConfiguration?.query as { query: string }).query,
|
||||
dataViewId,
|
||||
groups,
|
||||
logsExplorerLocator,
|
||||
metrics,
|
||||
searchConfiguration,
|
||||
startedAt: fields[ALERT_START],
|
||||
}),
|
||||
hasBasePath: true,
|
||||
};
|
||||
|
|
|
@ -1251,10 +1251,16 @@ describe('The custom threshold alert type', () => {
|
|||
const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
||||
expect(getViewInAppUrl).toBeCalledWith({
|
||||
dataViewId: 'c34a7c79-a88b-4b4a-ad19-72f6d24104e4',
|
||||
filter: mockQuery,
|
||||
logsExplorerLocator: undefined,
|
||||
metrics: customThresholdCountCriterion.metrics,
|
||||
startedAt: expect.stringMatching(ISO_DATE_REGEX),
|
||||
searchConfiguration: {
|
||||
index: {},
|
||||
query: {
|
||||
query: mockQuery,
|
||||
language: 'kuery',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,6 +18,7 @@ import { LocatorPublic } from '@kbn/share-plugin/common';
|
|||
import { RecoveredActionGroup } from '@kbn/alerting-plugin/common';
|
||||
import { IBasePath, Logger } from '@kbn/core/server';
|
||||
import { LifecycleRuleExecutor } from '@kbn/rule-registry-plugin/server';
|
||||
import { Group } from '../../../../common/custom_threshold_rule/types';
|
||||
import { getEvaluationValues, getThreshold } from './lib/get_values';
|
||||
import { AlertsLocatorParams, getAlertDetailsUrl } from '../../../../common';
|
||||
import { getViewInAppUrl } from '../../../../common/custom_threshold_rule/get_view_in_app_url';
|
||||
|
@ -177,16 +178,16 @@ export const createCustomThresholdExecutor = ({
|
|||
}
|
||||
|
||||
const groupByKeysObjectMapping = getFormattedGroupBy(params.groupBy, resultGroupSet);
|
||||
const groups = [...resultGroupSet];
|
||||
const groupArray = [...resultGroupSet];
|
||||
const nextMissingGroups = new Set<MissingGroupsRecord>();
|
||||
const hasGroups = !isEqual(groups, [UNGROUPED_FACTORY_KEY]);
|
||||
const hasGroups = !isEqual(groupArray, [UNGROUPED_FACTORY_KEY]);
|
||||
let scheduledActionsCount = 0;
|
||||
|
||||
const alertLimit = baseAlertFactory.alertLimit.getValue();
|
||||
let hasReachedLimit = false;
|
||||
|
||||
// The key of `groups` is the alert instance ID.
|
||||
for (const group of groups) {
|
||||
// The key of `groupArray` is the alert instance ID.
|
||||
for (const group of groupArray) {
|
||||
if (scheduledActionsCount >= alertLimit) {
|
||||
// need to set this so that warning is displayed in the UI and in the logs
|
||||
hasReachedLimit = true;
|
||||
|
@ -264,6 +265,7 @@ export const createCustomThresholdExecutor = ({
|
|||
new Set([...(additionalContext.tags ?? []), ...options.rule.tags])
|
||||
);
|
||||
|
||||
const groups: Group[] = groupByKeysObjectMapping[group];
|
||||
const alert = alertFactory(
|
||||
`${group}`,
|
||||
reason,
|
||||
|
@ -271,7 +273,7 @@ export const createCustomThresholdExecutor = ({
|
|||
additionalContext,
|
||||
evaluationValues,
|
||||
threshold,
|
||||
groupByKeysObjectMapping[group]
|
||||
groups
|
||||
);
|
||||
const alertUuid = getAlertUuid(group);
|
||||
const indexedStartedAt = getAlertStartedDate(group) ?? startedAt.toISOString();
|
||||
|
@ -291,9 +293,10 @@ export const createCustomThresholdExecutor = ({
|
|||
}),
|
||||
viewInAppUrl: getViewInAppUrl({
|
||||
dataViewId: params.searchConfiguration?.index?.title ?? dataViewId,
|
||||
filter: params.searchConfiguration.query.query,
|
||||
groups,
|
||||
logsExplorerLocator,
|
||||
metrics: alertResults.length === 1 ? alertResults[0][group].metrics : [],
|
||||
searchConfiguration: params.searchConfiguration,
|
||||
startedAt: indexedStartedAt,
|
||||
}),
|
||||
...additionalContext,
|
||||
|
@ -325,10 +328,11 @@ export const createCustomThresholdExecutor = ({
|
|||
group,
|
||||
timestamp: startedAt.toISOString(),
|
||||
viewInAppUrl: getViewInAppUrl({
|
||||
dataViewId: params.searchConfiguration?.index?.title ?? dataViewId,
|
||||
filter: params.searchConfiguration.query.query,
|
||||
dataViewId,
|
||||
groups: group,
|
||||
logsExplorerLocator,
|
||||
metrics: params.criteria[0]?.metrics,
|
||||
searchConfiguration: params.searchConfiguration,
|
||||
startedAt: indexedStartedAt,
|
||||
}),
|
||||
...additionalContext,
|
||||
|
|
|
@ -9,8 +9,10 @@ import { ElasticsearchClient } from '@kbn/core/server';
|
|||
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
|
||||
import type { Logger } from '@kbn/logging';
|
||||
import { isString, get, identity } from 'lodash';
|
||||
import { SearchConfigurationType } from '../types';
|
||||
import { CustomMetricExpressionParams } from '../../../../../common/custom_threshold_rule/types';
|
||||
import {
|
||||
CustomMetricExpressionParams,
|
||||
SearchConfigurationType,
|
||||
} from '../../../../../common/custom_threshold_rule/types';
|
||||
import type { BucketKey } from './get_data';
|
||||
import { calculateCurrentTimeFrame, createBoolQuery } from './metric_query';
|
||||
|
||||
|
|
|
@ -12,9 +12,9 @@ import { getIntervalInSeconds } from '../../../../../common/utils/get_interval_i
|
|||
import {
|
||||
Aggregators,
|
||||
CustomMetricExpressionParams,
|
||||
SearchConfigurationType,
|
||||
} from '../../../../../common/custom_threshold_rule/types';
|
||||
import { AdditionalContext } from '../utils';
|
||||
import { SearchConfigurationType } from '../types';
|
||||
import { createTimerange } from './create_timerange';
|
||||
import { getData } from './get_data';
|
||||
import { checkMissingGroups, MissingGroupsRecord } from './check_missing_group';
|
||||
|
|
|
@ -9,8 +9,10 @@ import { SearchResponse, AggregationsAggregate } from '@elastic/elasticsearch/li
|
|||
import { ElasticsearchClient } from '@kbn/core/server';
|
||||
import type { Logger } from '@kbn/logging';
|
||||
import { EcsFieldsResponse } from '@kbn/rule-registry-plugin/common/search_strategy';
|
||||
import { SearchConfigurationType } from '../types';
|
||||
import { CustomMetricExpressionParams } from '../../../../../common/custom_threshold_rule/types';
|
||||
import {
|
||||
CustomMetricExpressionParams,
|
||||
SearchConfigurationType,
|
||||
} from '../../../../../common/custom_threshold_rule/types';
|
||||
|
||||
import { UNGROUPED_FACTORY_KEY } from '../constants';
|
||||
import { CONTAINER_ID, AdditionalContext, doFieldsExist, KUBERNETES_POD_UID } from '../utils';
|
||||
|
|
|
@ -10,8 +10,8 @@ import {
|
|||
Comparator,
|
||||
Aggregators,
|
||||
CustomMetricExpressionParams,
|
||||
SearchConfigurationType,
|
||||
} from '../../../../../common/custom_threshold_rule/types';
|
||||
import { SearchConfigurationType } from '../types';
|
||||
import { getElasticsearchMetricQuery } from './metric_query';
|
||||
|
||||
describe("The Metric Threshold Alert's getElasticsearchMetricQuery", () => {
|
||||
|
@ -30,10 +30,12 @@ describe("The Metric Threshold Alert's getElasticsearchMetricQuery", () => {
|
|||
};
|
||||
const searchConfiguration: SearchConfigurationType = {
|
||||
index: {
|
||||
id: 'dataset-logs-*-*',
|
||||
name: 'All logs',
|
||||
timeFieldName: '@timestamp',
|
||||
title: 'logs-*-*',
|
||||
index: {
|
||||
id: 'dataset-logs-*-*',
|
||||
name: 'All logs',
|
||||
timeFieldName: '@timestamp',
|
||||
title: 'logs-*-*',
|
||||
},
|
||||
},
|
||||
query: {
|
||||
language: 'kuery',
|
||||
|
|
|
@ -11,9 +11,9 @@ import { Filter } from '@kbn/es-query';
|
|||
import {
|
||||
Aggregators,
|
||||
CustomMetricExpressionParams,
|
||||
SearchConfigurationType,
|
||||
} from '../../../../../common/custom_threshold_rule/types';
|
||||
import { getSearchConfigurationBoolQuery } from '../../../../utils/get_parsed_filtered_query';
|
||||
import { SearchConfigurationType } from '../types';
|
||||
import { createCustomMetricsAggregations } from './create_custom_metrics_aggregations';
|
||||
import {
|
||||
CONTAINER_ID,
|
||||
|
|
|
@ -13,13 +13,14 @@ import {
|
|||
RuleTypeState,
|
||||
} from '@kbn/alerting-plugin/common';
|
||||
import { Alert } from '@kbn/alerting-plugin/server';
|
||||
import { TypeOf } from '@kbn/config-schema';
|
||||
import { DataViewSpec } from '@kbn/data-views-plugin/common';
|
||||
import { CustomMetricExpressionParams } from '../../../../common/custom_threshold_rule/types';
|
||||
import {
|
||||
CustomMetricExpressionParams,
|
||||
Group,
|
||||
SearchConfigurationWithExtractedReferenceType,
|
||||
} from '../../../../common/custom_threshold_rule/types';
|
||||
import { FIRED_ACTIONS_ID, NO_DATA_ACTIONS_ID, FIRED_ACTION, NO_DATA_ACTION } from './constants';
|
||||
import { MissingGroupsRecord } from './lib/check_missing_group';
|
||||
import { AdditionalContext } from './utils';
|
||||
import { searchConfigurationSchema } from './register_custom_threshold_rule_type';
|
||||
|
||||
export enum AlertStates {
|
||||
OK,
|
||||
|
@ -29,13 +30,11 @@ export enum AlertStates {
|
|||
}
|
||||
|
||||
// Executor types
|
||||
export type SearchConfigurationType = TypeOf<typeof searchConfigurationSchema>;
|
||||
export type RuleTypeParams = Record<string, unknown>;
|
||||
|
||||
export interface CustomThresholdRuleTypeParams extends RuleTypeParams {
|
||||
criteria: CustomMetricExpressionParams[];
|
||||
// Index will be a data view spec after extracting references
|
||||
searchConfiguration: Omit<SearchConfigurationType, 'index'> & { index: DataViewSpec };
|
||||
searchConfiguration: SearchConfigurationWithExtractedReferenceType;
|
||||
groupBy?: string | string[];
|
||||
alertOnNoData: boolean;
|
||||
alertOnGroupDisappear?: boolean;
|
||||
|
@ -45,7 +44,7 @@ export type CustomThresholdRuleTypeState = RuleTypeState & {
|
|||
lastRunTimestamp?: number;
|
||||
missingGroups?: Array<string | MissingGroupsRecord>;
|
||||
groupBy?: string | string[];
|
||||
searchConfiguration?: Omit<SearchConfigurationType, 'index'> & { index: DataViewSpec };
|
||||
searchConfiguration?: SearchConfigurationWithExtractedReferenceType;
|
||||
};
|
||||
export type CustomThresholdAlertState = AlertState; // no specific instance state used
|
||||
export type CustomThresholdAlertContext = AlertContext & {
|
||||
|
@ -64,11 +63,6 @@ export type CustomThresholdActionGroup =
|
|||
| typeof NO_DATA_ACTIONS_ID
|
||||
| typeof RecoveredActionGroup.id;
|
||||
|
||||
export type Group = Array<{
|
||||
field: string;
|
||||
value: string;
|
||||
}>;
|
||||
|
||||
export type CustomThresholdAlertFactory = (
|
||||
id: string,
|
||||
reason: string,
|
||||
|
@ -76,7 +70,7 @@ export type CustomThresholdAlertFactory = (
|
|||
additionalContext?: AdditionalContext | null,
|
||||
evaluationValues?: Array<number | null>,
|
||||
threshold?: Array<number | null>,
|
||||
group?: Group
|
||||
group?: Group[]
|
||||
) => CustomThresholdAlert;
|
||||
|
||||
type CustomThresholdAlert = Alert<
|
||||
|
|
|
@ -16,8 +16,9 @@ import { ES_FIELD_TYPES } from '@kbn/field-types';
|
|||
import { set } from '@kbn/safer-lodash-set';
|
||||
import { ParsedExperimentalFields } from '@kbn/rule-registry-plugin/common/parse_experimental_fields';
|
||||
import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common';
|
||||
import type { Group } from '../../../../common/custom_threshold_rule/types';
|
||||
import { ObservabilityConfig } from '../../..';
|
||||
import { AlertExecutionDetails, Group } from './types';
|
||||
import { AlertExecutionDetails } from './types';
|
||||
|
||||
const ALERT_CONTEXT_CONTAINER = 'container';
|
||||
const ALERT_CONTEXT_ORCHESTRATOR = 'orchestrator';
|
||||
|
@ -228,13 +229,13 @@ export const flattenObject = (obj: AdditionalContext, prefix: string = ''): Addi
|
|||
export const getFormattedGroupBy = (
|
||||
groupBy: string | string[] | undefined,
|
||||
groupSet: Set<string>
|
||||
): Record<string, Group> => {
|
||||
const groupByKeysObjectMapping: Record<string, Group> = {};
|
||||
): Record<string, Group[]> => {
|
||||
const groupByKeysObjectMapping: Record<string, Group[]> = {};
|
||||
if (groupBy) {
|
||||
groupSet.forEach((group) => {
|
||||
const groupSetKeys = group.split(',');
|
||||
groupByKeysObjectMapping[group] = Array.isArray(groupBy)
|
||||
? groupBy.reduce((result: Group, groupByItem, index) => {
|
||||
? groupBy.reduce((result: Group[], groupByItem, index) => {
|
||||
result.push({ field: groupByItem, value: groupSetKeys[index]?.trim() });
|
||||
return result;
|
||||
}, [])
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
fromKueryExpression,
|
||||
toElasticsearchQuery,
|
||||
} from '@kbn/es-query';
|
||||
import { SearchConfigurationType } from '../lib/rules/custom_threshold/types';
|
||||
import { SearchConfigurationType } from '../../common/custom_threshold_rule/types';
|
||||
|
||||
export const getParsedFilterQuery: (filter: string | undefined) => Array<Record<string, any>> = (
|
||||
filter
|
||||
|
|
|
@ -252,6 +252,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
dataset: DATA_VIEW_TITLE,
|
||||
timeRange: { to: 'now' },
|
||||
query: { query: '', language: 'kuery' },
|
||||
filters: [],
|
||||
});
|
||||
expect(parsedViewInAppUrl.params.timeRange.from).match(ISO_DATE_REGEX);
|
||||
});
|
||||
|
|
|
@ -220,6 +220,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
dataset: DATA_VIEW_ID,
|
||||
timeRange: { to: 'now' },
|
||||
query: { query: '', language: 'kuery' },
|
||||
filters: [],
|
||||
});
|
||||
expect(parsedViewInAppUrl.params.timeRange.from).match(ISO_DATE_REGEX);
|
||||
});
|
||||
|
|
|
@ -252,6 +252,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
dataset: DATA_VIEW_ID,
|
||||
timeRange: { to: 'now' },
|
||||
query: { query: 'host.name:* and container.id:*', language: 'kuery' },
|
||||
filters: [],
|
||||
});
|
||||
expect(parsedViewInAppUrl.params.timeRange.from).match(ISO_DATE_REGEX);
|
||||
});
|
||||
|
|
|
@ -247,6 +247,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
dataset: DATE_VIEW_TITLE,
|
||||
timeRange: { to: 'now' },
|
||||
query: { query: '', language: 'kuery' },
|
||||
filters: [],
|
||||
});
|
||||
expect(parsedViewInAppUrl.params.timeRange.from).match(ISO_DATE_REGEX);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue