parent
296f81cf05
commit
def8204814
|
@ -1597,7 +1597,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 3160
|
"lineNumber": 174
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
{
|
{
|
||||||
|
@ -1816,7 +1816,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 558
|
"lineNumber": 56
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
{
|
{
|
||||||
|
@ -1837,7 +1837,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 559
|
"lineNumber": 57
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1848,7 +1848,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 562
|
"lineNumber": 60
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"[number, number[]][]"
|
"[number, number[]][]"
|
||||||
|
@ -1859,7 +1859,7 @@
|
||||||
"label": "[ColorSchemas.Greens]",
|
"label": "[ColorSchemas.Greens]",
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 557
|
"lineNumber": 55
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1875,7 +1875,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 1078
|
"lineNumber": 74
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
{
|
{
|
||||||
|
@ -1896,7 +1896,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 1079
|
"lineNumber": 75
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1907,7 +1907,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 1082
|
"lineNumber": 78
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"[number, number[]][]"
|
"[number, number[]][]"
|
||||||
|
@ -1918,7 +1918,7 @@
|
||||||
"label": "[ColorSchemas.Greys]",
|
"label": "[ColorSchemas.Greys]",
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 1077
|
"lineNumber": 73
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1934,7 +1934,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 1598
|
"lineNumber": 92
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
{
|
{
|
||||||
|
@ -1955,7 +1955,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 1599
|
"lineNumber": 93
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1966,7 +1966,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 1602
|
"lineNumber": 96
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"[number, number[]][]"
|
"[number, number[]][]"
|
||||||
|
@ -1977,7 +1977,7 @@
|
||||||
"label": "[ColorSchemas.Reds]",
|
"label": "[ColorSchemas.Reds]",
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 1597
|
"lineNumber": 91
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1993,7 +1993,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 2118
|
"lineNumber": 110
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
{
|
{
|
||||||
|
@ -2014,7 +2014,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 2119
|
"lineNumber": 111
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2025,7 +2025,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 2122
|
"lineNumber": 114
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"[number, number[]][]"
|
"[number, number[]][]"
|
||||||
|
@ -2036,7 +2036,7 @@
|
||||||
"label": "[ColorSchemas.YellowToRed]",
|
"label": "[ColorSchemas.YellowToRed]",
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 2117
|
"lineNumber": 109
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2052,7 +2052,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 2639
|
"lineNumber": 129
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
{
|
{
|
||||||
|
@ -2073,7 +2073,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 2640
|
"lineNumber": 130
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2084,7 +2084,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 2643
|
"lineNumber": 133
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"[number, number[]][]"
|
"[number, number[]][]"
|
||||||
|
@ -2095,7 +2095,7 @@
|
||||||
"label": "[ColorSchemas.GreenToRed]",
|
"label": "[ColorSchemas.GreenToRed]",
|
||||||
"source": {
|
"source": {
|
||||||
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
"path": "src/plugins/charts/public/static/color_maps/color_maps.ts",
|
||||||
"lineNumber": 2638
|
"lineNumber": 128
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
1394
api_docs/data.json
1394
api_docs/data.json
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -21952,6 +21952,41 @@
|
||||||
"returnComment": [],
|
"returnComment": [],
|
||||||
"initialIsOpen": false
|
"initialIsOpen": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "def-common.createMockContext",
|
||||||
|
"type": "Function",
|
||||||
|
"children": [],
|
||||||
|
"signature": [
|
||||||
|
"() => ",
|
||||||
|
{
|
||||||
|
"pluginId": "expressions",
|
||||||
|
"scope": "common",
|
||||||
|
"docId": "kibExpressionsPluginApi",
|
||||||
|
"section": "def-common.ExecutionContext",
|
||||||
|
"text": "ExecutionContext"
|
||||||
|
},
|
||||||
|
"<",
|
||||||
|
{
|
||||||
|
"pluginId": "inspector",
|
||||||
|
"scope": "common",
|
||||||
|
"docId": "kibInspectorPluginApi",
|
||||||
|
"section": "def-common.Adapters",
|
||||||
|
"text": "Adapters"
|
||||||
|
},
|
||||||
|
", ",
|
||||||
|
"SerializableState",
|
||||||
|
">"
|
||||||
|
],
|
||||||
|
"description": [],
|
||||||
|
"label": "createMockContext",
|
||||||
|
"source": {
|
||||||
|
"path": "src/plugins/expressions/common/util/test_utils.ts",
|
||||||
|
"lineNumber": 11
|
||||||
|
},
|
||||||
|
"tags": [],
|
||||||
|
"returnComment": [],
|
||||||
|
"initialIsOpen": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "def-common.format",
|
"id": "def-common.format",
|
||||||
"type": "Function",
|
"type": "Function",
|
||||||
|
@ -22465,6 +22500,52 @@
|
||||||
"tags": [],
|
"tags": [],
|
||||||
"returnComment": [],
|
"returnComment": [],
|
||||||
"initialIsOpen": false
|
"initialIsOpen": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "def-common.unboxExpressionValue",
|
||||||
|
"type": "Function",
|
||||||
|
"label": "unboxExpressionValue",
|
||||||
|
"signature": [
|
||||||
|
"({\n type,\n ...value\n}: ",
|
||||||
|
{
|
||||||
|
"pluginId": "expressions",
|
||||||
|
"scope": "common",
|
||||||
|
"docId": "kibExpressionsPluginApi",
|
||||||
|
"section": "def-common.ExpressionValueBoxed",
|
||||||
|
"text": "ExpressionValueBoxed"
|
||||||
|
},
|
||||||
|
"<string, T>) => T"
|
||||||
|
],
|
||||||
|
"description": [],
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"type": "CompoundType",
|
||||||
|
"label": "{\n type,\n ...value\n}",
|
||||||
|
"isRequired": true,
|
||||||
|
"signature": [
|
||||||
|
{
|
||||||
|
"pluginId": "expressions",
|
||||||
|
"scope": "common",
|
||||||
|
"docId": "kibExpressionsPluginApi",
|
||||||
|
"section": "def-common.ExpressionValueBoxed",
|
||||||
|
"text": "ExpressionValueBoxed"
|
||||||
|
},
|
||||||
|
"<string, T>"
|
||||||
|
],
|
||||||
|
"description": [],
|
||||||
|
"source": {
|
||||||
|
"path": "src/plugins/expressions/common/expression_types/unbox_expression_value.ts",
|
||||||
|
"lineNumber": 11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [],
|
||||||
|
"returnComment": [],
|
||||||
|
"source": {
|
||||||
|
"path": "src/plugins/expressions/common/expression_types/unbox_expression_value.ts",
|
||||||
|
"lineNumber": 11
|
||||||
|
},
|
||||||
|
"initialIsOpen": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"interfaces": [
|
"interfaces": [
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -288,7 +288,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/column_types.ts",
|
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/column_types.ts",
|
||||||
"lineNumber": 44
|
"lineNumber": 46
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"\"range\" | \"filters\" | \"count\" | \"max\" | \"min\" | \"date_histogram\" | \"sum\" | \"terms\" | \"avg\" | \"median\" | \"cumulative_sum\" | \"derivative\" | \"moving_average\" | \"counter_rate\" | \"cardinality\" | \"percentile\" | \"last_value\" | undefined"
|
"\"range\" | \"filters\" | \"count\" | \"max\" | \"min\" | \"date_histogram\" | \"sum\" | \"terms\" | \"avg\" | \"median\" | \"cumulative_sum\" | \"derivative\" | \"moving_average\" | \"counter_rate\" | \"cardinality\" | \"percentile\" | \"last_value\" | undefined"
|
||||||
|
@ -302,7 +302,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/column_types.ts",
|
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/column_types.ts",
|
||||||
"lineNumber": 45
|
"lineNumber": 47
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"string | undefined"
|
"string | undefined"
|
||||||
|
@ -311,7 +311,7 @@
|
||||||
],
|
],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/column_types.ts",
|
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/column_types.ts",
|
||||||
"lineNumber": 43
|
"lineNumber": 45
|
||||||
},
|
},
|
||||||
"initialIsOpen": false
|
"initialIsOpen": false
|
||||||
},
|
},
|
||||||
|
@ -1318,7 +1318,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx",
|
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx",
|
||||||
"lineNumber": 125
|
"lineNumber": 127
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"avg\"; }"
|
"BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"avg\"; }"
|
||||||
|
@ -1475,7 +1475,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx",
|
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx",
|
||||||
"lineNumber": 127
|
"lineNumber": 129
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"max\"; }"
|
"BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"max\"; }"
|
||||||
|
@ -1490,7 +1490,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx",
|
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx",
|
||||||
"lineNumber": 128
|
"lineNumber": 130
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"median\"; }"
|
"BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"median\"; }"
|
||||||
|
@ -1505,7 +1505,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx",
|
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx",
|
||||||
"lineNumber": 126
|
"lineNumber": 128
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"min\"; }"
|
"BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"min\"; }"
|
||||||
|
@ -1538,7 +1538,7 @@
|
||||||
],
|
],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts",
|
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts",
|
||||||
"lineNumber": 405
|
"lineNumber": 406
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"\"range\" | \"filters\" | \"count\" | \"max\" | \"min\" | \"date_histogram\" | \"sum\" | \"terms\" | \"avg\" | \"median\" | \"cumulative_sum\" | \"derivative\" | \"moving_average\" | \"counter_rate\" | \"cardinality\" | \"percentile\" | \"last_value\""
|
"\"range\" | \"filters\" | \"count\" | \"max\" | \"min\" | \"date_histogram\" | \"sum\" | \"terms\" | \"avg\" | \"median\" | \"cumulative_sum\" | \"derivative\" | \"moving_average\" | \"counter_rate\" | \"cardinality\" | \"percentile\" | \"last_value\""
|
||||||
|
@ -1598,7 +1598,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx",
|
"path": "x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx",
|
||||||
"lineNumber": 124
|
"lineNumber": 126
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"sum\"; }"
|
"BaseIndexPatternColumn & { params?: { format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; } | undefined; } & FieldBasedIndexPatternColumn & { operationType: \"sum\"; }"
|
||||||
|
|
|
@ -2312,7 +2312,7 @@
|
||||||
"description": [],
|
"description": [],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "x-pack/plugins/observability/server/plugin.ts",
|
"path": "x-pack/plugins/observability/server/plugin.ts",
|
||||||
"lineNumber": 22
|
"lineNumber": 23
|
||||||
},
|
},
|
||||||
"signature": [
|
"signature": [
|
||||||
"LazyScopedAnnotationsClientFactory"
|
"LazyScopedAnnotationsClientFactory"
|
||||||
|
@ -2321,7 +2321,7 @@
|
||||||
],
|
],
|
||||||
"source": {
|
"source": {
|
||||||
"path": "x-pack/plugins/observability/server/plugin.ts",
|
"path": "x-pack/plugins/observability/server/plugin.ts",
|
||||||
"lineNumber": 21
|
"lineNumber": 22
|
||||||
},
|
},
|
||||||
"lifecycle": "setup",
|
"lifecycle": "setup",
|
||||||
"initialIsOpen": true
|
"initialIsOpen": true
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggFunctionsMapping](./kibana-plugin-plugins-data-public.aggfunctionsmapping.md) > [aggFilteredMetric](./kibana-plugin-plugins-data-public.aggfunctionsmapping.aggfilteredmetric.md)
|
||||||
|
|
||||||
|
## AggFunctionsMapping.aggFilteredMetric property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
aggFilteredMetric: ReturnType<typeof aggFilteredMetric>;
|
||||||
|
```
|
|
@ -28,6 +28,7 @@ export interface AggFunctionsMapping
|
||||||
| [aggDateRange](./kibana-plugin-plugins-data-public.aggfunctionsmapping.aggdaterange.md) | <code>ReturnType<typeof aggDateRange></code> | |
|
| [aggDateRange](./kibana-plugin-plugins-data-public.aggfunctionsmapping.aggdaterange.md) | <code>ReturnType<typeof aggDateRange></code> | |
|
||||||
| [aggDerivative](./kibana-plugin-plugins-data-public.aggfunctionsmapping.aggderivative.md) | <code>ReturnType<typeof aggDerivative></code> | |
|
| [aggDerivative](./kibana-plugin-plugins-data-public.aggfunctionsmapping.aggderivative.md) | <code>ReturnType<typeof aggDerivative></code> | |
|
||||||
| [aggFilter](./kibana-plugin-plugins-data-public.aggfunctionsmapping.aggfilter.md) | <code>ReturnType<typeof aggFilter></code> | |
|
| [aggFilter](./kibana-plugin-plugins-data-public.aggfunctionsmapping.aggfilter.md) | <code>ReturnType<typeof aggFilter></code> | |
|
||||||
|
| [aggFilteredMetric](./kibana-plugin-plugins-data-public.aggfunctionsmapping.aggfilteredmetric.md) | <code>ReturnType<typeof aggFilteredMetric></code> | |
|
||||||
| [aggFilters](./kibana-plugin-plugins-data-public.aggfunctionsmapping.aggfilters.md) | <code>ReturnType<typeof aggFilters></code> | |
|
| [aggFilters](./kibana-plugin-plugins-data-public.aggfunctionsmapping.aggfilters.md) | <code>ReturnType<typeof aggFilters></code> | |
|
||||||
| [aggGeoBounds](./kibana-plugin-plugins-data-public.aggfunctionsmapping.agggeobounds.md) | <code>ReturnType<typeof aggGeoBounds></code> | |
|
| [aggGeoBounds](./kibana-plugin-plugins-data-public.aggfunctionsmapping.agggeobounds.md) | <code>ReturnType<typeof aggGeoBounds></code> | |
|
||||||
| [aggGeoCentroid](./kibana-plugin-plugins-data-public.aggfunctionsmapping.agggeocentroid.md) | <code>ReturnType<typeof aggGeoCentroid></code> | |
|
| [aggGeoCentroid](./kibana-plugin-plugins-data-public.aggfunctionsmapping.agggeocentroid.md) | <code>ReturnType<typeof aggGeoCentroid></code> | |
|
||||||
|
|
|
@ -20,6 +20,7 @@ export declare enum METRIC_TYPES
|
||||||
| COUNT | <code>"count"</code> | |
|
| COUNT | <code>"count"</code> | |
|
||||||
| CUMULATIVE\_SUM | <code>"cumulative_sum"</code> | |
|
| CUMULATIVE\_SUM | <code>"cumulative_sum"</code> | |
|
||||||
| DERIVATIVE | <code>"derivative"</code> | |
|
| DERIVATIVE | <code>"derivative"</code> | |
|
||||||
|
| FILTERED\_METRIC | <code>"filtered_metric"</code> | |
|
||||||
| GEO\_BOUNDS | <code>"geo_bounds"</code> | |
|
| GEO\_BOUNDS | <code>"geo_bounds"</code> | |
|
||||||
| GEO\_CENTROID | <code>"geo_centroid"</code> | |
|
| GEO\_CENTROID | <code>"geo_centroid"</code> | |
|
||||||
| MAX | <code>"max"</code> | |
|
| MAX | <code>"max"</code> | |
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggFunctionsMapping](./kibana-plugin-plugins-data-server.aggfunctionsmapping.md) > [aggFilteredMetric](./kibana-plugin-plugins-data-server.aggfunctionsmapping.aggfilteredmetric.md)
|
||||||
|
|
||||||
|
## AggFunctionsMapping.aggFilteredMetric property
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
aggFilteredMetric: ReturnType<typeof aggFilteredMetric>;
|
||||||
|
```
|
|
@ -28,6 +28,7 @@ export interface AggFunctionsMapping
|
||||||
| [aggDateRange](./kibana-plugin-plugins-data-server.aggfunctionsmapping.aggdaterange.md) | <code>ReturnType<typeof aggDateRange></code> | |
|
| [aggDateRange](./kibana-plugin-plugins-data-server.aggfunctionsmapping.aggdaterange.md) | <code>ReturnType<typeof aggDateRange></code> | |
|
||||||
| [aggDerivative](./kibana-plugin-plugins-data-server.aggfunctionsmapping.aggderivative.md) | <code>ReturnType<typeof aggDerivative></code> | |
|
| [aggDerivative](./kibana-plugin-plugins-data-server.aggfunctionsmapping.aggderivative.md) | <code>ReturnType<typeof aggDerivative></code> | |
|
||||||
| [aggFilter](./kibana-plugin-plugins-data-server.aggfunctionsmapping.aggfilter.md) | <code>ReturnType<typeof aggFilter></code> | |
|
| [aggFilter](./kibana-plugin-plugins-data-server.aggfunctionsmapping.aggfilter.md) | <code>ReturnType<typeof aggFilter></code> | |
|
||||||
|
| [aggFilteredMetric](./kibana-plugin-plugins-data-server.aggfunctionsmapping.aggfilteredmetric.md) | <code>ReturnType<typeof aggFilteredMetric></code> | |
|
||||||
| [aggFilters](./kibana-plugin-plugins-data-server.aggfunctionsmapping.aggfilters.md) | <code>ReturnType<typeof aggFilters></code> | |
|
| [aggFilters](./kibana-plugin-plugins-data-server.aggfunctionsmapping.aggfilters.md) | <code>ReturnType<typeof aggFilters></code> | |
|
||||||
| [aggGeoBounds](./kibana-plugin-plugins-data-server.aggfunctionsmapping.agggeobounds.md) | <code>ReturnType<typeof aggGeoBounds></code> | |
|
| [aggGeoBounds](./kibana-plugin-plugins-data-server.aggfunctionsmapping.agggeobounds.md) | <code>ReturnType<typeof aggGeoBounds></code> | |
|
||||||
| [aggGeoCentroid](./kibana-plugin-plugins-data-server.aggfunctionsmapping.agggeocentroid.md) | <code>ReturnType<typeof aggGeoCentroid></code> | |
|
| [aggGeoCentroid](./kibana-plugin-plugins-data-server.aggfunctionsmapping.agggeocentroid.md) | <code>ReturnType<typeof aggGeoCentroid></code> | |
|
||||||
|
|
|
@ -20,6 +20,7 @@ export declare enum METRIC_TYPES
|
||||||
| COUNT | <code>"count"</code> | |
|
| COUNT | <code>"count"</code> | |
|
||||||
| CUMULATIVE\_SUM | <code>"cumulative_sum"</code> | |
|
| CUMULATIVE\_SUM | <code>"cumulative_sum"</code> | |
|
||||||
| DERIVATIVE | <code>"derivative"</code> | |
|
| DERIVATIVE | <code>"derivative"</code> | |
|
||||||
|
| FILTERED\_METRIC | <code>"filtered_metric"</code> | |
|
||||||
| GEO\_BOUNDS | <code>"geo_bounds"</code> | |
|
| GEO\_BOUNDS | <code>"geo_bounds"</code> | |
|
||||||
| GEO\_CENTROID | <code>"geo_centroid"</code> | |
|
| GEO\_CENTROID | <code>"geo_centroid"</code> | |
|
||||||
| MAX | <code>"max"</code> | |
|
| MAX | <code>"max"</code> | |
|
||||||
|
|
|
@ -232,7 +232,9 @@ export class AggConfig {
|
||||||
const output = this.write(aggConfigs) as any;
|
const output = this.write(aggConfigs) as any;
|
||||||
|
|
||||||
const configDsl = {} as any;
|
const configDsl = {} as any;
|
||||||
configDsl[this.type.dslName || this.type.name] = output.params;
|
if (!this.type.hasNoDslParams) {
|
||||||
|
configDsl[this.type.dslName || this.type.name] = output.params;
|
||||||
|
}
|
||||||
|
|
||||||
// if the config requires subAggs, write them to the dsl as well
|
// if the config requires subAggs, write them to the dsl as well
|
||||||
if (this.subAggs.length) {
|
if (this.subAggs.length) {
|
||||||
|
|
|
@ -21,7 +21,14 @@ import { TimeRange } from '../../../common';
|
||||||
function removeParentAggs(obj: any) {
|
function removeParentAggs(obj: any) {
|
||||||
for (const prop in obj) {
|
for (const prop in obj) {
|
||||||
if (prop === 'parentAggs') delete obj[prop];
|
if (prop === 'parentAggs') delete obj[prop];
|
||||||
else if (typeof obj[prop] === 'object') removeParentAggs(obj[prop]);
|
else if (typeof obj[prop] === 'object') {
|
||||||
|
const hasParentAggsKey = 'parentAggs' in obj[prop];
|
||||||
|
removeParentAggs(obj[prop]);
|
||||||
|
// delete object if parentAggs was the last key
|
||||||
|
if (hasParentAggsKey && Object.keys(obj[prop]).length === 0) {
|
||||||
|
delete obj[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,10 +200,12 @@ export class AggConfigs {
|
||||||
// advance the cursor and nest under the previous agg, or
|
// advance the cursor and nest under the previous agg, or
|
||||||
// put it on the same level if the previous agg doesn't accept
|
// put it on the same level if the previous agg doesn't accept
|
||||||
// sub aggs
|
// sub aggs
|
||||||
dslLvlCursor = prevDsl.aggs || dslLvlCursor;
|
dslLvlCursor = prevDsl?.aggs || dslLvlCursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dsl = (dslLvlCursor[config.id] = config.toDsl(this));
|
const dsl = config.type.hasNoDslParams
|
||||||
|
? config.toDsl(this)
|
||||||
|
: (dslLvlCursor[config.id] = config.toDsl(this));
|
||||||
let subAggs: any;
|
let subAggs: any;
|
||||||
|
|
||||||
parseParentAggs(dslLvlCursor, dsl);
|
parseParentAggs(dslLvlCursor, dsl);
|
||||||
|
@ -206,6 +215,11 @@ export class AggConfigs {
|
||||||
subAggs = dsl.aggs || (dsl.aggs = {});
|
subAggs = dsl.aggs || (dsl.aggs = {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (subAggs) {
|
||||||
|
_.each(subAggs, (agg) => {
|
||||||
|
parseParentAggs(subAggs, agg);
|
||||||
|
});
|
||||||
|
}
|
||||||
if (subAggs && nestedMetrics) {
|
if (subAggs && nestedMetrics) {
|
||||||
nestedMetrics.forEach((agg: any) => {
|
nestedMetrics.forEach((agg: any) => {
|
||||||
subAggs[agg.config.id] = agg.dsl;
|
subAggs[agg.config.id] = agg.dsl;
|
||||||
|
|
|
@ -32,6 +32,7 @@ export interface AggTypeConfig<
|
||||||
makeLabel?: ((aggConfig: TAggConfig) => string) | (() => string);
|
makeLabel?: ((aggConfig: TAggConfig) => string) | (() => string);
|
||||||
ordered?: any;
|
ordered?: any;
|
||||||
hasNoDsl?: boolean;
|
hasNoDsl?: boolean;
|
||||||
|
hasNoDslParams?: boolean;
|
||||||
params?: Array<Partial<TParam>>;
|
params?: Array<Partial<TParam>>;
|
||||||
valueType?: DatatableColumnType;
|
valueType?: DatatableColumnType;
|
||||||
getRequestAggs?: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void);
|
getRequestAggs?: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void);
|
||||||
|
@ -129,6 +130,12 @@ export class AggType<
|
||||||
* @type {Boolean}
|
* @type {Boolean}
|
||||||
*/
|
*/
|
||||||
hasNoDsl: boolean;
|
hasNoDsl: boolean;
|
||||||
|
/**
|
||||||
|
* Flag that prevents params from this aggregation from being included in the dsl. Sibling and parent aggs are still written.
|
||||||
|
*
|
||||||
|
* @type {Boolean}
|
||||||
|
*/
|
||||||
|
hasNoDslParams: boolean;
|
||||||
/**
|
/**
|
||||||
* The method to create a filter representation of the bucket
|
* The method to create a filter representation of the bucket
|
||||||
* @param {object} aggConfig The instance of the aggConfig
|
* @param {object} aggConfig The instance of the aggConfig
|
||||||
|
@ -232,6 +239,7 @@ export class AggType<
|
||||||
this.makeLabel = config.makeLabel || constant(this.name);
|
this.makeLabel = config.makeLabel || constant(this.name);
|
||||||
this.ordered = config.ordered;
|
this.ordered = config.ordered;
|
||||||
this.hasNoDsl = !!config.hasNoDsl;
|
this.hasNoDsl = !!config.hasNoDsl;
|
||||||
|
this.hasNoDslParams = !!config.hasNoDslParams;
|
||||||
|
|
||||||
if (config.createFilter) {
|
if (config.createFilter) {
|
||||||
this.createFilter = config.createFilter;
|
this.createFilter = config.createFilter;
|
||||||
|
|
|
@ -44,6 +44,7 @@ export const getAggTypes = () => ({
|
||||||
{ name: METRIC_TYPES.SUM_BUCKET, fn: metrics.getBucketSumMetricAgg },
|
{ name: METRIC_TYPES.SUM_BUCKET, fn: metrics.getBucketSumMetricAgg },
|
||||||
{ name: METRIC_TYPES.MIN_BUCKET, fn: metrics.getBucketMinMetricAgg },
|
{ name: METRIC_TYPES.MIN_BUCKET, fn: metrics.getBucketMinMetricAgg },
|
||||||
{ name: METRIC_TYPES.MAX_BUCKET, fn: metrics.getBucketMaxMetricAgg },
|
{ name: METRIC_TYPES.MAX_BUCKET, fn: metrics.getBucketMaxMetricAgg },
|
||||||
|
{ name: METRIC_TYPES.FILTERED_METRIC, fn: metrics.getFilteredMetricAgg },
|
||||||
{ name: METRIC_TYPES.GEO_BOUNDS, fn: metrics.getGeoBoundsMetricAgg },
|
{ name: METRIC_TYPES.GEO_BOUNDS, fn: metrics.getGeoBoundsMetricAgg },
|
||||||
{ name: METRIC_TYPES.GEO_CENTROID, fn: metrics.getGeoCentroidMetricAgg },
|
{ name: METRIC_TYPES.GEO_CENTROID, fn: metrics.getGeoCentroidMetricAgg },
|
||||||
],
|
],
|
||||||
|
@ -80,6 +81,7 @@ export const getAggTypesFunctions = () => [
|
||||||
metrics.aggBucketMax,
|
metrics.aggBucketMax,
|
||||||
metrics.aggBucketMin,
|
metrics.aggBucketMin,
|
||||||
metrics.aggBucketSum,
|
metrics.aggBucketSum,
|
||||||
|
metrics.aggFilteredMetric,
|
||||||
metrics.aggCardinality,
|
metrics.aggCardinality,
|
||||||
metrics.aggCount,
|
metrics.aggCount,
|
||||||
metrics.aggCumulativeSum,
|
metrics.aggCumulativeSum,
|
||||||
|
|
|
@ -97,6 +97,7 @@ describe('Aggs service', () => {
|
||||||
"sum_bucket",
|
"sum_bucket",
|
||||||
"min_bucket",
|
"min_bucket",
|
||||||
"max_bucket",
|
"max_bucket",
|
||||||
|
"filtered_metric",
|
||||||
"geo_bounds",
|
"geo_bounds",
|
||||||
"geo_centroid",
|
"geo_centroid",
|
||||||
]
|
]
|
||||||
|
@ -142,6 +143,7 @@ describe('Aggs service', () => {
|
||||||
"sum_bucket",
|
"sum_bucket",
|
||||||
"min_bucket",
|
"min_bucket",
|
||||||
"max_bucket",
|
"max_bucket",
|
||||||
|
"filtered_metric",
|
||||||
"geo_bounds",
|
"geo_bounds",
|
||||||
"geo_centroid",
|
"geo_centroid",
|
||||||
]
|
]
|
||||||
|
|
|
@ -6,12 +6,15 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { BucketAggType } from './bucket_agg_type';
|
import { BucketAggType } from './bucket_agg_type';
|
||||||
import { BUCKET_TYPES } from './bucket_agg_types';
|
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||||
import { GeoBoundingBox } from './lib/geo_point';
|
import { GeoBoundingBox } from './lib/geo_point';
|
||||||
import { aggFilterFnName } from './filter_fn';
|
import { aggFilterFnName } from './filter_fn';
|
||||||
import { BaseAggParams } from '../types';
|
import { BaseAggParams } from '../types';
|
||||||
|
import { Query } from '../../../types';
|
||||||
|
import { buildEsQuery, getEsQueryConfig } from '../../../es_query';
|
||||||
|
|
||||||
const filterTitle = i18n.translate('data.search.aggs.buckets.filterTitle', {
|
const filterTitle = i18n.translate('data.search.aggs.buckets.filterTitle', {
|
||||||
defaultMessage: 'Filter',
|
defaultMessage: 'Filter',
|
||||||
|
@ -21,7 +24,7 @@ export interface AggParamsFilter extends BaseAggParams {
|
||||||
geo_bounding_box?: GeoBoundingBox;
|
geo_bounding_box?: GeoBoundingBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getFilterBucketAgg = () =>
|
export const getFilterBucketAgg = ({ getConfig }: { getConfig: <T = any>(key: string) => any }) =>
|
||||||
new BucketAggType({
|
new BucketAggType({
|
||||||
name: BUCKET_TYPES.FILTER,
|
name: BUCKET_TYPES.FILTER,
|
||||||
expressionName: aggFilterFnName,
|
expressionName: aggFilterFnName,
|
||||||
|
@ -31,5 +34,27 @@ export const getFilterBucketAgg = () =>
|
||||||
{
|
{
|
||||||
name: 'geo_bounding_box',
|
name: 'geo_bounding_box',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'filter',
|
||||||
|
write(aggConfig, output) {
|
||||||
|
const filter: Query = aggConfig.params.filter;
|
||||||
|
|
||||||
|
const input = cloneDeep(filter);
|
||||||
|
|
||||||
|
if (!input) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const esQueryConfigs = getEsQueryConfig({ get: getConfig });
|
||||||
|
const query = buildEsQuery(aggConfig.getIndexPattern(), [input], [], esQueryConfigs);
|
||||||
|
|
||||||
|
if (!query) {
|
||||||
|
console.log('malformed filter agg params, missing "query" on input'); // eslint-disable-line no-console
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.params = query;
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,6 +23,7 @@ describe('agg_expression_functions', () => {
|
||||||
"id": undefined,
|
"id": undefined,
|
||||||
"params": Object {
|
"params": Object {
|
||||||
"customLabel": undefined,
|
"customLabel": undefined,
|
||||||
|
"filter": undefined,
|
||||||
"geo_bounding_box": undefined,
|
"geo_bounding_box": undefined,
|
||||||
"json": undefined,
|
"json": undefined,
|
||||||
},
|
},
|
||||||
|
@ -46,6 +47,7 @@ describe('agg_expression_functions', () => {
|
||||||
"id": undefined,
|
"id": undefined,
|
||||||
"params": Object {
|
"params": Object {
|
||||||
"customLabel": undefined,
|
"customLabel": undefined,
|
||||||
|
"filter": undefined,
|
||||||
"geo_bounding_box": Object {
|
"geo_bounding_box": Object {
|
||||||
"wkt": "BBOX (-74.1, -71.12, 40.73, 40.01)",
|
"wkt": "BBOX (-74.1, -71.12, 40.73, 40.01)",
|
||||||
},
|
},
|
||||||
|
@ -57,6 +59,25 @@ describe('agg_expression_functions', () => {
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('correctly parses filter string argument', () => {
|
||||||
|
const actual = fn({
|
||||||
|
filter: '{ "language": "kuery", "query": "a: b" }',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(actual.value.params.filter).toEqual({ language: 'kuery', query: 'a: b' });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('errors out if geo_bounding_box is used together with filter', () => {
|
||||||
|
expect(() =>
|
||||||
|
fn({
|
||||||
|
filter: '{ "language": "kuery", "query": "a: b" }',
|
||||||
|
geo_bounding_box: JSON.stringify({
|
||||||
|
wkt: 'BBOX (-74.1, -71.12, 40.73, 40.01)',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
test('correctly parses json string argument', () => {
|
test('correctly parses json string argument', () => {
|
||||||
const actual = fn({
|
const actual = fn({
|
||||||
json: '{ "foo": true }',
|
json: '{ "foo": true }',
|
||||||
|
|
|
@ -17,7 +17,7 @@ export const aggFilterFnName = 'aggFilter';
|
||||||
type Input = any;
|
type Input = any;
|
||||||
type AggArgs = AggExpressionFunctionArgs<typeof BUCKET_TYPES.FILTER>;
|
type AggArgs = AggExpressionFunctionArgs<typeof BUCKET_TYPES.FILTER>;
|
||||||
|
|
||||||
type Arguments = Assign<AggArgs, { geo_bounding_box?: string }>;
|
type Arguments = Assign<AggArgs, { geo_bounding_box?: string; filter?: string }>;
|
||||||
|
|
||||||
type Output = AggExpressionType;
|
type Output = AggExpressionType;
|
||||||
type FunctionDefinition = ExpressionFunctionDefinition<
|
type FunctionDefinition = ExpressionFunctionDefinition<
|
||||||
|
@ -59,6 +59,13 @@ export const aggFilter = (): FunctionDefinition => ({
|
||||||
defaultMessage: 'Filter results based on a point location within a bounding box',
|
defaultMessage: 'Filter results based on a point location within a bounding box',
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
filter: {
|
||||||
|
types: ['string'],
|
||||||
|
help: i18n.translate('data.search.aggs.buckets.filter.filter.help', {
|
||||||
|
defaultMessage:
|
||||||
|
'Filter results based on a kql or lucene query. Do not use together with geo_bounding_box',
|
||||||
|
}),
|
||||||
|
},
|
||||||
json: {
|
json: {
|
||||||
types: ['string'],
|
types: ['string'],
|
||||||
help: i18n.translate('data.search.aggs.buckets.filter.json.help', {
|
help: i18n.translate('data.search.aggs.buckets.filter.json.help', {
|
||||||
|
@ -75,6 +82,13 @@ export const aggFilter = (): FunctionDefinition => ({
|
||||||
fn: (input, args) => {
|
fn: (input, args) => {
|
||||||
const { id, enabled, schema, ...rest } = args;
|
const { id, enabled, schema, ...rest } = args;
|
||||||
|
|
||||||
|
const geoBoundingBox = getParsedValue(args, 'geo_bounding_box');
|
||||||
|
const filter = getParsedValue(args, 'filter');
|
||||||
|
|
||||||
|
if (geoBoundingBox && filter) {
|
||||||
|
throw new Error("filter and geo_bounding_box can't be used together");
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'agg_type',
|
type: 'agg_type',
|
||||||
value: {
|
value: {
|
||||||
|
@ -84,7 +98,8 @@ export const aggFilter = (): FunctionDefinition => ({
|
||||||
type: BUCKET_TYPES.FILTER,
|
type: BUCKET_TYPES.FILTER,
|
||||||
params: {
|
params: {
|
||||||
...rest,
|
...rest,
|
||||||
geo_bounding_box: getParsedValue(args, 'geo_bounding_box'),
|
geo_bounding_box: geoBoundingBox,
|
||||||
|
filter,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { AggConfigs, IAggConfigs } from '../agg_configs';
|
||||||
|
import { mockAggTypesRegistry } from '../test_helpers';
|
||||||
|
import { METRIC_TYPES } from './metric_agg_types';
|
||||||
|
|
||||||
|
describe('filtered metric agg type', () => {
|
||||||
|
let aggConfigs: IAggConfigs;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const typesRegistry = mockAggTypesRegistry();
|
||||||
|
const field = {
|
||||||
|
name: 'bytes',
|
||||||
|
};
|
||||||
|
const indexPattern = {
|
||||||
|
id: '1234',
|
||||||
|
title: 'logstash-*',
|
||||||
|
fields: {
|
||||||
|
getByName: () => field,
|
||||||
|
filter: () => [field],
|
||||||
|
},
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
aggConfigs = new AggConfigs(
|
||||||
|
indexPattern,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: METRIC_TYPES.FILTERED_METRIC,
|
||||||
|
type: METRIC_TYPES.FILTERED_METRIC,
|
||||||
|
schema: 'metric',
|
||||||
|
params: {
|
||||||
|
customBucket: {
|
||||||
|
type: 'filter',
|
||||||
|
params: {
|
||||||
|
filter: { language: 'kuery', query: 'a: b' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
customMetric: {
|
||||||
|
type: 'cardinality',
|
||||||
|
params: {
|
||||||
|
field: 'bytes',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
typesRegistry,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('converts the response', () => {
|
||||||
|
const agg = aggConfigs.getResponseAggs()[0];
|
||||||
|
|
||||||
|
expect(
|
||||||
|
agg.getValue({
|
||||||
|
'filtered_metric-bucket': {
|
||||||
|
'filtered_metric-metric': {
|
||||||
|
value: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).toEqual(10);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { MetricAggType } from './metric_agg_type';
|
||||||
|
import { makeNestedLabel } from './lib/make_nested_label';
|
||||||
|
import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper';
|
||||||
|
import { METRIC_TYPES } from './metric_agg_types';
|
||||||
|
import { AggConfigSerialized, BaseAggParams } from '../types';
|
||||||
|
import { aggFilteredMetricFnName } from './filtered_metric_fn';
|
||||||
|
|
||||||
|
export interface AggParamsFilteredMetric extends BaseAggParams {
|
||||||
|
customMetric?: AggConfigSerialized;
|
||||||
|
customBucket?: AggConfigSerialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredMetricLabel = i18n.translate('data.search.aggs.metrics.filteredMetricLabel', {
|
||||||
|
defaultMessage: 'filtered',
|
||||||
|
});
|
||||||
|
|
||||||
|
const filteredMetricTitle = i18n.translate('data.search.aggs.metrics.filteredMetricTitle', {
|
||||||
|
defaultMessage: 'Filtered metric',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getFilteredMetricAgg = () => {
|
||||||
|
const { subtype, params, getSerializedFormat } = siblingPipelineAggHelper;
|
||||||
|
|
||||||
|
return new MetricAggType({
|
||||||
|
name: METRIC_TYPES.FILTERED_METRIC,
|
||||||
|
expressionName: aggFilteredMetricFnName,
|
||||||
|
title: filteredMetricTitle,
|
||||||
|
makeLabel: (agg) => makeNestedLabel(agg, filteredMetricLabel),
|
||||||
|
subtype,
|
||||||
|
params: [...params(['filter'])],
|
||||||
|
hasNoDslParams: true,
|
||||||
|
getSerializedFormat,
|
||||||
|
getValue(agg, bucket) {
|
||||||
|
const customMetric = agg.getParam('customMetric');
|
||||||
|
const customBucket = agg.getParam('customBucket');
|
||||||
|
return customMetric.getValue(bucket[customBucket.id]);
|
||||||
|
},
|
||||||
|
getValueBucketPath(agg) {
|
||||||
|
const customBucket = agg.getParam('customBucket');
|
||||||
|
const customMetric = agg.getParam('customMetric');
|
||||||
|
if (customMetric.type.name === 'count') {
|
||||||
|
return customBucket.getValueBucketPath();
|
||||||
|
}
|
||||||
|
return `${customBucket.getValueBucketPath()}>${customMetric.getValueBucketPath()}`;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { functionWrapper } from '../test_helpers';
|
||||||
|
import { aggFilteredMetric } from './filtered_metric_fn';
|
||||||
|
|
||||||
|
describe('agg_expression_functions', () => {
|
||||||
|
describe('aggFilteredMetric', () => {
|
||||||
|
const fn = functionWrapper(aggFilteredMetric());
|
||||||
|
|
||||||
|
test('handles customMetric and customBucket as a subexpression', () => {
|
||||||
|
const actual = fn({
|
||||||
|
customMetric: fn({}),
|
||||||
|
customBucket: fn({}),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(actual.value.params).toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"customBucket": Object {
|
||||||
|
"enabled": true,
|
||||||
|
"id": undefined,
|
||||||
|
"params": Object {
|
||||||
|
"customBucket": undefined,
|
||||||
|
"customLabel": undefined,
|
||||||
|
"customMetric": undefined,
|
||||||
|
},
|
||||||
|
"schema": undefined,
|
||||||
|
"type": "filtered_metric",
|
||||||
|
},
|
||||||
|
"customLabel": undefined,
|
||||||
|
"customMetric": Object {
|
||||||
|
"enabled": true,
|
||||||
|
"id": undefined,
|
||||||
|
"params": Object {
|
||||||
|
"customBucket": undefined,
|
||||||
|
"customLabel": undefined,
|
||||||
|
"customMetric": undefined,
|
||||||
|
},
|
||||||
|
"schema": undefined,
|
||||||
|
"type": "filtered_metric",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { Assign } from '@kbn/utility-types';
|
||||||
|
import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common';
|
||||||
|
import { AggExpressionType, AggExpressionFunctionArgs, METRIC_TYPES } from '../';
|
||||||
|
|
||||||
|
export const aggFilteredMetricFnName = 'aggFilteredMetric';
|
||||||
|
|
||||||
|
type Input = any;
|
||||||
|
type AggArgs = AggExpressionFunctionArgs<typeof METRIC_TYPES.FILTERED_METRIC>;
|
||||||
|
type Arguments = Assign<
|
||||||
|
AggArgs,
|
||||||
|
{ customBucket?: AggExpressionType; customMetric?: AggExpressionType }
|
||||||
|
>;
|
||||||
|
type Output = AggExpressionType;
|
||||||
|
type FunctionDefinition = ExpressionFunctionDefinition<
|
||||||
|
typeof aggFilteredMetricFnName,
|
||||||
|
Input,
|
||||||
|
Arguments,
|
||||||
|
Output
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const aggFilteredMetric = (): FunctionDefinition => ({
|
||||||
|
name: aggFilteredMetricFnName,
|
||||||
|
help: i18n.translate('data.search.aggs.function.metrics.filtered_metric.help', {
|
||||||
|
defaultMessage: 'Generates a serialized agg config for a filtered metric agg',
|
||||||
|
}),
|
||||||
|
type: 'agg_type',
|
||||||
|
args: {
|
||||||
|
id: {
|
||||||
|
types: ['string'],
|
||||||
|
help: i18n.translate('data.search.aggs.metrics.filtered_metric.id.help', {
|
||||||
|
defaultMessage: 'ID for this aggregation',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
enabled: {
|
||||||
|
types: ['boolean'],
|
||||||
|
default: true,
|
||||||
|
help: i18n.translate('data.search.aggs.metrics.filtered_metric.enabled.help', {
|
||||||
|
defaultMessage: 'Specifies whether this aggregation should be enabled',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
types: ['string'],
|
||||||
|
help: i18n.translate('data.search.aggs.metrics.filtered_metric.schema.help', {
|
||||||
|
defaultMessage: 'Schema to use for this aggregation',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
customBucket: {
|
||||||
|
types: ['agg_type'],
|
||||||
|
help: i18n.translate('data.search.aggs.metrics.filtered_metric.customBucket.help', {
|
||||||
|
defaultMessage:
|
||||||
|
'Agg config to use for building sibling pipeline aggregations. Has to be a filter aggregation',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
customMetric: {
|
||||||
|
types: ['agg_type'],
|
||||||
|
help: i18n.translate('data.search.aggs.metrics.filtered_metric.customMetric.help', {
|
||||||
|
defaultMessage: 'Agg config to use for building sibling pipeline aggregations',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
customLabel: {
|
||||||
|
types: ['string'],
|
||||||
|
help: i18n.translate('data.search.aggs.metrics.filtered_metric.customLabel.help', {
|
||||||
|
defaultMessage: 'Represents a custom label for this aggregation',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fn: (input, args) => {
|
||||||
|
const { id, enabled, schema, ...rest } = args;
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'agg_type',
|
||||||
|
value: {
|
||||||
|
id,
|
||||||
|
enabled,
|
||||||
|
schema,
|
||||||
|
type: METRIC_TYPES.FILTERED_METRIC,
|
||||||
|
params: {
|
||||||
|
...rest,
|
||||||
|
customBucket: args.customBucket?.value,
|
||||||
|
customMetric: args.customMetric?.value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -16,6 +16,8 @@ export * from './bucket_min_fn';
|
||||||
export * from './bucket_min';
|
export * from './bucket_min';
|
||||||
export * from './bucket_sum_fn';
|
export * from './bucket_sum_fn';
|
||||||
export * from './bucket_sum';
|
export * from './bucket_sum';
|
||||||
|
export * from './filtered_metric_fn';
|
||||||
|
export * from './filtered_metric';
|
||||||
export * from './cardinality_fn';
|
export * from './cardinality_fn';
|
||||||
export * from './cardinality';
|
export * from './cardinality';
|
||||||
export * from './count';
|
export * from './count';
|
||||||
|
|
|
@ -21,6 +21,7 @@ const metricAggFilter = [
|
||||||
'!std_dev',
|
'!std_dev',
|
||||||
'!geo_bounds',
|
'!geo_bounds',
|
||||||
'!geo_centroid',
|
'!geo_centroid',
|
||||||
|
'!filtered_metric',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const parentPipelineType = i18n.translate(
|
export const parentPipelineType = i18n.translate(
|
||||||
|
|
|
@ -27,6 +27,7 @@ const metricAggFilter: string[] = [
|
||||||
'!cumulative_sum',
|
'!cumulative_sum',
|
||||||
'!geo_bounds',
|
'!geo_bounds',
|
||||||
'!geo_centroid',
|
'!geo_centroid',
|
||||||
|
'!filtered_metric',
|
||||||
];
|
];
|
||||||
const bucketAggFilter: string[] = [];
|
const bucketAggFilter: string[] = [];
|
||||||
|
|
||||||
|
@ -39,12 +40,12 @@ export const siblingPipelineType = i18n.translate(
|
||||||
|
|
||||||
export const siblingPipelineAggHelper = {
|
export const siblingPipelineAggHelper = {
|
||||||
subtype: siblingPipelineType,
|
subtype: siblingPipelineType,
|
||||||
params() {
|
params(bucketFilter = bucketAggFilter) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
name: 'customBucket',
|
name: 'customBucket',
|
||||||
type: 'agg',
|
type: 'agg',
|
||||||
allowedAggs: bucketAggFilter,
|
allowedAggs: bucketFilter,
|
||||||
default: null,
|
default: null,
|
||||||
makeAgg(agg: IMetricAggConfig, state = { type: 'date_histogram' }) {
|
makeAgg(agg: IMetricAggConfig, state = { type: 'date_histogram' }) {
|
||||||
const orderAgg = agg.aggConfigs.createAggConfig(state, { addToAggConfigs: false });
|
const orderAgg = agg.aggConfigs.createAggConfig(state, { addToAggConfigs: false });
|
||||||
|
@ -69,7 +70,8 @@ export const siblingPipelineAggHelper = {
|
||||||
modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart(
|
modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart(
|
||||||
'customMetric'
|
'customMetric'
|
||||||
),
|
),
|
||||||
write: siblingPipelineAggWriter,
|
write: (agg: IMetricAggConfig, output: Record<string, any>) =>
|
||||||
|
siblingPipelineAggWriter(agg, output),
|
||||||
},
|
},
|
||||||
] as Array<MetricAggParam<IMetricAggConfig>>;
|
] as Array<MetricAggParam<IMetricAggConfig>>;
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
export enum METRIC_TYPES {
|
export enum METRIC_TYPES {
|
||||||
AVG = 'avg',
|
AVG = 'avg',
|
||||||
|
FILTERED_METRIC = 'filtered_metric',
|
||||||
CARDINALITY = 'cardinality',
|
CARDINALITY = 'cardinality',
|
||||||
AVG_BUCKET = 'avg_bucket',
|
AVG_BUCKET = 'avg_bucket',
|
||||||
MAX_BUCKET = 'max_bucket',
|
MAX_BUCKET = 'max_bucket',
|
||||||
|
|
|
@ -41,6 +41,7 @@ import {
|
||||||
AggParamsBucketMax,
|
AggParamsBucketMax,
|
||||||
AggParamsBucketMin,
|
AggParamsBucketMin,
|
||||||
AggParamsBucketSum,
|
AggParamsBucketSum,
|
||||||
|
AggParamsFilteredMetric,
|
||||||
AggParamsCardinality,
|
AggParamsCardinality,
|
||||||
AggParamsCumulativeSum,
|
AggParamsCumulativeSum,
|
||||||
AggParamsDateHistogram,
|
AggParamsDateHistogram,
|
||||||
|
@ -84,6 +85,7 @@ import {
|
||||||
getCalculateAutoTimeExpression,
|
getCalculateAutoTimeExpression,
|
||||||
METRIC_TYPES,
|
METRIC_TYPES,
|
||||||
AggConfig,
|
AggConfig,
|
||||||
|
aggFilteredMetric,
|
||||||
} from './';
|
} from './';
|
||||||
|
|
||||||
export { IAggConfig, AggConfigSerialized } from './agg_config';
|
export { IAggConfig, AggConfigSerialized } from './agg_config';
|
||||||
|
@ -188,6 +190,7 @@ export interface AggParamsMapping {
|
||||||
[METRIC_TYPES.MAX_BUCKET]: AggParamsBucketMax;
|
[METRIC_TYPES.MAX_BUCKET]: AggParamsBucketMax;
|
||||||
[METRIC_TYPES.MIN_BUCKET]: AggParamsBucketMin;
|
[METRIC_TYPES.MIN_BUCKET]: AggParamsBucketMin;
|
||||||
[METRIC_TYPES.SUM_BUCKET]: AggParamsBucketSum;
|
[METRIC_TYPES.SUM_BUCKET]: AggParamsBucketSum;
|
||||||
|
[METRIC_TYPES.FILTERED_METRIC]: AggParamsFilteredMetric;
|
||||||
[METRIC_TYPES.CUMULATIVE_SUM]: AggParamsCumulativeSum;
|
[METRIC_TYPES.CUMULATIVE_SUM]: AggParamsCumulativeSum;
|
||||||
[METRIC_TYPES.DERIVATIVE]: AggParamsDerivative;
|
[METRIC_TYPES.DERIVATIVE]: AggParamsDerivative;
|
||||||
[METRIC_TYPES.MOVING_FN]: AggParamsMovingAvg;
|
[METRIC_TYPES.MOVING_FN]: AggParamsMovingAvg;
|
||||||
|
@ -217,6 +220,7 @@ export interface AggFunctionsMapping {
|
||||||
aggBucketMax: ReturnType<typeof aggBucketMax>;
|
aggBucketMax: ReturnType<typeof aggBucketMax>;
|
||||||
aggBucketMin: ReturnType<typeof aggBucketMin>;
|
aggBucketMin: ReturnType<typeof aggBucketMin>;
|
||||||
aggBucketSum: ReturnType<typeof aggBucketSum>;
|
aggBucketSum: ReturnType<typeof aggBucketSum>;
|
||||||
|
aggFilteredMetric: ReturnType<typeof aggFilteredMetric>;
|
||||||
aggCardinality: ReturnType<typeof aggCardinality>;
|
aggCardinality: ReturnType<typeof aggCardinality>;
|
||||||
aggCount: ReturnType<typeof aggCount>;
|
aggCount: ReturnType<typeof aggCount>;
|
||||||
aggCumulativeSum: ReturnType<typeof aggCumulativeSum>;
|
aggCumulativeSum: ReturnType<typeof aggCumulativeSum>;
|
||||||
|
|
|
@ -329,6 +329,10 @@ export interface AggFunctionsMapping {
|
||||||
//
|
//
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
aggFilter: ReturnType<typeof aggFilter>;
|
aggFilter: ReturnType<typeof aggFilter>;
|
||||||
|
// Warning: (ae-forgotten-export) The symbol "aggFilteredMetric" needs to be exported by the entry point index.d.ts
|
||||||
|
//
|
||||||
|
// (undocumented)
|
||||||
|
aggFilteredMetric: ReturnType<typeof aggFilteredMetric>;
|
||||||
// Warning: (ae-forgotten-export) The symbol "aggFilters" needs to be exported by the entry point index.d.ts
|
// Warning: (ae-forgotten-export) The symbol "aggFilters" needs to be exported by the entry point index.d.ts
|
||||||
//
|
//
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -711,7 +715,7 @@ export const ES_SEARCH_STRATEGY = "es";
|
||||||
// Warning: (ae-missing-release-tag) "EsaggsExpressionFunctionDefinition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "EsaggsExpressionFunctionDefinition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export type EsaggsExpressionFunctionDefinition = ExpressionFunctionDefinition<'esaggs', Input_34, Arguments_20, Output_34>;
|
export type EsaggsExpressionFunctionDefinition = ExpressionFunctionDefinition<'esaggs', Input_35, Arguments_21, Output_35>;
|
||||||
|
|
||||||
// Warning: (ae-forgotten-export) The symbol "name" needs to be exported by the entry point index.d.ts
|
// Warning: (ae-forgotten-export) The symbol "name" needs to be exported by the entry point index.d.ts
|
||||||
// Warning: (ae-forgotten-export) The symbol "Input" needs to be exported by the entry point index.d.ts
|
// Warning: (ae-forgotten-export) The symbol "Input" needs to be exported by the entry point index.d.ts
|
||||||
|
@ -720,7 +724,7 @@ export type EsaggsExpressionFunctionDefinition = ExpressionFunctionDefinition<'e
|
||||||
// Warning: (ae-missing-release-tag) "EsdslExpressionFunctionDefinition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "EsdslExpressionFunctionDefinition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export type EsdslExpressionFunctionDefinition = ExpressionFunctionDefinition_2<typeof name_3, Input_35, Arguments_22, Output_35>;
|
export type EsdslExpressionFunctionDefinition = ExpressionFunctionDefinition_2<typeof name_3, Input_36, Arguments_23, Output_36>;
|
||||||
|
|
||||||
// Warning: (ae-missing-release-tag) "esFilters" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "esFilters" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
|
@ -861,7 +865,7 @@ export type ExpressionFunctionKibana = ExpressionFunctionDefinition<'kibana', Ex
|
||||||
// Warning: (ae-missing-release-tag) "ExpressionFunctionKibanaContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "ExpressionFunctionKibanaContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export type ExpressionFunctionKibanaContext = ExpressionFunctionDefinition<'kibana_context', KibanaContext | null, Arguments_21, Promise<KibanaContext>, ExecutionContext<Adapters_2, ExecutionContextSearch>>;
|
export type ExpressionFunctionKibanaContext = ExpressionFunctionDefinition<'kibana_context', KibanaContext | null, Arguments_22, Promise<KibanaContext>, ExecutionContext<Adapters_2, ExecutionContextSearch>>;
|
||||||
|
|
||||||
// Warning: (ae-missing-release-tag) "ExpressionValueSearchContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "ExpressionValueSearchContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
|
@ -1838,6 +1842,8 @@ export enum METRIC_TYPES {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
DERIVATIVE = "derivative",
|
DERIVATIVE = "derivative",
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
FILTERED_METRIC = "filtered_metric",
|
||||||
|
// (undocumented)
|
||||||
GEO_BOUNDS = "geo_bounds",
|
GEO_BOUNDS = "geo_bounds",
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
GEO_CENTROID = "geo_centroid",
|
GEO_CENTROID = "geo_centroid",
|
||||||
|
@ -2657,7 +2663,7 @@ export const UI_SETTINGS: {
|
||||||
// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:65:5 - (ae-forgotten-export) The symbol "FormatFieldFn" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:65:5 - (ae-forgotten-export) The symbol "FormatFieldFn" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:138:7 - (ae-forgotten-export) The symbol "FieldAttrSet" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:138:7 - (ae-forgotten-export) The symbol "FieldAttrSet" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:169:7 - (ae-forgotten-export) The symbol "RuntimeField" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts:169:7 - (ae-forgotten-export) The symbol "RuntimeField" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/common/search/aggs/types.ts:139:51 - (ae-forgotten-export) The symbol "AggTypesRegistryStart" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/common/search/aggs/types.ts:141:51 - (ae-forgotten-export) The symbol "AggTypesRegistryStart" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/field_formats/field_formats_service.ts:56:3 - (ae-forgotten-export) The symbol "FormatFactory" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/field_formats/field_formats_service.ts:56:3 - (ae-forgotten-export) The symbol "FormatFactory" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:56:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:56:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:56:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:56:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts
|
||||||
|
|
|
@ -54,7 +54,7 @@ describe('AggsService - public', () => {
|
||||||
service.setup(setupDeps);
|
service.setup(setupDeps);
|
||||||
const start = service.start(startDeps);
|
const start = service.start(startDeps);
|
||||||
expect(start.types.getAll().buckets.length).toBe(11);
|
expect(start.types.getAll().buckets.length).toBe(11);
|
||||||
expect(start.types.getAll().metrics.length).toBe(21);
|
expect(start.types.getAll().metrics.length).toBe(22);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('registers custom agg types', () => {
|
test('registers custom agg types', () => {
|
||||||
|
@ -71,7 +71,7 @@ describe('AggsService - public', () => {
|
||||||
const start = service.start(startDeps);
|
const start = service.start(startDeps);
|
||||||
expect(start.types.getAll().buckets.length).toBe(12);
|
expect(start.types.getAll().buckets.length).toBe(12);
|
||||||
expect(start.types.getAll().buckets.some(({ name }) => name === 'foo')).toBe(true);
|
expect(start.types.getAll().buckets.some(({ name }) => name === 'foo')).toBe(true);
|
||||||
expect(start.types.getAll().metrics.length).toBe(22);
|
expect(start.types.getAll().metrics.length).toBe(23);
|
||||||
expect(start.types.getAll().metrics.some(({ name }) => name === 'bar')).toBe(true);
|
expect(start.types.getAll().metrics.some(({ name }) => name === 'bar')).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -134,6 +134,10 @@ export interface AggFunctionsMapping {
|
||||||
//
|
//
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
aggFilter: ReturnType<typeof aggFilter>;
|
aggFilter: ReturnType<typeof aggFilter>;
|
||||||
|
// Warning: (ae-forgotten-export) The symbol "aggFilteredMetric" needs to be exported by the entry point index.d.ts
|
||||||
|
//
|
||||||
|
// (undocumented)
|
||||||
|
aggFilteredMetric: ReturnType<typeof aggFilteredMetric>;
|
||||||
// Warning: (ae-forgotten-export) The symbol "aggFilters" needs to be exported by the entry point index.d.ts
|
// Warning: (ae-forgotten-export) The symbol "aggFilters" needs to be exported by the entry point index.d.ts
|
||||||
//
|
//
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -405,7 +409,7 @@ export const ES_SEARCH_STRATEGY = "es";
|
||||||
// Warning: (ae-missing-release-tag) "EsaggsExpressionFunctionDefinition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "EsaggsExpressionFunctionDefinition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export type EsaggsExpressionFunctionDefinition = ExpressionFunctionDefinition<'esaggs', Input_34, Arguments_20, Output_34>;
|
export type EsaggsExpressionFunctionDefinition = ExpressionFunctionDefinition<'esaggs', Input_35, Arguments_21, Output_35>;
|
||||||
|
|
||||||
// Warning: (ae-missing-release-tag) "esFilters" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "esFilters" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
|
@ -485,7 +489,7 @@ export type ExpressionFunctionKibana = ExpressionFunctionDefinition<'kibana', Ex
|
||||||
// Warning: (ae-missing-release-tag) "ExpressionFunctionKibanaContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "ExpressionFunctionKibanaContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export type ExpressionFunctionKibanaContext = ExpressionFunctionDefinition<'kibana_context', KibanaContext | null, Arguments_21, Promise<KibanaContext>, ExecutionContext<Adapters, ExecutionContextSearch>>;
|
export type ExpressionFunctionKibanaContext = ExpressionFunctionDefinition<'kibana_context', KibanaContext | null, Arguments_22, Promise<KibanaContext>, ExecutionContext<Adapters, ExecutionContextSearch>>;
|
||||||
|
|
||||||
// Warning: (ae-missing-release-tag) "ExpressionValueSearchContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "ExpressionValueSearchContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
|
@ -1147,6 +1151,8 @@ export enum METRIC_TYPES {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
DERIVATIVE = "derivative",
|
DERIVATIVE = "derivative",
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
FILTERED_METRIC = "filtered_metric",
|
||||||
|
// (undocumented)
|
||||||
GEO_BOUNDS = "geo_bounds",
|
GEO_BOUNDS = "geo_bounds",
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
GEO_CENTROID = "geo_centroid",
|
GEO_CENTROID = "geo_centroid",
|
||||||
|
|
|
@ -63,6 +63,7 @@ export const createMetricVisTypeDefinition = (): VisTypeDefinition<VisParams> =>
|
||||||
'!moving_avg',
|
'!moving_avg',
|
||||||
'!cumulative_sum',
|
'!cumulative_sum',
|
||||||
'!geo_bounds',
|
'!geo_bounds',
|
||||||
|
'!filtered_metric',
|
||||||
],
|
],
|
||||||
aggSettings: {
|
aggSettings: {
|
||||||
top_hits: {
|
top_hits: {
|
||||||
|
|
|
@ -50,7 +50,7 @@ export const tableVisLegacyTypeDefinition: VisTypeDefinition<TableVisParams> = {
|
||||||
title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.metricTitle', {
|
title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.metricTitle', {
|
||||||
defaultMessage: 'Metric',
|
defaultMessage: 'Metric',
|
||||||
}),
|
}),
|
||||||
aggFilter: ['!geo_centroid', '!geo_bounds'],
|
aggFilter: ['!geo_centroid', '!geo_bounds', '!filtered_metric'],
|
||||||
aggSettings: {
|
aggSettings: {
|
||||||
top_hits: {
|
top_hits: {
|
||||||
allowStrings: true,
|
allowStrings: true,
|
||||||
|
|
|
@ -46,7 +46,7 @@ export const tableVisTypeDefinition: VisTypeDefinition<TableVisParams> = {
|
||||||
title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.metricTitle', {
|
title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.metricTitle', {
|
||||||
defaultMessage: 'Metric',
|
defaultMessage: 'Metric',
|
||||||
}),
|
}),
|
||||||
aggFilter: ['!geo_centroid', '!geo_bounds'],
|
aggFilter: ['!geo_centroid', '!geo_bounds', '!filtered_metric'],
|
||||||
aggSettings: {
|
aggSettings: {
|
||||||
top_hits: {
|
top_hits: {
|
||||||
allowStrings: true,
|
allowStrings: true,
|
||||||
|
|
|
@ -51,6 +51,7 @@ export const tagCloudVisTypeDefinition = {
|
||||||
'!derivative',
|
'!derivative',
|
||||||
'!geo_bounds',
|
'!geo_bounds',
|
||||||
'!geo_centroid',
|
'!geo_centroid',
|
||||||
|
'!filtered_metric',
|
||||||
],
|
],
|
||||||
defaults: [{ schema: 'metric', type: 'count' }],
|
defaults: [{ schema: 'metric', type: 'count' }],
|
||||||
},
|
},
|
||||||
|
|
|
@ -119,6 +119,7 @@ export const gaugeVisTypeDefinition: VisTypeDefinition<GaugeVisParams> = {
|
||||||
'!moving_avg',
|
'!moving_avg',
|
||||||
'!cumulative_sum',
|
'!cumulative_sum',
|
||||||
'!geo_bounds',
|
'!geo_bounds',
|
||||||
|
'!filtered_metric',
|
||||||
],
|
],
|
||||||
defaults: [{ schema: 'metric', type: 'count' }],
|
defaults: [{ schema: 'metric', type: 'count' }],
|
||||||
},
|
},
|
||||||
|
|
|
@ -83,6 +83,7 @@ export const goalVisTypeDefinition: VisTypeDefinition<GaugeVisParams> = {
|
||||||
'!moving_avg',
|
'!moving_avg',
|
||||||
'!cumulative_sum',
|
'!cumulative_sum',
|
||||||
'!geo_bounds',
|
'!geo_bounds',
|
||||||
|
'!filtered_metric',
|
||||||
],
|
],
|
||||||
defaults: [{ schema: 'metric', type: 'count' }],
|
defaults: [{ schema: 'metric', type: 'count' }],
|
||||||
},
|
},
|
||||||
|
|
|
@ -94,6 +94,7 @@ export const heatmapVisTypeDefinition: VisTypeDefinition<HeatmapVisParams> = {
|
||||||
'cardinality',
|
'cardinality',
|
||||||
'std_dev',
|
'std_dev',
|
||||||
'top_hits',
|
'top_hits',
|
||||||
|
'!filtered_metric',
|
||||||
],
|
],
|
||||||
defaults: [{ schema: 'metric', type: 'count' }],
|
defaults: [{ schema: 'metric', type: 'count' }],
|
||||||
},
|
},
|
||||||
|
|
|
@ -133,7 +133,7 @@ export const getAreaVisTypeDefinition = (
|
||||||
title: i18n.translate('visTypeXy.area.metricsTitle', {
|
title: i18n.translate('visTypeXy.area.metricsTitle', {
|
||||||
defaultMessage: 'Y-axis',
|
defaultMessage: 'Y-axis',
|
||||||
}),
|
}),
|
||||||
aggFilter: ['!geo_centroid', '!geo_bounds'],
|
aggFilter: ['!geo_centroid', '!geo_bounds', '!filtered_metric'],
|
||||||
min: 1,
|
min: 1,
|
||||||
defaults: [{ schema: 'metric', type: 'count' }],
|
defaults: [{ schema: 'metric', type: 'count' }],
|
||||||
},
|
},
|
||||||
|
|
|
@ -137,7 +137,7 @@ export const getHistogramVisTypeDefinition = (
|
||||||
defaultMessage: 'Y-axis',
|
defaultMessage: 'Y-axis',
|
||||||
}),
|
}),
|
||||||
min: 1,
|
min: 1,
|
||||||
aggFilter: ['!geo_centroid', '!geo_bounds'],
|
aggFilter: ['!geo_centroid', '!geo_bounds', '!filtered_metric'],
|
||||||
defaults: [{ schema: 'metric', type: 'count' }],
|
defaults: [{ schema: 'metric', type: 'count' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -136,7 +136,7 @@ export const getHorizontalBarVisTypeDefinition = (
|
||||||
defaultMessage: 'Y-axis',
|
defaultMessage: 'Y-axis',
|
||||||
}),
|
}),
|
||||||
min: 1,
|
min: 1,
|
||||||
aggFilter: ['!geo_centroid', '!geo_bounds'],
|
aggFilter: ['!geo_centroid', '!geo_bounds', '!filtered_metric'],
|
||||||
defaults: [{ schema: 'metric', type: 'count' }],
|
defaults: [{ schema: 'metric', type: 'count' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -132,7 +132,7 @@ export const getLineVisTypeDefinition = (
|
||||||
name: 'metric',
|
name: 'metric',
|
||||||
title: i18n.translate('visTypeXy.line.metricTitle', { defaultMessage: 'Y-axis' }),
|
title: i18n.translate('visTypeXy.line.metricTitle', { defaultMessage: 'Y-axis' }),
|
||||||
min: 1,
|
min: 1,
|
||||||
aggFilter: ['!geo_centroid', '!geo_bounds'],
|
aggFilter: ['!geo_centroid', '!geo_bounds', '!filtered_metric'],
|
||||||
defaults: [{ schema: 'metric', type: 'count' }],
|
defaults: [{ schema: 'metric', type: 'count' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
|
* 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { EuiLink, EuiText, EuiPopover, EuiButtonEmpty, EuiSpacer } from '@elastic/eui';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export function AdvancedOptions(props: {
|
||||||
|
options: Array<{
|
||||||
|
title: string;
|
||||||
|
dataTestSubj: string;
|
||||||
|
onClick: () => void;
|
||||||
|
showInPopover: boolean;
|
||||||
|
inlineElement: React.ReactElement | null;
|
||||||
|
}>;
|
||||||
|
}) {
|
||||||
|
const [popoverOpen, setPopoverOpen] = useState(false);
|
||||||
|
const popoverOptions = props.options.filter((option) => option.showInPopover);
|
||||||
|
const inlineOptions = props.options
|
||||||
|
.filter((option) => option.inlineElement)
|
||||||
|
.map((option) => React.cloneElement(option.inlineElement!, { key: option.dataTestSubj }));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{popoverOptions.length > 0 && (
|
||||||
|
<EuiText textAlign="right">
|
||||||
|
<EuiSpacer size="s" />
|
||||||
|
<EuiPopover
|
||||||
|
ownFocus
|
||||||
|
button={
|
||||||
|
<EuiButtonEmpty
|
||||||
|
size="xs"
|
||||||
|
iconType="arrowDown"
|
||||||
|
iconSide="right"
|
||||||
|
data-test-subj="indexPattern-advanced-popover"
|
||||||
|
onClick={() => {
|
||||||
|
setPopoverOpen(!popoverOpen);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18n.translate('xpack.lens.indexPattern.advancedSettings', {
|
||||||
|
defaultMessage: 'Add advanced options',
|
||||||
|
})}
|
||||||
|
</EuiButtonEmpty>
|
||||||
|
}
|
||||||
|
isOpen={popoverOpen}
|
||||||
|
closePopover={() => {
|
||||||
|
setPopoverOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{popoverOptions.map(({ dataTestSubj, onClick, title }, index) => (
|
||||||
|
<React.Fragment key={dataTestSubj}>
|
||||||
|
<EuiText size="s">
|
||||||
|
<EuiLink
|
||||||
|
data-test-subj={dataTestSubj}
|
||||||
|
color="text"
|
||||||
|
onClick={() => {
|
||||||
|
setPopoverOpen(false);
|
||||||
|
onClick();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</EuiLink>
|
||||||
|
</EuiText>
|
||||||
|
{popoverOptions.length - 1 !== index && <EuiSpacer size="s" />}
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</EuiPopover>
|
||||||
|
</EuiText>
|
||||||
|
)}
|
||||||
|
{inlineOptions.length > 0 && (
|
||||||
|
<>
|
||||||
|
<EuiSpacer size="s" />
|
||||||
|
{inlineOptions}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ import {
|
||||||
resetIncomplete,
|
resetIncomplete,
|
||||||
FieldBasedIndexPatternColumn,
|
FieldBasedIndexPatternColumn,
|
||||||
canTransition,
|
canTransition,
|
||||||
|
DEFAULT_TIME_SCALE,
|
||||||
} from '../operations';
|
} from '../operations';
|
||||||
import { mergeLayer } from '../state_helpers';
|
import { mergeLayer } from '../state_helpers';
|
||||||
import { FieldSelect } from './field_select';
|
import { FieldSelect } from './field_select';
|
||||||
|
@ -41,7 +42,9 @@ import { IndexPattern, IndexPatternLayer } from '../types';
|
||||||
import { trackUiEvent } from '../../lens_ui_telemetry';
|
import { trackUiEvent } from '../../lens_ui_telemetry';
|
||||||
import { FormatSelector } from './format_selector';
|
import { FormatSelector } from './format_selector';
|
||||||
import { ReferenceEditor } from './reference_editor';
|
import { ReferenceEditor } from './reference_editor';
|
||||||
import { TimeScaling } from './time_scaling';
|
import { setTimeScaling, TimeScaling } from './time_scaling';
|
||||||
|
import { defaultFilter, Filtering, setFilter } from './filtering';
|
||||||
|
import { AdvancedOptions } from './advanced_options';
|
||||||
|
|
||||||
const operationPanels = getOperationDisplay();
|
const operationPanels = getOperationDisplay();
|
||||||
|
|
||||||
|
@ -156,6 +159,8 @@ export function DimensionEditor(props: DimensionEditorProps) {
|
||||||
.filter((type) => fieldByOperation[type]?.size || operationWithoutField.has(type));
|
.filter((type) => fieldByOperation[type]?.size || operationWithoutField.has(type));
|
||||||
}, [fieldByOperation, operationWithoutField]);
|
}, [fieldByOperation, operationWithoutField]);
|
||||||
|
|
||||||
|
const [filterByOpenInitially, setFilterByOpenInitally] = useState(false);
|
||||||
|
|
||||||
// Operations are compatible if they match inputs. They are always compatible in
|
// Operations are compatible if they match inputs. They are always compatible in
|
||||||
// the empty state. Field-based operations are not compatible with field-less operations.
|
// the empty state. Field-based operations are not compatible with field-less operations.
|
||||||
const operationsWithCompatibility = [...possibleOperations].map((operationType) => {
|
const operationsWithCompatibility = [...possibleOperations].map((operationType) => {
|
||||||
|
@ -458,11 +463,63 @@ export function DimensionEditor(props: DimensionEditorProps) {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!currentFieldIsInvalid && !incompleteInfo && selectedColumn && (
|
{!currentFieldIsInvalid && !incompleteInfo && selectedColumn && (
|
||||||
<TimeScaling
|
<AdvancedOptions
|
||||||
selectedColumn={selectedColumn}
|
options={[
|
||||||
columnId={columnId}
|
{
|
||||||
layer={state.layers[layerId]}
|
title: i18n.translate('xpack.lens.indexPattern.timeScale.enableTimeScale', {
|
||||||
updateLayer={setStateWrapper}
|
defaultMessage: 'Normalize by unit',
|
||||||
|
}),
|
||||||
|
dataTestSubj: 'indexPattern-time-scaling-enable',
|
||||||
|
onClick: () => {
|
||||||
|
setStateWrapper(
|
||||||
|
setTimeScaling(columnId, state.layers[layerId], DEFAULT_TIME_SCALE)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
showInPopover: Boolean(
|
||||||
|
operationDefinitionMap[selectedColumn.operationType].timeScalingMode &&
|
||||||
|
operationDefinitionMap[selectedColumn.operationType].timeScalingMode !==
|
||||||
|
'disabled' &&
|
||||||
|
Object.values(state.layers[layerId].columns).some(
|
||||||
|
(col) => col.operationType === 'date_histogram'
|
||||||
|
) &&
|
||||||
|
!selectedColumn.timeScale
|
||||||
|
),
|
||||||
|
inlineElement: (
|
||||||
|
<TimeScaling
|
||||||
|
selectedColumn={selectedColumn}
|
||||||
|
columnId={columnId}
|
||||||
|
layer={state.layers[layerId]}
|
||||||
|
updateLayer={setStateWrapper}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.translate('xpack.lens.indexPattern.filterBy.label', {
|
||||||
|
defaultMessage: 'Filter by',
|
||||||
|
}),
|
||||||
|
dataTestSubj: 'indexPattern-filter-by-enable',
|
||||||
|
onClick: () => {
|
||||||
|
setFilterByOpenInitally(true);
|
||||||
|
setStateWrapper(setFilter(columnId, state.layers[layerId], defaultFilter));
|
||||||
|
},
|
||||||
|
showInPopover: Boolean(
|
||||||
|
operationDefinitionMap[selectedColumn.operationType].filterable &&
|
||||||
|
!selectedColumn.filter
|
||||||
|
),
|
||||||
|
inlineElement:
|
||||||
|
operationDefinitionMap[selectedColumn.operationType].filterable &&
|
||||||
|
selectedColumn.filter ? (
|
||||||
|
<Filtering
|
||||||
|
indexPattern={currentIndexPattern}
|
||||||
|
selectedColumn={selectedColumn}
|
||||||
|
columnId={columnId}
|
||||||
|
layer={state.layers[layerId]}
|
||||||
|
updateLayer={setStateWrapper}
|
||||||
|
isInitiallyOpen={filterByOpenInitially}
|
||||||
|
/>
|
||||||
|
) : null,
|
||||||
|
},
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ReactWrapper, ShallowWrapper } from 'enzyme';
|
import { ReactWrapper, ShallowWrapper } from 'enzyme';
|
||||||
import React, { ChangeEvent, MouseEvent } from 'react';
|
import React, { ChangeEvent, MouseEvent, ReactElement } from 'react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
import {
|
import {
|
||||||
EuiComboBox,
|
EuiComboBox,
|
||||||
|
@ -15,6 +15,7 @@ import {
|
||||||
EuiRange,
|
EuiRange,
|
||||||
EuiSelect,
|
EuiSelect,
|
||||||
EuiButtonIcon,
|
EuiButtonIcon,
|
||||||
|
EuiPopover,
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
import { DataPublicPluginStart } from '../../../../../../src/plugins/data/public';
|
import { DataPublicPluginStart } from '../../../../../../src/plugins/data/public';
|
||||||
import {
|
import {
|
||||||
|
@ -30,10 +31,14 @@ import { documentField } from '../document_field';
|
||||||
import { OperationMetadata } from '../../types';
|
import { OperationMetadata } from '../../types';
|
||||||
import { DateHistogramIndexPatternColumn } from '../operations/definitions/date_histogram';
|
import { DateHistogramIndexPatternColumn } from '../operations/definitions/date_histogram';
|
||||||
import { getFieldByNameFactory } from '../pure_helpers';
|
import { getFieldByNameFactory } from '../pure_helpers';
|
||||||
import { TimeScaling } from './time_scaling';
|
|
||||||
import { DimensionEditor } from './dimension_editor';
|
import { DimensionEditor } from './dimension_editor';
|
||||||
|
import { AdvancedOptions } from './advanced_options';
|
||||||
|
import { Filtering } from './filtering';
|
||||||
|
|
||||||
jest.mock('../loader');
|
jest.mock('../loader');
|
||||||
|
jest.mock('../query_input', () => ({
|
||||||
|
QueryInput: () => null,
|
||||||
|
}));
|
||||||
jest.mock('../operations');
|
jest.mock('../operations');
|
||||||
jest.mock('lodash', () => {
|
jest.mock('lodash', () => {
|
||||||
const original = jest.requireActual('lodash');
|
const original = jest.requireActual('lodash');
|
||||||
|
@ -1029,7 +1034,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should not show custom options if time scaling is not available', () => {
|
it('should not show custom options if time scaling is not available', () => {
|
||||||
wrapper = mount(
|
wrapper = shallow(
|
||||||
<IndexPatternDimensionEditorComponent
|
<IndexPatternDimensionEditorComponent
|
||||||
{...getProps({
|
{...getProps({
|
||||||
operationType: 'avg',
|
operationType: 'avg',
|
||||||
|
@ -1037,17 +1042,26 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
expect(wrapper.find('[data-test-subj="indexPattern-time-scaling"]')).toHaveLength(0);
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find(DimensionEditor)
|
||||||
|
.dive()
|
||||||
|
.find(AdvancedOptions)
|
||||||
|
.dive()
|
||||||
|
.find('[data-test-subj="indexPattern-time-scaling-enable"]')
|
||||||
|
).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show custom options if time scaling is available', () => {
|
it('should show custom options if time scaling is available', () => {
|
||||||
wrapper = mount(<IndexPatternDimensionEditorComponent {...getProps({})} />);
|
wrapper = shallow(<IndexPatternDimensionEditorComponent {...getProps({})} />);
|
||||||
expect(
|
expect(
|
||||||
wrapper
|
wrapper
|
||||||
.find(TimeScaling)
|
.find(DimensionEditor)
|
||||||
.find('[data-test-subj="indexPattern-time-scaling-popover"]')
|
.dive()
|
||||||
.exists()
|
.find(AdvancedOptions)
|
||||||
).toBe(true);
|
.dive()
|
||||||
|
.find('[data-test-subj="indexPattern-time-scaling-enable"]')
|
||||||
|
).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show current time scaling if set', () => {
|
it('should show current time scaling if set', () => {
|
||||||
|
@ -1066,7 +1080,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
||||||
wrapper
|
wrapper
|
||||||
.find(DimensionEditor)
|
.find(DimensionEditor)
|
||||||
.dive()
|
.dive()
|
||||||
.find(TimeScaling)
|
.find(AdvancedOptions)
|
||||||
.dive()
|
.dive()
|
||||||
.find('[data-test-subj="indexPattern-time-scaling-enable"]')
|
.find('[data-test-subj="indexPattern-time-scaling-enable"]')
|
||||||
.prop('onClick')!({} as MouseEvent);
|
.prop('onClick')!({} as MouseEvent);
|
||||||
|
@ -1239,6 +1253,199 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('filtering', () => {
|
||||||
|
function getProps(colOverrides: Partial<IndexPatternColumn>) {
|
||||||
|
return {
|
||||||
|
...defaultProps,
|
||||||
|
state: getStateWithColumns({
|
||||||
|
datecolumn: {
|
||||||
|
dataType: 'date',
|
||||||
|
isBucketed: true,
|
||||||
|
label: '',
|
||||||
|
customLabel: true,
|
||||||
|
operationType: 'date_histogram',
|
||||||
|
sourceField: 'ts',
|
||||||
|
params: {
|
||||||
|
interval: '1d',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
col2: {
|
||||||
|
dataType: 'number',
|
||||||
|
isBucketed: false,
|
||||||
|
label: 'Count of records',
|
||||||
|
operationType: 'count',
|
||||||
|
sourceField: 'Records',
|
||||||
|
...colOverrides,
|
||||||
|
} as IndexPatternColumn,
|
||||||
|
}),
|
||||||
|
columnId: 'col2',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should not show custom options if time scaling is not available', () => {
|
||||||
|
wrapper = shallow(
|
||||||
|
<IndexPatternDimensionEditorComponent
|
||||||
|
{...getProps({
|
||||||
|
operationType: 'terms',
|
||||||
|
sourceField: 'bytes',
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find(DimensionEditor)
|
||||||
|
.dive()
|
||||||
|
.find(AdvancedOptions)
|
||||||
|
.dive()
|
||||||
|
.find('[data-test-subj="indexPattern-filter-by-enable"]')
|
||||||
|
).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show custom options if filtering is available', () => {
|
||||||
|
wrapper = shallow(<IndexPatternDimensionEditorComponent {...getProps({})} />);
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find(DimensionEditor)
|
||||||
|
.dive()
|
||||||
|
.find(AdvancedOptions)
|
||||||
|
.dive()
|
||||||
|
.find('[data-test-subj="indexPattern-filter-by-enable"]')
|
||||||
|
).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show current filter if set', () => {
|
||||||
|
wrapper = mount(
|
||||||
|
<IndexPatternDimensionEditorComponent
|
||||||
|
{...getProps({ filter: { language: 'kuery', query: 'a: b' } })}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
(wrapper.find(Filtering).find(EuiPopover).prop('children') as ReactElement).props.value
|
||||||
|
).toEqual({ language: 'kuery', query: 'a: b' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow to set filter initially', () => {
|
||||||
|
const props = getProps({});
|
||||||
|
wrapper = shallow(<IndexPatternDimensionEditorComponent {...props} />);
|
||||||
|
wrapper
|
||||||
|
.find(DimensionEditor)
|
||||||
|
.dive()
|
||||||
|
.find(AdvancedOptions)
|
||||||
|
.dive()
|
||||||
|
.find('[data-test-subj="indexPattern-filter-by-enable"]')
|
||||||
|
.prop('onClick')!({} as MouseEvent);
|
||||||
|
expect(props.setState).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
|
...props.state,
|
||||||
|
layers: {
|
||||||
|
first: {
|
||||||
|
...props.state.layers.first,
|
||||||
|
columns: {
|
||||||
|
...props.state.layers.first.columns,
|
||||||
|
col2: expect.objectContaining({
|
||||||
|
filter: {
|
||||||
|
language: 'kuery',
|
||||||
|
query: '',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ shouldRemoveDimension: false, shouldReplaceDimension: true }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should carry over filter to other operation if possible', () => {
|
||||||
|
const props = getProps({
|
||||||
|
filter: { language: 'kuery', query: 'a: b' },
|
||||||
|
sourceField: 'bytes',
|
||||||
|
operationType: 'sum',
|
||||||
|
label: 'Sum of bytes per hour',
|
||||||
|
});
|
||||||
|
wrapper = mount(<IndexPatternDimensionEditorComponent {...props} />);
|
||||||
|
wrapper
|
||||||
|
.find('button[data-test-subj="lns-indexPatternDimension-count incompatible"]')
|
||||||
|
.simulate('click');
|
||||||
|
expect(props.setState).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
|
...props.state,
|
||||||
|
layers: {
|
||||||
|
first: {
|
||||||
|
...props.state.layers.first,
|
||||||
|
columns: {
|
||||||
|
...props.state.layers.first.columns,
|
||||||
|
col2: expect.objectContaining({
|
||||||
|
filter: { language: 'kuery', query: 'a: b' },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ shouldRemoveDimension: false, shouldReplaceDimension: true }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow to change filter', () => {
|
||||||
|
const props = getProps({
|
||||||
|
filter: { language: 'kuery', query: 'a: b' },
|
||||||
|
});
|
||||||
|
wrapper = mount(<IndexPatternDimensionEditorComponent {...props} />);
|
||||||
|
(wrapper.find(Filtering).find(EuiPopover).prop('children') as ReactElement).props.onChange({
|
||||||
|
language: 'kuery',
|
||||||
|
query: 'c: d',
|
||||||
|
});
|
||||||
|
expect(props.setState).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
|
...props.state,
|
||||||
|
layers: {
|
||||||
|
first: {
|
||||||
|
...props.state.layers.first,
|
||||||
|
columns: {
|
||||||
|
...props.state.layers.first.columns,
|
||||||
|
col2: expect.objectContaining({
|
||||||
|
filter: { language: 'kuery', query: 'c: d' },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ shouldRemoveDimension: false, shouldReplaceDimension: true }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow to remove filter', () => {
|
||||||
|
const props = getProps({
|
||||||
|
filter: { language: 'kuery', query: 'a: b' },
|
||||||
|
});
|
||||||
|
wrapper = mount(<IndexPatternDimensionEditorComponent {...props} />);
|
||||||
|
wrapper
|
||||||
|
.find('[data-test-subj="indexPattern-filter-by-remove"]')
|
||||||
|
.find(EuiButtonIcon)
|
||||||
|
.prop('onClick')!(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
{} as any
|
||||||
|
);
|
||||||
|
expect(props.setState).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
|
...props.state,
|
||||||
|
layers: {
|
||||||
|
first: {
|
||||||
|
...props.state.layers.first,
|
||||||
|
columns: {
|
||||||
|
...props.state.layers.first.columns,
|
||||||
|
col2: expect.objectContaining({
|
||||||
|
filter: undefined,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ shouldRemoveDimension: false, shouldReplaceDimension: true }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should render invalid field if field reference is broken', () => {
|
it('should render invalid field if field reference is broken', () => {
|
||||||
wrapper = mount(
|
wrapper = mount(
|
||||||
<IndexPatternDimensionEditorComponent
|
<IndexPatternDimensionEditorComponent
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
|
* 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { EuiButtonIcon, EuiLink, EuiPanel, EuiPopover } from '@elastic/eui';
|
||||||
|
import { EuiFormRow, EuiFlexItem, EuiFlexGroup } from '@elastic/eui';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Query } from 'src/plugins/data/public';
|
||||||
|
import { IndexPatternColumn, operationDefinitionMap } from '../operations';
|
||||||
|
import { isQueryValid } from '../operations/definitions/filters';
|
||||||
|
import { QueryInput } from '../query_input';
|
||||||
|
import { IndexPattern, IndexPatternLayer } from '../types';
|
||||||
|
|
||||||
|
// to do: get the language from uiSettings
|
||||||
|
export const defaultFilter: Query = {
|
||||||
|
query: '',
|
||||||
|
language: 'kuery',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function setFilter(columnId: string, layer: IndexPatternLayer, query: Query | undefined) {
|
||||||
|
return {
|
||||||
|
...layer,
|
||||||
|
columns: {
|
||||||
|
...layer.columns,
|
||||||
|
[columnId]: {
|
||||||
|
...layer.columns[columnId],
|
||||||
|
filter: query,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Filtering({
|
||||||
|
selectedColumn,
|
||||||
|
columnId,
|
||||||
|
layer,
|
||||||
|
updateLayer,
|
||||||
|
indexPattern,
|
||||||
|
isInitiallyOpen,
|
||||||
|
}: {
|
||||||
|
selectedColumn: IndexPatternColumn;
|
||||||
|
indexPattern: IndexPattern;
|
||||||
|
columnId: string;
|
||||||
|
layer: IndexPatternLayer;
|
||||||
|
updateLayer: (newLayer: IndexPatternLayer) => void;
|
||||||
|
isInitiallyOpen: boolean;
|
||||||
|
}) {
|
||||||
|
const [filterPopoverOpen, setFilterPopoverOpen] = useState(isInitiallyOpen);
|
||||||
|
const selectedOperation = operationDefinitionMap[selectedColumn.operationType];
|
||||||
|
if (!selectedOperation.filterable || !selectedColumn.filter) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isInvalid = !isQueryValid(selectedColumn.filter, indexPattern);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EuiFormRow
|
||||||
|
display="columnCompressed"
|
||||||
|
fullWidth
|
||||||
|
label={i18n.translate('xpack.lens.indexPattern.filterBy.label', {
|
||||||
|
defaultMessage: 'Filter by',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<EuiFlexGroup gutterSize="s" alignItems="center">
|
||||||
|
<EuiFlexItem>
|
||||||
|
<EuiPopover
|
||||||
|
isOpen={filterPopoverOpen}
|
||||||
|
closePopover={() => {
|
||||||
|
setFilterPopoverOpen(false);
|
||||||
|
}}
|
||||||
|
anchorClassName="eui-fullWidth"
|
||||||
|
panelClassName="lnsIndexPatternDimensionEditor__filtersEditor"
|
||||||
|
button={
|
||||||
|
<EuiPanel paddingSize="none">
|
||||||
|
<EuiFlexGroup gutterSize="s" alignItems="center" responsive={false}>
|
||||||
|
<EuiFlexItem grow={false}>{/* Empty for spacing */}</EuiFlexItem>
|
||||||
|
<EuiFlexItem grow={false}>
|
||||||
|
<EuiLink
|
||||||
|
className="lnsFiltersOperation__popoverButton"
|
||||||
|
data-test-subj="indexPattern-filters-existingFilterTrigger"
|
||||||
|
onClick={() => {
|
||||||
|
setFilterPopoverOpen(!filterPopoverOpen);
|
||||||
|
}}
|
||||||
|
color={isInvalid ? 'danger' : 'text'}
|
||||||
|
title={i18n.translate('xpack.lens.indexPattern.filterBy.clickToEdit', {
|
||||||
|
defaultMessage: 'Click to edit',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{selectedColumn.filter.query ||
|
||||||
|
i18n.translate('xpack.lens.indexPattern.filterBy.emptyFilterQuery', {
|
||||||
|
defaultMessage: '(empty)',
|
||||||
|
})}
|
||||||
|
</EuiLink>
|
||||||
|
</EuiFlexItem>
|
||||||
|
</EuiFlexGroup>
|
||||||
|
</EuiPanel>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<QueryInput
|
||||||
|
indexPattern={indexPattern}
|
||||||
|
data-test-subj="indexPattern-filter-by-input"
|
||||||
|
value={selectedColumn.filter || defaultFilter}
|
||||||
|
onChange={(newQuery) => {
|
||||||
|
updateLayer(setFilter(columnId, layer, newQuery));
|
||||||
|
}}
|
||||||
|
isInvalid={false}
|
||||||
|
onSubmit={() => {}}
|
||||||
|
/>
|
||||||
|
</EuiPopover>
|
||||||
|
</EuiFlexItem>
|
||||||
|
<EuiFlexItem grow={false}>
|
||||||
|
<EuiButtonIcon
|
||||||
|
data-test-subj="indexPattern-filter-by-remove"
|
||||||
|
color="danger"
|
||||||
|
aria-label={i18n.translate('xpack.lens.filterBy.removeLabel', {
|
||||||
|
defaultMessage: 'Remove filter',
|
||||||
|
})}
|
||||||
|
onClick={() => {
|
||||||
|
updateLayer(setFilter(columnId, layer, undefined));
|
||||||
|
}}
|
||||||
|
iconType="cross"
|
||||||
|
/>
|
||||||
|
</EuiFlexItem>
|
||||||
|
</EuiFlexGroup>
|
||||||
|
</EuiFormRow>
|
||||||
|
);
|
||||||
|
}
|
|
@ -7,23 +7,11 @@
|
||||||
|
|
||||||
import { EuiToolTip } from '@elastic/eui';
|
import { EuiToolTip } from '@elastic/eui';
|
||||||
import { EuiIcon } from '@elastic/eui';
|
import { EuiIcon } from '@elastic/eui';
|
||||||
import {
|
import { EuiFormRow, EuiSelect, EuiFlexItem, EuiFlexGroup, EuiButtonIcon } from '@elastic/eui';
|
||||||
EuiLink,
|
|
||||||
EuiFormRow,
|
|
||||||
EuiSelect,
|
|
||||||
EuiFlexItem,
|
|
||||||
EuiFlexGroup,
|
|
||||||
EuiButtonIcon,
|
|
||||||
EuiText,
|
|
||||||
EuiPopover,
|
|
||||||
EuiButtonEmpty,
|
|
||||||
EuiSpacer,
|
|
||||||
} from '@elastic/eui';
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
adjustTimeScaleLabelSuffix,
|
adjustTimeScaleLabelSuffix,
|
||||||
DEFAULT_TIME_SCALE,
|
|
||||||
IndexPatternColumn,
|
IndexPatternColumn,
|
||||||
operationDefinitionMap,
|
operationDefinitionMap,
|
||||||
} from '../operations';
|
} from '../operations';
|
||||||
|
@ -64,7 +52,6 @@ export function TimeScaling({
|
||||||
layer: IndexPatternLayer;
|
layer: IndexPatternLayer;
|
||||||
updateLayer: (newLayer: IndexPatternLayer) => void;
|
updateLayer: (newLayer: IndexPatternLayer) => void;
|
||||||
}) {
|
}) {
|
||||||
const [popoverOpen, setPopoverOpen] = useState(false);
|
|
||||||
const hasDateHistogram = layer.columnOrder.some(
|
const hasDateHistogram = layer.columnOrder.some(
|
||||||
(colId) => layer.columns[colId].operationType === 'date_histogram'
|
(colId) => layer.columns[colId].operationType === 'date_histogram'
|
||||||
);
|
);
|
||||||
|
@ -72,56 +59,12 @@ export function TimeScaling({
|
||||||
if (
|
if (
|
||||||
!selectedOperation.timeScalingMode ||
|
!selectedOperation.timeScalingMode ||
|
||||||
selectedOperation.timeScalingMode === 'disabled' ||
|
selectedOperation.timeScalingMode === 'disabled' ||
|
||||||
!hasDateHistogram
|
!hasDateHistogram ||
|
||||||
|
!selectedColumn.timeScale
|
||||||
) {
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!selectedColumn.timeScale) {
|
|
||||||
return (
|
|
||||||
<EuiText textAlign="right">
|
|
||||||
<EuiSpacer size="s" />
|
|
||||||
<EuiPopover
|
|
||||||
ownFocus
|
|
||||||
button={
|
|
||||||
<EuiButtonEmpty
|
|
||||||
size="xs"
|
|
||||||
iconType="arrowDown"
|
|
||||||
iconSide="right"
|
|
||||||
data-test-subj="indexPattern-time-scaling-popover"
|
|
||||||
onClick={() => {
|
|
||||||
setPopoverOpen(!popoverOpen);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n.translate('xpack.lens.indexPattern.timeScale.advancedSettings', {
|
|
||||||
defaultMessage: 'Add advanced options',
|
|
||||||
})}
|
|
||||||
</EuiButtonEmpty>
|
|
||||||
}
|
|
||||||
isOpen={popoverOpen}
|
|
||||||
closePopover={() => {
|
|
||||||
setPopoverOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<EuiText size="s">
|
|
||||||
<EuiLink
|
|
||||||
data-test-subj="indexPattern-time-scaling-enable"
|
|
||||||
color="text"
|
|
||||||
onClick={() => {
|
|
||||||
setPopoverOpen(false);
|
|
||||||
updateLayer(setTimeScaling(columnId, layer, DEFAULT_TIME_SCALE));
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n.translate('xpack.lens.indexPattern.timeScale.enableTimeScale', {
|
|
||||||
defaultMessage: 'Normalize by unit',
|
|
||||||
})}
|
|
||||||
</EuiLink>
|
|
||||||
</EuiText>
|
|
||||||
</EuiPopover>
|
|
||||||
</EuiText>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EuiFormRow
|
<EuiFormRow
|
||||||
display="columnCompressed"
|
display="columnCompressed"
|
||||||
|
|
|
@ -521,6 +521,123 @@ describe('IndexPattern Data Source', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should wrap filtered metrics in filtered metric aggregation', async () => {
|
||||||
|
const queryBaseState: IndexPatternBaseState = {
|
||||||
|
currentIndexPatternId: '1',
|
||||||
|
layers: {
|
||||||
|
first: {
|
||||||
|
indexPatternId: '1',
|
||||||
|
columnOrder: ['col1', 'col2', 'col3'],
|
||||||
|
columns: {
|
||||||
|
col1: {
|
||||||
|
label: 'Count of records',
|
||||||
|
dataType: 'number',
|
||||||
|
isBucketed: false,
|
||||||
|
sourceField: 'Records',
|
||||||
|
operationType: 'count',
|
||||||
|
timeScale: 'h',
|
||||||
|
filter: {
|
||||||
|
language: 'kuery',
|
||||||
|
query: 'bytes > 5',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
col2: {
|
||||||
|
label: 'Average of bytes',
|
||||||
|
dataType: 'number',
|
||||||
|
isBucketed: false,
|
||||||
|
sourceField: 'bytes',
|
||||||
|
operationType: 'avg',
|
||||||
|
timeScale: 'h',
|
||||||
|
},
|
||||||
|
col3: {
|
||||||
|
label: 'Date',
|
||||||
|
dataType: 'date',
|
||||||
|
isBucketed: true,
|
||||||
|
operationType: 'date_histogram',
|
||||||
|
sourceField: 'timestamp',
|
||||||
|
params: {
|
||||||
|
interval: 'auto',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = enrichBaseState(queryBaseState);
|
||||||
|
|
||||||
|
const ast = indexPatternDatasource.toExpression(state, 'first') as Ast;
|
||||||
|
expect(ast.chain[0].arguments.aggs[0]).toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"chain": Array [
|
||||||
|
Object {
|
||||||
|
"arguments": Object {
|
||||||
|
"customBucket": Array [
|
||||||
|
Object {
|
||||||
|
"chain": Array [
|
||||||
|
Object {
|
||||||
|
"arguments": Object {
|
||||||
|
"enabled": Array [
|
||||||
|
true,
|
||||||
|
],
|
||||||
|
"filter": Array [
|
||||||
|
"{\\"language\\":\\"kuery\\",\\"query\\":\\"bytes > 5\\"}",
|
||||||
|
],
|
||||||
|
"id": Array [
|
||||||
|
"col1-filter",
|
||||||
|
],
|
||||||
|
"schema": Array [
|
||||||
|
"bucket",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"function": "aggFilter",
|
||||||
|
"type": "function",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"type": "expression",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"customMetric": Array [
|
||||||
|
Object {
|
||||||
|
"chain": Array [
|
||||||
|
Object {
|
||||||
|
"arguments": Object {
|
||||||
|
"enabled": Array [
|
||||||
|
true,
|
||||||
|
],
|
||||||
|
"id": Array [
|
||||||
|
"col1-metric",
|
||||||
|
],
|
||||||
|
"schema": Array [
|
||||||
|
"metric",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"function": "aggCount",
|
||||||
|
"type": "function",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"type": "expression",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"enabled": Array [
|
||||||
|
true,
|
||||||
|
],
|
||||||
|
"id": Array [
|
||||||
|
"col1",
|
||||||
|
],
|
||||||
|
"schema": Array [
|
||||||
|
"metric",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"function": "aggFilteredMetric",
|
||||||
|
"type": "function",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"type": "expression",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
it('should add time_scale and format function if time scale is set and supported', async () => {
|
it('should add time_scale and format function if time scale is set and supported', async () => {
|
||||||
const queryBaseState: IndexPatternBaseState = {
|
const queryBaseState: IndexPatternBaseState = {
|
||||||
currentIndexPatternId: '1',
|
currentIndexPatternId: '1',
|
||||||
|
|
|
@ -82,6 +82,7 @@ export const counterRateOperation: OperationDefinition<
|
||||||
scale: 'ratio',
|
scale: 'ratio',
|
||||||
references: referenceIds,
|
references: referenceIds,
|
||||||
timeScale,
|
timeScale,
|
||||||
|
filter: previousColumn?.filter,
|
||||||
params: getFormatFromPreviousColumn(previousColumn),
|
params: getFormatFromPreviousColumn(previousColumn),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -106,4 +107,5 @@ export const counterRateOperation: OperationDefinition<
|
||||||
)?.join(', ');
|
)?.join(', ');
|
||||||
},
|
},
|
||||||
timeScalingMode: 'mandatory',
|
timeScalingMode: 'mandatory',
|
||||||
|
filterable: true,
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,6 +77,7 @@ export const cumulativeSumOperation: OperationDefinition<
|
||||||
operationType: 'cumulative_sum',
|
operationType: 'cumulative_sum',
|
||||||
isBucketed: false,
|
isBucketed: false,
|
||||||
scale: 'ratio',
|
scale: 'ratio',
|
||||||
|
filter: previousColumn?.filter,
|
||||||
references: referenceIds,
|
references: referenceIds,
|
||||||
params: getFormatFromPreviousColumn(previousColumn),
|
params: getFormatFromPreviousColumn(previousColumn),
|
||||||
};
|
};
|
||||||
|
@ -101,4 +102,5 @@ export const cumulativeSumOperation: OperationDefinition<
|
||||||
})
|
})
|
||||||
)?.join(', ');
|
)?.join(', ');
|
||||||
},
|
},
|
||||||
|
filterable: true,
|
||||||
};
|
};
|
||||||
|
|
|
@ -83,6 +83,7 @@ export const derivativeOperation: OperationDefinition<
|
||||||
scale: 'ratio',
|
scale: 'ratio',
|
||||||
references: referenceIds,
|
references: referenceIds,
|
||||||
timeScale: previousColumn?.timeScale,
|
timeScale: previousColumn?.timeScale,
|
||||||
|
filter: previousColumn?.filter,
|
||||||
params: getFormatFromPreviousColumn(previousColumn),
|
params: getFormatFromPreviousColumn(previousColumn),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -108,4 +109,5 @@ export const derivativeOperation: OperationDefinition<
|
||||||
)?.join(', ');
|
)?.join(', ');
|
||||||
},
|
},
|
||||||
timeScalingMode: 'optional',
|
timeScalingMode: 'optional',
|
||||||
|
filterable: true,
|
||||||
};
|
};
|
||||||
|
|
|
@ -89,6 +89,7 @@ export const movingAverageOperation: OperationDefinition<
|
||||||
scale: 'ratio',
|
scale: 'ratio',
|
||||||
references: referenceIds,
|
references: referenceIds,
|
||||||
timeScale: previousColumn?.timeScale,
|
timeScale: previousColumn?.timeScale,
|
||||||
|
filter: previousColumn?.filter,
|
||||||
params: {
|
params: {
|
||||||
window: 5,
|
window: 5,
|
||||||
...getFormatFromPreviousColumn(previousColumn),
|
...getFormatFromPreviousColumn(previousColumn),
|
||||||
|
@ -119,6 +120,7 @@ export const movingAverageOperation: OperationDefinition<
|
||||||
)?.join(', ');
|
)?.join(', ');
|
||||||
},
|
},
|
||||||
timeScalingMode: 'optional',
|
timeScalingMode: 'optional',
|
||||||
|
filterable: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
function MovingAverageParamEditor({
|
function MovingAverageParamEditor({
|
||||||
|
|
|
@ -70,6 +70,7 @@ export const cardinalityOperation: OperationDefinition<CardinalityIndexPatternCo
|
||||||
(!newField.aggregationRestrictions || newField.aggregationRestrictions.cardinality)
|
(!newField.aggregationRestrictions || newField.aggregationRestrictions.cardinality)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
filterable: true,
|
||||||
getDefaultLabel: (column, indexPattern) => ofName(getSafeName(column.sourceField, indexPattern)),
|
getDefaultLabel: (column, indexPattern) => ofName(getSafeName(column.sourceField, indexPattern)),
|
||||||
buildColumn({ field, previousColumn }) {
|
buildColumn({ field, previousColumn }) {
|
||||||
return {
|
return {
|
||||||
|
@ -79,6 +80,7 @@ export const cardinalityOperation: OperationDefinition<CardinalityIndexPatternCo
|
||||||
scale: SCALE,
|
scale: SCALE,
|
||||||
sourceField: field.name,
|
sourceField: field.name,
|
||||||
isBucketed: IS_BUCKETED,
|
isBucketed: IS_BUCKETED,
|
||||||
|
filter: previousColumn?.filter,
|
||||||
params: getFormatFromPreviousColumn(previousColumn),
|
params: getFormatFromPreviousColumn(previousColumn),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Query } from 'src/plugins/data/public';
|
||||||
import type { Operation } from '../../../types';
|
import type { Operation } from '../../../types';
|
||||||
import { TimeScaleUnit } from '../../time_scale';
|
import { TimeScaleUnit } from '../../time_scale';
|
||||||
import type { OperationType } from '../definitions';
|
import type { OperationType } from '../definitions';
|
||||||
|
@ -14,6 +15,7 @@ export interface BaseIndexPatternColumn extends Operation {
|
||||||
operationType: string;
|
operationType: string;
|
||||||
customLabel?: boolean;
|
customLabel?: boolean;
|
||||||
timeScale?: TimeScaleUnit;
|
timeScale?: TimeScaleUnit;
|
||||||
|
filter?: Query;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formatting can optionally be added to any column
|
// Formatting can optionally be added to any column
|
||||||
|
|
|
@ -61,6 +61,7 @@ export const countOperation: OperationDefinition<CountIndexPatternColumn, 'field
|
||||||
scale: 'ratio',
|
scale: 'ratio',
|
||||||
sourceField: field.name,
|
sourceField: field.name,
|
||||||
timeScale: previousColumn?.timeScale,
|
timeScale: previousColumn?.timeScale,
|
||||||
|
filter: previousColumn?.filter,
|
||||||
params:
|
params:
|
||||||
previousColumn?.dataType === 'number' &&
|
previousColumn?.dataType === 'number' &&
|
||||||
previousColumn.params &&
|
previousColumn.params &&
|
||||||
|
@ -87,4 +88,5 @@ export const countOperation: OperationDefinition<CountIndexPatternColumn, 'field
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
timeScalingMode: 'optional',
|
timeScalingMode: 'optional',
|
||||||
|
filterable: true,
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,8 +10,9 @@ import { shallow, mount } from 'enzyme';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
import { EuiPopover, EuiLink } from '@elastic/eui';
|
import { EuiPopover, EuiLink } from '@elastic/eui';
|
||||||
import { createMockedIndexPattern } from '../../../mocks';
|
import { createMockedIndexPattern } from '../../../mocks';
|
||||||
import { FilterPopover, QueryInput } from './filter_popover';
|
import { FilterPopover } from './filter_popover';
|
||||||
import { LabelInput } from '../shared_components';
|
import { LabelInput } from '../shared_components';
|
||||||
|
import { QueryInput } from '../../../query_input';
|
||||||
|
|
||||||
jest.mock('.', () => ({
|
jest.mock('.', () => ({
|
||||||
isQueryValid: () => true,
|
isQueryValid: () => true,
|
||||||
|
|
|
@ -8,13 +8,12 @@
|
||||||
import './filter_popover.scss';
|
import './filter_popover.scss';
|
||||||
|
|
||||||
import React, { MouseEventHandler, useEffect, useState } from 'react';
|
import React, { MouseEventHandler, useEffect, useState } from 'react';
|
||||||
import useDebounce from 'react-use/lib/useDebounce';
|
|
||||||
import { EuiPopover, EuiSpacer } from '@elastic/eui';
|
import { EuiPopover, EuiSpacer } from '@elastic/eui';
|
||||||
import { i18n } from '@kbn/i18n';
|
|
||||||
import { FilterValue, defaultLabel, isQueryValid } from '.';
|
import { FilterValue, defaultLabel, isQueryValid } from '.';
|
||||||
import { IndexPattern } from '../../../types';
|
import { IndexPattern } from '../../../types';
|
||||||
import { QueryStringInput, Query } from '../../../../../../../../src/plugins/data/public';
|
import { Query } from '../../../../../../../../src/plugins/data/public';
|
||||||
import { LabelInput } from '../shared_components';
|
import { LabelInput } from '../shared_components';
|
||||||
|
import { QueryInput } from '../../../query_input';
|
||||||
|
|
||||||
export const FilterPopover = ({
|
export const FilterPopover = ({
|
||||||
filter,
|
filter,
|
||||||
|
@ -94,54 +93,3 @@ export const FilterPopover = ({
|
||||||
</EuiPopover>
|
</EuiPopover>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const QueryInput = ({
|
|
||||||
value,
|
|
||||||
onChange,
|
|
||||||
indexPattern,
|
|
||||||
isInvalid,
|
|
||||||
onSubmit,
|
|
||||||
}: {
|
|
||||||
value: Query;
|
|
||||||
onChange: (input: Query) => void;
|
|
||||||
indexPattern: IndexPattern;
|
|
||||||
isInvalid: boolean;
|
|
||||||
onSubmit: () => void;
|
|
||||||
}) => {
|
|
||||||
const [inputValue, setInputValue] = useState(value);
|
|
||||||
|
|
||||||
useDebounce(() => onChange(inputValue), 256, [inputValue]);
|
|
||||||
|
|
||||||
const handleInputChange = (input: Query) => {
|
|
||||||
setInputValue(input);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<QueryStringInput
|
|
||||||
dataTestSubj="indexPattern-filters-queryStringInput"
|
|
||||||
size="s"
|
|
||||||
isInvalid={isInvalid}
|
|
||||||
bubbleSubmitEvent={false}
|
|
||||||
indexPatterns={[indexPattern]}
|
|
||||||
query={inputValue}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
onSubmit={() => {
|
|
||||||
if (inputValue.query) {
|
|
||||||
onSubmit();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
placeholder={
|
|
||||||
inputValue.language === 'kuery'
|
|
||||||
? i18n.translate('xpack.lens.indexPattern.filters.queryPlaceholderKql', {
|
|
||||||
defaultMessage: '{example}',
|
|
||||||
values: { example: 'method : "GET" or status : "404"' },
|
|
||||||
})
|
|
||||||
: i18n.translate('xpack.lens.indexPattern.filters.queryPlaceholderLucene', {
|
|
||||||
defaultMessage: '{example}',
|
|
||||||
values: { example: 'method:GET OR status:404' },
|
|
||||||
})
|
|
||||||
}
|
|
||||||
languageSwitcherPopoverAnchorPosition="rightDown"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
@ -230,6 +230,7 @@ interface BaseOperationDefinitionProps<C extends BaseIndexPatternColumn> {
|
||||||
* If set to optional, time scaling won't be enabled by default and can be removed.
|
* If set to optional, time scaling won't be enabled by default and can be removed.
|
||||||
*/
|
*/
|
||||||
timeScalingMode?: TimeScalingMode;
|
timeScalingMode?: TimeScalingMode;
|
||||||
|
filterable?: boolean;
|
||||||
|
|
||||||
getHelpMessage?: (props: HelpProps<C>) => React.ReactNode;
|
getHelpMessage?: (props: HelpProps<C>) => React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,12 +161,14 @@ export const lastValueOperation: OperationDefinition<LastValueIndexPatternColumn
|
||||||
isBucketed: false,
|
isBucketed: false,
|
||||||
scale: field.type === 'string' ? 'ordinal' : 'ratio',
|
scale: field.type === 'string' ? 'ordinal' : 'ratio',
|
||||||
sourceField: field.name,
|
sourceField: field.name,
|
||||||
|
filter: previousColumn?.filter,
|
||||||
params: {
|
params: {
|
||||||
sortField,
|
sortField,
|
||||||
...getFormatFromPreviousColumn(previousColumn),
|
...getFormatFromPreviousColumn(previousColumn),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
filterable: true,
|
||||||
toEsAggsFn: (column, columnId) => {
|
toEsAggsFn: (column, columnId) => {
|
||||||
return buildExpressionFunction<AggFunctionsMapping['aggTopHit']>('aggTopHit', {
|
return buildExpressionFunction<AggFunctionsMapping['aggTopHit']>('aggTopHit', {
|
||||||
id: columnId,
|
id: columnId,
|
||||||
|
|
|
@ -99,6 +99,7 @@ function buildMetricOperation<T extends MetricColumn<string>>({
|
||||||
isBucketed: false,
|
isBucketed: false,
|
||||||
scale: 'ratio',
|
scale: 'ratio',
|
||||||
timeScale: optionalTimeScaling ? previousColumn?.timeScale : undefined,
|
timeScale: optionalTimeScaling ? previousColumn?.timeScale : undefined,
|
||||||
|
filter: previousColumn?.filter,
|
||||||
params: getFormatFromPreviousColumn(previousColumn),
|
params: getFormatFromPreviousColumn(previousColumn),
|
||||||
} as T),
|
} as T),
|
||||||
onFieldChange: (oldColumn, field) => {
|
onFieldChange: (oldColumn, field) => {
|
||||||
|
@ -118,6 +119,7 @@ function buildMetricOperation<T extends MetricColumn<string>>({
|
||||||
},
|
},
|
||||||
getErrorMessage: (layer, columnId, indexPattern) =>
|
getErrorMessage: (layer, columnId, indexPattern) =>
|
||||||
getInvalidFieldMessage(layer.columns[columnId] as FieldBasedIndexPatternColumn, indexPattern),
|
getInvalidFieldMessage(layer.columns[columnId] as FieldBasedIndexPatternColumn, indexPattern),
|
||||||
|
filterable: true,
|
||||||
} as OperationDefinition<T, 'field'>;
|
} as OperationDefinition<T, 'field'>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -967,6 +967,49 @@ describe('state_helpers', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should remove filter from the wrapped column if it gets wrapped (case new1)', () => {
|
||||||
|
const expectedColumn = {
|
||||||
|
label: 'Count',
|
||||||
|
customLabel: true,
|
||||||
|
dataType: 'number' as const,
|
||||||
|
isBucketed: false,
|
||||||
|
sourceField: 'Records',
|
||||||
|
operationType: 'count' as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
const testFilter = { language: 'kuery', query: '' };
|
||||||
|
|
||||||
|
const layer: IndexPatternLayer = {
|
||||||
|
indexPatternId: '1',
|
||||||
|
columnOrder: ['col1'],
|
||||||
|
columns: { col1: { ...expectedColumn, filter: testFilter } },
|
||||||
|
};
|
||||||
|
const result = replaceColumn({
|
||||||
|
layer,
|
||||||
|
indexPattern,
|
||||||
|
columnId: 'col1',
|
||||||
|
op: 'testReference' as OperationType,
|
||||||
|
visualizationGroups: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(operationDefinitionMap.testReference.buildColumn).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
referenceIds: ['id1'],
|
||||||
|
previousColumn: expect.objectContaining({
|
||||||
|
// filter should be passed to the buildColumn function of the target operation
|
||||||
|
filter: testFilter,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(result.columns).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
// filter should be stripped from the original column
|
||||||
|
id1: expectedColumn,
|
||||||
|
col1: expect.any(Object),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('should create a new no-input operation to use as reference (case new2)', () => {
|
it('should create a new no-input operation to use as reference (case new2)', () => {
|
||||||
// @ts-expect-error this function is not valid
|
// @ts-expect-error this function is not valid
|
||||||
operationDefinitionMap.testReference.requiredReferences = [
|
operationDefinitionMap.testReference.requiredReferences = [
|
||||||
|
|
|
@ -509,7 +509,18 @@ function applyReferenceTransition({
|
||||||
if (!hasExactMatch && isColumnValidAsReference({ validation, column: previousColumn })) {
|
if (!hasExactMatch && isColumnValidAsReference({ validation, column: previousColumn })) {
|
||||||
hasExactMatch = true;
|
hasExactMatch = true;
|
||||||
|
|
||||||
const newLayer = { ...layer, columns: { ...layer.columns, [newId]: { ...previousColumn } } };
|
const newLayer = {
|
||||||
|
...layer,
|
||||||
|
columns: {
|
||||||
|
...layer.columns,
|
||||||
|
[newId]: {
|
||||||
|
...previousColumn,
|
||||||
|
// drop the filter for the referenced column because the wrapping operation
|
||||||
|
// is filterable as well and will handle it one level higher.
|
||||||
|
filter: operationDefinition.filterable ? undefined : previousColumn.filter,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
layer = {
|
layer = {
|
||||||
...layer,
|
...layer,
|
||||||
columnOrder: getColumnOrder(newLayer),
|
columnOrder: getColumnOrder(newLayer),
|
||||||
|
|
|
@ -32,6 +32,7 @@ export const createMockedReferenceOperation = () => {
|
||||||
references: args.referenceIds,
|
references: args.referenceIds,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
filterable: true,
|
||||||
isTransferable: jest.fn(),
|
isTransferable: jest.fn(),
|
||||||
toExpression: jest.fn().mockReturnValue([]),
|
toExpression: jest.fn().mockReturnValue([]),
|
||||||
getPossibleOperation: jest.fn().mockReturnValue({ dataType: 'number', isBucketed: false }),
|
getPossibleOperation: jest.fn().mockReturnValue({ dataType: 'number', isBucketed: false }),
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
|
* 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import useDebounce from 'react-use/lib/useDebounce';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { IndexPattern } from './types';
|
||||||
|
import { QueryStringInput, Query } from '../../../../../src/plugins/data/public';
|
||||||
|
|
||||||
|
export const QueryInput = ({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
indexPattern,
|
||||||
|
isInvalid,
|
||||||
|
onSubmit,
|
||||||
|
disableAutoFocus,
|
||||||
|
}: {
|
||||||
|
value: Query;
|
||||||
|
onChange: (input: Query) => void;
|
||||||
|
indexPattern: IndexPattern;
|
||||||
|
isInvalid: boolean;
|
||||||
|
onSubmit: () => void;
|
||||||
|
disableAutoFocus?: boolean;
|
||||||
|
}) => {
|
||||||
|
const [inputValue, setInputValue] = useState(value);
|
||||||
|
|
||||||
|
useDebounce(() => onChange(inputValue), 256, [inputValue]);
|
||||||
|
|
||||||
|
const handleInputChange = (input: Query) => {
|
||||||
|
setInputValue(input);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<QueryStringInput
|
||||||
|
dataTestSubj="indexPattern-filters-queryStringInput"
|
||||||
|
size="s"
|
||||||
|
disableAutoFocus={disableAutoFocus}
|
||||||
|
isInvalid={isInvalid}
|
||||||
|
bubbleSubmitEvent={false}
|
||||||
|
indexPatterns={[indexPattern]}
|
||||||
|
query={inputValue}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
onSubmit={() => {
|
||||||
|
if (inputValue.query) {
|
||||||
|
onSubmit();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
placeholder={
|
||||||
|
inputValue.language === 'kuery'
|
||||||
|
? i18n.translate('xpack.lens.indexPattern.filters.queryPlaceholderKql', {
|
||||||
|
defaultMessage: '{example}',
|
||||||
|
values: { example: 'method : "GET" or status : "404"' },
|
||||||
|
})
|
||||||
|
: i18n.translate('xpack.lens.indexPattern.filters.queryPlaceholderLucene', {
|
||||||
|
defaultMessage: '{example}',
|
||||||
|
values: { example: 'method:GET OR status:404' },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
languageSwitcherPopoverAnchorPosition="rightDown"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import type { IUiSettingsClient } from 'kibana/public';
|
import type { IUiSettingsClient } from 'kibana/public';
|
||||||
import {
|
import {
|
||||||
|
AggFunctionsMapping,
|
||||||
EsaggsExpressionFunctionDefinition,
|
EsaggsExpressionFunctionDefinition,
|
||||||
IndexPatternLoadExpressionFunctionDefinition,
|
IndexPatternLoadExpressionFunctionDefinition,
|
||||||
} from '../../../../../src/plugins/data/public';
|
} from '../../../../../src/plugins/data/public';
|
||||||
|
@ -29,11 +30,32 @@ function getExpressionForLayer(
|
||||||
indexPattern: IndexPattern,
|
indexPattern: IndexPattern,
|
||||||
uiSettings: IUiSettingsClient
|
uiSettings: IUiSettingsClient
|
||||||
): ExpressionAstExpression | null {
|
): ExpressionAstExpression | null {
|
||||||
const { columns, columnOrder } = layer;
|
const { columnOrder } = layer;
|
||||||
if (columnOrder.length === 0 || !indexPattern) {
|
if (columnOrder.length === 0 || !indexPattern) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const columns = { ...layer.columns };
|
||||||
|
Object.keys(columns).forEach((columnId) => {
|
||||||
|
const column = columns[columnId];
|
||||||
|
const rootDef = operationDefinitionMap[column.operationType];
|
||||||
|
if (
|
||||||
|
'references' in column &&
|
||||||
|
rootDef.filterable &&
|
||||||
|
rootDef.input === 'fullReference' &&
|
||||||
|
column.filter
|
||||||
|
) {
|
||||||
|
// inherit filter to all referenced operations
|
||||||
|
column.references.forEach((referenceColumnId) => {
|
||||||
|
const referencedColumn = columns[referenceColumnId];
|
||||||
|
const referenceDef = operationDefinitionMap[column.operationType];
|
||||||
|
if (referenceDef.filterable) {
|
||||||
|
columns[referenceColumnId] = { ...referencedColumn, filter: column.filter };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const columnEntries = columnOrder.map((colId) => [colId, columns[colId]] as const);
|
const columnEntries = columnOrder.map((colId) => [colId, columns[colId]] as const);
|
||||||
|
|
||||||
if (columnEntries.length) {
|
if (columnEntries.length) {
|
||||||
|
@ -44,10 +66,37 @@ function getExpressionForLayer(
|
||||||
if (def.input === 'fullReference') {
|
if (def.input === 'fullReference') {
|
||||||
expressions.push(...def.toExpression(layer, colId, indexPattern));
|
expressions.push(...def.toExpression(layer, colId, indexPattern));
|
||||||
} else {
|
} else {
|
||||||
|
const wrapInFilter = Boolean(def.filterable && col.filter);
|
||||||
|
let aggAst = def.toEsAggsFn(
|
||||||
|
col,
|
||||||
|
wrapInFilter ? `${colId}-metric` : colId,
|
||||||
|
indexPattern,
|
||||||
|
layer,
|
||||||
|
uiSettings
|
||||||
|
);
|
||||||
|
if (wrapInFilter) {
|
||||||
|
aggAst = buildExpressionFunction<AggFunctionsMapping['aggFilteredMetric']>(
|
||||||
|
'aggFilteredMetric',
|
||||||
|
{
|
||||||
|
id: colId,
|
||||||
|
enabled: true,
|
||||||
|
schema: 'metric',
|
||||||
|
customBucket: buildExpression([
|
||||||
|
buildExpressionFunction<AggFunctionsMapping['aggFilter']>('aggFilter', {
|
||||||
|
id: `${colId}-filter`,
|
||||||
|
enabled: true,
|
||||||
|
schema: 'bucket',
|
||||||
|
filter: JSON.stringify(col.filter),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
customMetric: buildExpression({ type: 'expression', chain: [aggAst] }),
|
||||||
|
}
|
||||||
|
).toAst();
|
||||||
|
}
|
||||||
aggs.push(
|
aggs.push(
|
||||||
buildExpression({
|
buildExpression({
|
||||||
type: 'expression',
|
type: 'expression',
|
||||||
chain: [def.toEsAggsFn(col, colId, indexPattern, layer, uiSettings)],
|
chain: [aggAst],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12087,7 +12087,6 @@
|
||||||
"xpack.lens.indexPattern.terms.otherLabel": "その他",
|
"xpack.lens.indexPattern.terms.otherLabel": "その他",
|
||||||
"xpack.lens.indexPattern.terms.size": "値の数",
|
"xpack.lens.indexPattern.terms.size": "値の数",
|
||||||
"xpack.lens.indexPattern.termsOf": "{name} のトップの値",
|
"xpack.lens.indexPattern.termsOf": "{name} のトップの値",
|
||||||
"xpack.lens.indexPattern.timeScale.advancedSettings": "高度なオプションを追加",
|
|
||||||
"xpack.lens.indexPattern.timeScale.enableTimeScale": "単位で正規化",
|
"xpack.lens.indexPattern.timeScale.enableTimeScale": "単位で正規化",
|
||||||
"xpack.lens.indexPattern.timeScale.label": "単位で正規化",
|
"xpack.lens.indexPattern.timeScale.label": "単位で正規化",
|
||||||
"xpack.lens.indexPattern.timeScale.tooltip": "基本の日付間隔に関係なく、常に指定された時間単位のレートとして表示されるように値を正規化します。",
|
"xpack.lens.indexPattern.timeScale.tooltip": "基本の日付間隔に関係なく、常に指定された時間単位のレートとして表示されるように値を正規化します。",
|
||||||
|
|
|
@ -12244,7 +12244,6 @@
|
||||||
"xpack.lens.indexPattern.terms.otherLabel": "其他",
|
"xpack.lens.indexPattern.terms.otherLabel": "其他",
|
||||||
"xpack.lens.indexPattern.terms.size": "值数目",
|
"xpack.lens.indexPattern.terms.size": "值数目",
|
||||||
"xpack.lens.indexPattern.termsOf": "{name} 排名最前值",
|
"xpack.lens.indexPattern.termsOf": "{name} 排名最前值",
|
||||||
"xpack.lens.indexPattern.timeScale.advancedSettings": "添加高级选项",
|
|
||||||
"xpack.lens.indexPattern.timeScale.enableTimeScale": "按单位标准化",
|
"xpack.lens.indexPattern.timeScale.enableTimeScale": "按单位标准化",
|
||||||
"xpack.lens.indexPattern.timeScale.label": "按单位标准化",
|
"xpack.lens.indexPattern.timeScale.label": "按单位标准化",
|
||||||
"xpack.lens.indexPattern.timeScale.tooltip": "将值标准化为始终显示为每指定时间单位速率,无论基础日期时间间隔是多少。",
|
"xpack.lens.indexPattern.timeScale.tooltip": "将值标准化为始终显示为每指定时间单位速率,无论基础日期时间间隔是多少。",
|
||||||
|
|
Loading…
Reference in a new issue