Skip to content

Commit 6a3b687

Browse files
[Vega] Filter bar in Vega is not usable with non default index pattern. (#84090) (#86476)
* [Vega] Filtering is not working Closes: #81738 * fix CI * some work * some work * add tests for extract_index_pattern * simplify extract_index_pattern * fix type error * cleanup * Update vega_base_view.js * Update extract_index_pattern.test.ts * fix PR comments * fix some comments * findByTitle -> getByTitle * remove getByTitle * fix vega_base_view * fix jest * allow to set multiple indexes from top_nav Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> # Conflicts: # src/plugins/vis_type_vega/public/vega_type.ts # src/plugins/vis_type_vega/public/vega_visualization.test.js # src/plugins/vis_type_vega/public/vega_visualization.ts Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
1 parent 6ee4d26 commit 6a3b687

File tree

16 files changed

+285
-94
lines changed

16 files changed

+285
-94
lines changed

src/plugins/data/common/index_patterns/utils.ts

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
* under the License.
1818
*/
1919

20-
import { find } from 'lodash';
21-
import { SavedObjectsClientCommon, SavedObject } from '..';
20+
import type { IndexPatternSavedObjectAttrs } from './index_patterns';
21+
import type { SavedObjectsClientCommon } from '../types';
2222

2323
/**
2424
* Returns an object matching a given title
@@ -27,24 +27,16 @@ import { SavedObjectsClientCommon, SavedObject } from '..';
2727
* @param title {string}
2828
* @returns {Promise<SavedObject|undefined>}
2929
*/
30-
export async function findByTitle(
31-
client: SavedObjectsClientCommon,
32-
title: string
33-
): Promise<SavedObject<any> | void> {
34-
if (!title) {
35-
return Promise.resolve();
36-
}
37-
38-
const savedObjects = await client.find({
39-
type: 'index-pattern',
40-
perPage: 10,
41-
search: `"${title}"`,
42-
searchFields: ['title'],
43-
fields: ['title'],
44-
});
30+
export async function findByTitle(client: SavedObjectsClientCommon, title: string) {
31+
if (title) {
32+
const savedObjects = await client.find<IndexPatternSavedObjectAttrs>({
33+
type: 'index-pattern',
34+
perPage: 10,
35+
search: `"${title}"`,
36+
searchFields: ['title'],
37+
fields: ['title'],
38+
});
4539

46-
return find(
47-
savedObjects,
48-
(obj: SavedObject<any>) => obj.attributes.title.toLowerCase() === title.toLowerCase()
49-
);
40+
return savedObjects.find((obj) => obj.attributes.title.toLowerCase() === title.toLowerCase());
41+
}
5042
}

src/plugins/data/public/mocks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const createStartContract = (): Start => {
6464
SearchBar: jest.fn().mockReturnValue(null),
6565
},
6666
indexPatterns: ({
67+
find: jest.fn((search) => [{ id: search, title: search }]),
6768
createField: jest.fn(() => {}),
6869
createFieldList: jest.fn(() => []),
6970
ensureDefaultIndexPattern: jest.fn(),

src/plugins/vis_type_vega/public/data_model/es_query_parser.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ export class EsQueryParser {
226226
const requestObject = requests.find((item) => getRequestName(item, index) === data.name);
227227

228228
if (requestObject) {
229+
requestObject.dataObject.url = requestObject.url;
229230
requestObject.dataObject.values = data.rawResponse;
230231
}
231232
});

src/plugins/vis_type_vega/public/data_model/types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,9 @@ interface Projection {
8282
name: string;
8383
}
8484

85-
interface RequestDataObject {
85+
interface RequestDataObject<TUrlData = UrlObject> {
8686
name?: string;
87+
url?: TUrlData;
8788
values: SearchResponse<unknown>;
8889
}
8990

@@ -186,7 +187,7 @@ export interface CacheBounds {
186187
max: number;
187188
}
188189

189-
interface Requests<TUrlData = UrlObject, TRequestDataObject = RequestDataObject> {
190+
interface Requests<TUrlData = UrlObject, TRequestDataObject = RequestDataObject<TUrlData>> {
190191
url: TUrlData;
191192
name: string;
192193
dataObject: TRequestDataObject;

src/plugins/vis_type_vega/public/data_model/vega_parser.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,21 +185,21 @@ describe('VegaParser._resolveEsQueries', () => {
185185
'es',
186186
check(
187187
{ data: { name: 'requestId', url: { index: 'a' }, x: 1 } },
188-
{ data: { name: 'requestId', values: [42], x: 1 } }
188+
{ data: { name: 'requestId', url: { index: 'a', body: {} }, values: [42], x: 1 } }
189189
)
190190
);
191191
test(
192192
'es 2',
193193
check(
194194
{ data: { name: 'requestId', url: { '%type%': 'elasticsearch', index: 'a' } } },
195-
{ data: { name: 'requestId', values: [42] } }
195+
{ data: { name: 'requestId', url: { index: 'a', body: {} }, values: [42] } }
196196
)
197197
);
198198
test(
199199
'es arr',
200200
check(
201201
{ arr: [{ data: { name: 'requestId', url: { index: 'a' }, x: 1 } }] },
202-
{ arr: [{ data: { name: 'requestId', values: [42], x: 1 } }] }
202+
{ arr: [{ data: { name: 'requestId', url: { index: 'a', body: {} }, values: [42], x: 1 } }] }
203203
)
204204
);
205205
test(
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import { dataPluginMock } from '../../../data/public/mocks';
21+
import { extractIndexPatternsFromSpec } from './extract_index_pattern';
22+
import { setData } from '../services';
23+
24+
import type { VegaSpec } from '../data_model/types';
25+
26+
const getMockedSpec = (mockedObj: any) => (mockedObj as unknown) as VegaSpec;
27+
28+
describe('extractIndexPatternsFromSpec', () => {
29+
const dataStart = dataPluginMock.createStartContract();
30+
31+
beforeAll(() => {
32+
setData(dataStart);
33+
});
34+
35+
test('should not throw errors if no index is specified', async () => {
36+
const spec = getMockedSpec({
37+
data: {},
38+
});
39+
40+
const indexes = await extractIndexPatternsFromSpec(spec);
41+
42+
expect(indexes).toMatchInlineSnapshot(`Array []`);
43+
});
44+
45+
test('should extract single index pattern', async () => {
46+
const spec = getMockedSpec({
47+
data: {
48+
url: {
49+
index: 'test',
50+
},
51+
},
52+
});
53+
54+
const indexes = await extractIndexPatternsFromSpec(spec);
55+
56+
expect(indexes).toMatchInlineSnapshot(`
57+
Array [
58+
Object {
59+
"id": "test",
60+
"title": "test",
61+
},
62+
]
63+
`);
64+
});
65+
66+
test('should extract multiple index patterns', async () => {
67+
const spec = getMockedSpec({
68+
data: [
69+
{
70+
url: {
71+
index: 'test1',
72+
},
73+
},
74+
{
75+
url: {
76+
index: 'test2',
77+
},
78+
},
79+
],
80+
});
81+
82+
const indexes = await extractIndexPatternsFromSpec(spec);
83+
84+
expect(indexes).toMatchInlineSnapshot(`
85+
Array [
86+
Object {
87+
"id": "test1",
88+
"title": "test1",
89+
},
90+
Object {
91+
"id": "test2",
92+
"title": "test2",
93+
},
94+
]
95+
`);
96+
});
97+
98+
test('should filter empty values', async () => {
99+
const spec = getMockedSpec({
100+
data: [
101+
{
102+
url: {
103+
wrong: 'wrong',
104+
},
105+
},
106+
{
107+
url: {
108+
index: 'ok',
109+
},
110+
},
111+
],
112+
});
113+
114+
const indexes = await extractIndexPatternsFromSpec(spec);
115+
116+
expect(indexes).toMatchInlineSnapshot(`
117+
Array [
118+
Object {
119+
"id": "ok",
120+
"title": "ok",
121+
},
122+
]
123+
`);
124+
});
125+
});
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import { flatten } from 'lodash';
21+
import { getData } from '../services';
22+
23+
import type { Data, VegaSpec } from '../data_model/types';
24+
import type { IndexPattern } from '../../../data/public';
25+
26+
export const extractIndexPatternsFromSpec = async (spec: VegaSpec) => {
27+
const { indexPatterns } = getData();
28+
let data: Data[] = [];
29+
30+
if (Array.isArray(spec.data)) {
31+
data = spec.data;
32+
} else if (spec.data) {
33+
data = [spec.data];
34+
}
35+
36+
return flatten<IndexPattern>(
37+
await Promise.all(
38+
data.reduce<Array<Promise<IndexPattern[]>>>((accumulator, currentValue) => {
39+
if (currentValue.url?.index) {
40+
accumulator.push(indexPatterns.find(currentValue.url.index));
41+
}
42+
43+
return accumulator;
44+
}, [])
45+
)
46+
);
47+
};

src/plugins/vis_type_vega/public/plugin.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import { Setup as InspectorSetup } from '../../inspector/public';
2525
import {
2626
setNotifications,
2727
setData,
28-
setSavedObjects,
2928
setInjectedVars,
3029
setUISettings,
3130
setMapsLegacyConfig,
@@ -99,7 +98,6 @@ export class VegaPlugin implements Plugin<Promise<void>, void> {
9998

10099
public start(core: CoreStart, { data }: VegaPluginStartDependencies) {
101100
setNotifications(core.notifications);
102-
setSavedObjects(core.savedObjects);
103101
setData(data);
104102
setInjectedMetadata(core.injectedMetadata);
105103
}

src/plugins/vis_type_vega/public/services.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,7 @@
1717
* under the License.
1818
*/
1919

20-
import {
21-
CoreStart,
22-
SavedObjectsStart,
23-
NotificationsStart,
24-
IUiSettingsClient,
25-
} from 'src/core/public';
20+
import { CoreStart, NotificationsStart, IUiSettingsClient } from 'src/core/public';
2621

2722
import { DataPublicPluginStart } from '../../data/public';
2823
import { createGetterSetter } from '../../kibana_utils/public';
@@ -40,10 +35,6 @@ export const [getInjectedMetadata, setInjectedMetadata] = createGetterSetter<
4035
CoreStart['injectedMetadata']
4136
>('InjectedMetadata');
4237

43-
export const [getSavedObjects, setSavedObjects] = createGetterSetter<SavedObjectsStart>(
44-
'SavedObjects'
45-
);
46-
4738
export const [getInjectedVars, setInjectedVars] = createGetterSetter<{
4839
enableExternalUrls: boolean;
4940
emsTileLayerId: unknown;

src/plugins/vis_type_vega/public/vega_type.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@
1818
*/
1919

2020
import { i18n } from '@kbn/i18n';
21+
import { parse } from 'hjson';
2122
import { BaseVisTypeOptions } from 'src/plugins/visualizations/public';
2223
import { DefaultEditorSize } from '../../vis_default_editor/public';
2324
import { VegaVisualizationDependencies } from './plugin';
2425
import { VegaVisEditor } from './components';
2526

27+
import type { VegaSpec } from './data_model/types';
28+
29+
import { extractIndexPatternsFromSpec } from './lib/extract_index_pattern';
2630
import { createVegaRequestHandler } from './vega_request_handler';
2731
// @ts-expect-error
2832
import { createVegaVisualization } from './vega_visualization';
@@ -64,6 +68,16 @@ export const createVegaTypeDefinition = (
6468
getSupportedTriggers: () => {
6569
return [VIS_EVENT_TO_TRIGGER.applyFilter];
6670
},
71+
getUsedIndexPattern: async (visParams) => {
72+
try {
73+
const spec = parse(visParams.spec, { legacyRoot: false, keepWsc: true });
74+
75+
return extractIndexPatternsFromSpec(spec as VegaSpec);
76+
} catch (e) {
77+
// spec is invalid
78+
}
79+
return [];
80+
},
6781
inspectorAdapters: createInspectorAdapters,
6882
};
6983
};

0 commit comments

Comments
 (0)