Timelion reads raw field list from saved object, should grab from index pattern api (#89988)

* Timelion reads raw field list from saved object, should grab from index pattern api

Closes: #84387

* fix PR comment
This commit is contained in:
Alexey Antonov 2021-02-03 10:29:50 +03:00 committed by GitHub
parent 14cf1875b5
commit af454d61bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 31 additions and 68 deletions

View file

@ -8,14 +8,12 @@
import { SUGGESTION_TYPE, suggest } from './timelion_expression_input_helpers'; import { SUGGESTION_TYPE, suggest } from './timelion_expression_input_helpers';
import { getArgValueSuggestions } from '../helpers/arg_value_suggestions'; import { getArgValueSuggestions } from '../helpers/arg_value_suggestions';
import { setIndexPatterns, setSavedObjectsClient } from '../helpers/plugin_services'; import { setIndexPatterns } from '../helpers/plugin_services';
import { IndexPatternsContract } from 'src/plugins/data/public'; import { IndexPatternsContract } from 'src/plugins/data/public';
import { SavedObjectsClient } from 'kibana/public';
import { ITimelionFunction } from '../../common/types'; import { ITimelionFunction } from '../../common/types';
describe('Timelion expression suggestions', () => { describe('Timelion expression suggestions', () => {
setIndexPatterns({} as IndexPatternsContract); setIndexPatterns({} as IndexPatternsContract);
setSavedObjectsClient({} as SavedObjectsClient);
const argValueSuggestions = getArgValueSuggestions(); const argValueSuggestions = getArgValueSuggestions();

View file

@ -7,9 +7,9 @@
*/ */
import { get } from 'lodash'; import { get } from 'lodash';
import { getIndexPatterns, getSavedObjectsClient } from './plugin_services'; import { getIndexPatterns } from './plugin_services';
import { TimelionFunctionArgs } from '../../common/types'; import { TimelionFunctionArgs } from '../../common/types';
import { indexPatterns as indexPatternsUtils, IndexPatternAttributes } from '../../../data/public'; import { indexPatterns as indexPatternsUtils } from '../../../data/public';
export interface Location { export interface Location {
min: number; min: number;
@ -32,7 +32,6 @@ export interface FunctionArg {
export function getArgValueSuggestions() { export function getArgValueSuggestions() {
const indexPatterns = getIndexPatterns(); const indexPatterns = getIndexPatterns();
const savedObjectsClient = getSavedObjectsClient();
async function getIndexPattern(functionArgs: FunctionArg[]) { async function getIndexPattern(functionArgs: FunctionArg[]) {
const indexPatternArg = functionArgs.find(({ name }) => name === 'index'); const indexPatternArg = functionArgs.find(({ name }) => name === 'index');
@ -42,22 +41,9 @@ export function getArgValueSuggestions() {
} }
const indexPatternTitle = get(indexPatternArg, 'value.text'); const indexPatternTitle = get(indexPatternArg, 'value.text');
const { savedObjects } = await savedObjectsClient.find<IndexPatternAttributes>({ return (await indexPatterns.find(indexPatternTitle)).find(
type: 'index-pattern', (index) => index.title === indexPatternTitle
fields: ['title'],
search: `"${indexPatternTitle}"`,
searchFields: ['title'],
perPage: 10,
});
const indexPatternSavedObject = savedObjects.find(
({ attributes }) => attributes.title === indexPatternTitle
); );
if (!indexPatternSavedObject) {
// index argument does not match an index pattern
return;
}
return await indexPatterns.get(indexPatternSavedObject.id);
} }
function containsFieldName(partial: string, field: { name: string }) { function containsFieldName(partial: string, field: { name: string }) {
@ -73,18 +59,11 @@ export function getArgValueSuggestions() {
es: { es: {
async index(partial: string) { async index(partial: string) {
const search = partial ? `${partial}*` : '*'; const search = partial ? `${partial}*` : '*';
const resp = await savedObjectsClient.find<IndexPatternAttributes>({ const size = 25;
type: 'index-pattern',
fields: ['title', 'type'], return (await indexPatterns.find(search, size)).map(({ title }) => ({
search: `${search}`, name: title,
searchFields: ['title'], }));
perPage: 25,
});
return resp.savedObjects
.filter((savedObject) => !savedObject.get('type'))
.map((savedObject) => {
return { name: savedObject.attributes.title };
});
}, },
async metric(partial: string, functionArgs: FunctionArg[]) { async metric(partial: string, functionArgs: FunctionArg[]) {
if (!partial || !partial.includes(':')) { if (!partial || !partial.includes(':')) {

View file

@ -7,7 +7,6 @@
*/ */
import type { IndexPatternsContract, ISearchStart } from 'src/plugins/data/public'; import type { IndexPatternsContract, ISearchStart } from 'src/plugins/data/public';
import type { SavedObjectsClientContract } from 'kibana/public';
import { createGetterSetter } from '../../../kibana_utils/public'; import { createGetterSetter } from '../../../kibana_utils/public';
export const [getIndexPatterns, setIndexPatterns] = createGetterSetter<IndexPatternsContract>( export const [getIndexPatterns, setIndexPatterns] = createGetterSetter<IndexPatternsContract>(
@ -15,8 +14,3 @@ export const [getIndexPatterns, setIndexPatterns] = createGetterSetter<IndexPatt
); );
export const [getDataSearch, setDataSearch] = createGetterSetter<ISearchStart>('Search'); export const [getDataSearch, setDataSearch] = createGetterSetter<ISearchStart>('Search');
export const [
getSavedObjectsClient,
setSavedObjectsClient,
] = createGetterSetter<SavedObjectsClientContract>('SavedObjectsClient');

View file

@ -25,7 +25,7 @@ import { VisualizationsSetup } from '../../visualizations/public';
import { getTimelionVisualizationConfig } from './timelion_vis_fn'; import { getTimelionVisualizationConfig } from './timelion_vis_fn';
import { getTimelionVisDefinition } from './timelion_vis_type'; import { getTimelionVisDefinition } from './timelion_vis_type';
import { setIndexPatterns, setSavedObjectsClient, setDataSearch } from './helpers/plugin_services'; import { setIndexPatterns, setDataSearch } from './helpers/plugin_services';
import { ConfigSchema } from '../config'; import { ConfigSchema } from '../config';
import { getArgValueSuggestions } from './helpers/arg_value_suggestions'; import { getArgValueSuggestions } from './helpers/arg_value_suggestions';
@ -92,7 +92,6 @@ export class TimelionVisPlugin
public start(core: CoreStart, plugins: TimelionVisStartDependencies) { public start(core: CoreStart, plugins: TimelionVisStartDependencies) {
setIndexPatterns(plugins.data.indexPatterns); setIndexPatterns(plugins.data.indexPatterns);
setSavedObjectsClient(core.savedObjects.client);
setDataSearch(plugins.data.search); setDataSearch(plugins.data.search);
return { return {

View file

@ -46,7 +46,9 @@ export interface TimelionPluginStartDeps {
export class Plugin { export class Plugin {
constructor(private readonly initializerContext: PluginInitializerContext) {} constructor(private readonly initializerContext: PluginInitializerContext) {}
public async setup(core: CoreSetup): Promise<RecursiveReadonly<PluginSetupContract>> { public async setup(
core: CoreSetup<TimelionPluginStartDeps>
): Promise<RecursiveReadonly<PluginSetupContract>> {
const config = await this.initializerContext.config const config = await this.initializerContext.config
.create<TypeOf<typeof configSchema>>() .create<TypeOf<typeof configSchema>>()
.pipe(first()) .pipe(first())

View file

@ -18,6 +18,7 @@ import getNamespacesSettings from '../lib/get_namespaced_settings';
import getTlConfig from '../handlers/lib/tl_config'; import getTlConfig from '../handlers/lib/tl_config';
import { TimelionFunctionInterface } from '../types'; import { TimelionFunctionInterface } from '../types';
import { ConfigManager } from '../lib/config_manager'; import { ConfigManager } from '../lib/config_manager';
import { TimelionPluginStartDeps } from '../plugin';
const timelionDefaults = getNamespacesSettings(); const timelionDefaults = getNamespacesSettings();
@ -32,7 +33,7 @@ export function runRoute(
logger: Logger; logger: Logger;
getFunction: (name: string) => TimelionFunctionInterface; getFunction: (name: string) => TimelionFunctionInterface;
configManager: ConfigManager; configManager: ConfigManager;
core: CoreSetup; core: CoreSetup<TimelionPluginStartDeps>;
} }
) { ) {
router.post( router.post(
@ -77,17 +78,22 @@ export function runRoute(
}, },
router.handleLegacyErrors(async (context, request, response) => { router.handleLegacyErrors(async (context, request, response) => {
try { try {
const [, { data }] = await core.getStartServices();
const uiSettings = await context.core.uiSettings.client.getAll(); const uiSettings = await context.core.uiSettings.client.getAll();
const indexPatternsService = await data.indexPatterns.indexPatternsServiceFactory(
context.core.savedObjects.client,
context.core.elasticsearch.client.asCurrentUser
);
const tlConfig = getTlConfig({ const tlConfig = getTlConfig({
context, context,
request, request,
settings: _.defaults(uiSettings, timelionDefaults), // Just in case they delete some setting. settings: _.defaults(uiSettings, timelionDefaults), // Just in case they delete some setting.
getFunction, getFunction,
getIndexPatternsService: () => indexPatternsService,
getStartServices: core.getStartServices, getStartServices: core.getStartServices,
allowedGraphiteUrls: configManager.getGraphiteUrls(), allowedGraphiteUrls: configManager.getGraphiteUrls(),
esShardTimeout: configManager.getEsShardTimeout(), esShardTimeout: configManager.getEsShardTimeout(),
savedObjectsClient: context.core.savedObjects.client,
}); });
const chainRunner = chainRunnerFn(tlConfig); const chainRunner = chainRunnerFn(tlConfig);
const sheet = await Bluebird.all(chainRunner.processRequest(request.body)); const sheet = await Bluebird.all(chainRunner.processRequest(request.body));

View file

@ -22,16 +22,12 @@ import { UI_SETTINGS } from '../../../../data/server';
describe('es', () => { describe('es', () => {
let tlConfig; let tlConfig;
function stubRequestAndServer(response, indexPatternSavedObjects = []) { function stubRequestAndServer(response) {
return { return {
context: { search: { search: jest.fn().mockReturnValue(of(response)) } }, context: { search: { search: jest.fn().mockReturnValue(of(response)) } },
savedObjectsClient: { getIndexPatternsService: () => ({
find: function () { find: async () => [],
return Promise.resolve({ }),
saved_objects: indexPatternSavedObjects,
});
},
},
}; };
} }

View file

@ -96,23 +96,12 @@ export default new Datasource('es', {
kibana: true, kibana: true,
fit: 'nearest', fit: 'nearest',
}); });
const indexPatternsService = tlConfig.getIndexPatternsService();
const indexPatternSpec = (await indexPatternsService.find(config.index)).find(
(index) => index.title === config.index
);
const findResp = await tlConfig.savedObjectsClient.find({ const scriptedFields = indexPatternSpec?.getScriptedFields() ?? [];
type: 'index-pattern',
fields: ['title', 'fields'],
search: `"${config.index}"`,
search_fields: ['title'],
});
const indexPatternSavedObject = findResp.saved_objects.find((savedObject) => {
return savedObject.attributes.title === config.index;
});
let scriptedFields = [];
if (indexPatternSavedObject) {
const fields = JSON.parse(indexPatternSavedObject.attributes.fields);
scriptedFields = fields.filter((field) => {
return field.scripted;
});
}
const esShardTimeout = tlConfig.esShardTimeout; const esShardTimeout = tlConfig.esShardTimeout;