From cb3fdcc7d9c00e59174e69f71f78c4c2daece11b Mon Sep 17 00:00:00 2001 From: Andrew Tate Date: Thu, 28 Apr 2022 14:31:44 -0500 Subject: [PATCH] Add filter fns --- .../public/kibana_api/kibana_api.ts | 77 +++++++++++++++++++ .../vis_type_script/public/renderer/index.tsx | 19 +++++ .../vis_definition/editor_options/script.tsx | 54 +++++++++++++ 3 files changed, 150 insertions(+) diff --git a/src/plugins/vis_type_script/public/kibana_api/kibana_api.ts b/src/plugins/vis_type_script/public/kibana_api/kibana_api.ts index f376eb0236aa7..e9f921012681b 100644 --- a/src/plugins/vis_type_script/public/kibana_api/kibana_api.ts +++ b/src/plugins/vis_type_script/public/kibana_api/kibana_api.ts @@ -15,6 +15,8 @@ import { SqlSearchStrategyResponse, } from '@kbn/data-plugin/common'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { buildQueryFilter, compareFilters, Filter } from '@kbn/es-query'; +import { i18n } from '@kbn/i18n'; import { VisSearchContext } from '../types'; export interface VisTypeScriptKibanaApiDeps { @@ -116,4 +118,79 @@ export class VisTypeScriptKibanaApi { return response.rawResponse; } + + async addFilter(query: any, index?: string, alias?: string) { + const dataViewId = await this.getDataViewIdWithDefault(index); + const newFilter = buildQueryFilter(query, dataViewId, alias); + + if (!!this.findMatchingFilter(newFilter)) return; + + this.deps.data.query.filterManager.addFilters(newFilter); + } + + /** + * Removes a filter matching the query and index if one exists + * @param {object} query Elastic Query DSL snippet, as used in the query DSL editor + * @param {string} [index] as defined in Kibana, or default if missing + */ + async removeFilter(query: any, index?: string) { + const indexId = await this.getDataViewIdWithDefault(index); + const filterToRemove = buildQueryFilter(query, indexId); + + const existingFilter = this.findMatchingFilter(filterToRemove); + + if (!existingFilter) return; + + this.deps.data.query.filterManager.removeFilter(existingFilter); + } + + /** + * Removes all filters + */ + removeAllFilters() { + this.deps.data.query.filterManager.removeAll(); + } + + findMatchingFilter(filter: Filter) { + const currentFilters = this.deps.data.query.filterManager.getFilters(); + return currentFilters.find((existing: Filter) => compareFilters(existing, filter)); + } + + /** + * Find data view by its title, if not given, gets it from spec or a defaults one + * @param {string} [index] + * @returns {Promise} data view id + */ + async getDataViewIdWithDefault(index?: string): Promise { + const dataViews = this.deps.data.dataViews; + let idxObj; + + if (index) { + [idxObj] = await dataViews.find(index); + if (!idxObj) { + throw new Error( + i18n.translate('visTypeVega.vegaParser.baseView.indexNotFoundErrorMessage', { + defaultMessage: 'Index {index} not found', + values: { index: `"${index}"` }, + }) + ); + } + } else { + if (!idxObj) { + const defaultIdx = await dataViews.getDefault(); + + if (defaultIdx) { + idxObj = defaultIdx; + } else { + throw new Error( + i18n.translate('visTypeVega.vegaParser.baseView.unableToFindDefaultIndexErrorMessage', { + defaultMessage: 'Unable to find default index', + }) + ); + } + } + } + + return idxObj.id as string; + } } diff --git a/src/plugins/vis_type_script/public/renderer/index.tsx b/src/plugins/vis_type_script/public/renderer/index.tsx index d8dadbf87875d..3ef16da993e14 100644 --- a/src/plugins/vis_type_script/public/renderer/index.tsx +++ b/src/plugins/vis_type_script/public/renderer/index.tsx @@ -47,6 +47,15 @@ const getSandboxDocument = (script: string, dependencies: string[], nonce: strin searchSql: (payload, options) => { return endpoint.call.sqlSearch(payload, options); }, + addFilter: (query, index, alias) => { + return endpoint.call.addFilter(query, index, alias); + }, + removeFilter: (query, index) => { + return endpoint.call.removeFilter(query, index); + }, + removeAllFilters: () => { + endpoint.call.removeAllFilters(); + }, subscribeToResize: (fn) => { onResize = fn; }, @@ -118,6 +127,16 @@ export const ScriptRenderer: React.FunctionComponent<{ ): Promise => { return kibanaApi.sqlSearch(payload, options); }, + addFilter: (query: any, indexName?: string, alias?: string) => { + return kibanaApi.addFilter(query, indexName, alias); + }, + removeFilter: (query: any, indexName?: string) => { + return kibanaApi.removeFilter(query, indexName); + }, + removeAllFilters: () => { + kibanaApi.removeAllFilters(); + }, + setTimeRange: () => {}, }); return () => { diff --git a/src/plugins/vis_type_script/public/vis_definition/editor_options/script.tsx b/src/plugins/vis_type_script/public/vis_definition/editor_options/script.tsx index e0797e4119a43..951aa76f7a23f 100644 --- a/src/plugins/vis_type_script/public/vis_definition/editor_options/script.tsx +++ b/src/plugins/vis_type_script/public/vis_definition/editor_options/script.tsx @@ -82,6 +82,60 @@ const provideSuggestions = ( insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, range: wordRange, }, + { + label: 'addFilter', + kind: monacoEditor.languages.CompletionItemKind.Method, + documentation: { + value: 'Adds a Kibana filter', + isTrusted: true, + }, + insertText: 'addFilter({$0})', + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range: wordRange, + }, + { + label: 'removeFilter', + kind: monacoEditor.languages.CompletionItemKind.Method, + documentation: { + value: 'Removes a Kibana filter', + isTrusted: true, + }, + insertText: 'removeFilter({$0})', + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range: wordRange, + }, + { + label: 'removeAllFilters', + kind: monacoEditor.languages.CompletionItemKind.Method, + documentation: { + value: 'Removes all Kibana filters', + isTrusted: true, + }, + insertText: 'removeAllFilters()', + range: wordRange, + }, + { + label: 'searchSql', + kind: monacoEditor.languages.CompletionItemKind.Method, + documentation: { + value: 'Runs an Elasticsearch SQL query', + isTrusted: true, + }, + insertText: 'searchSql({\n\tquery: "$0"\n})', + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range: wordRange, + }, + { + label: 'searchSql', + kind: monacoEditor.languages.CompletionItemKind.Method, + documentation: { + value: 'Runs an Elasticsearch SQL query', + isTrusted: true, + }, + insertText: 'searchSql({\n\tquery: "$0"\n})', + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range: wordRange, + }, { label: 'subscribeToResize', kind: monacoEditor.languages.CompletionItemKind.Method,