From 184111d97182162f7eae5ef96fa49e26036476d5 Mon Sep 17 00:00:00 2001 From: Stacey Gammon Date: Wed, 19 Jun 2019 11:09:25 -0400 Subject: [PATCH] Migrate old style queries stored in filters array (#38945) * Migrate old query filters * Null check instead of undefined for more completeness * remove unnecessary undefined check * Use good defaults, not undefined, for brand new dashboards. * fix: typescript errors * be explicit instead of matchinline snapshot. * default to Kuery when there is no query given --- .../core_plugins/kibana/migrations/index.ts | 21 ++++++ .../core_plugins/kibana/migrations/is_doc.ts | 31 +++++++++ .../kibana/{ => migrations}/migrations.js | 3 + .../{ => migrations}/migrations.test.js | 0 .../core_plugins/kibana/migrations/types.ts | 39 +++++++++++ .../__tests__/get_saved_dashboard_mock.ts | 2 + .../dashboard/dashboard_state_manager.ts | 16 ++--- .../public/dashboard/lib/filter_utils.ts | 47 ------------- .../dashboard/lib/get_app_state_defaults.ts | 5 +- .../public/dashboard/migrations/index.ts | 20 ++++++ .../dashboard/migrations/is_dashboard_doc.ts | 35 ++++++++++ .../migrations/migrations_730.test.ts | 60 ++++++++++++++++ .../dashboard/migrations/migrations_730.ts | 45 ++++++++++++ .../migrations/move_filters_to_query.test.ts | 64 +++++++++++++++++ .../migrations/move_filters_to_query.ts | 69 +++++++++++++++++++ .../public/dashboard/migrations/types.ts | 38 ++++++++++ .../saved_dashboard/saved_dashboard.d.ts | 4 ++ .../saved_dashboard/saved_dashboard.js | 11 ++- .../apps/dashboard/bwc_shared_urls.js | 33 ++++++++- 19 files changed, 479 insertions(+), 64 deletions(-) create mode 100644 src/legacy/core_plugins/kibana/migrations/index.ts create mode 100644 src/legacy/core_plugins/kibana/migrations/is_doc.ts rename src/legacy/core_plugins/kibana/{ => migrations}/migrations.js (99%) rename src/legacy/core_plugins/kibana/{ => migrations}/migrations.test.js (100%) create mode 100644 src/legacy/core_plugins/kibana/migrations/types.ts create mode 100644 src/legacy/core_plugins/kibana/public/dashboard/migrations/index.ts create mode 100644 src/legacy/core_plugins/kibana/public/dashboard/migrations/is_dashboard_doc.ts create mode 100644 src/legacy/core_plugins/kibana/public/dashboard/migrations/migrations_730.test.ts create mode 100644 src/legacy/core_plugins/kibana/public/dashboard/migrations/migrations_730.ts create mode 100644 src/legacy/core_plugins/kibana/public/dashboard/migrations/move_filters_to_query.test.ts create mode 100644 src/legacy/core_plugins/kibana/public/dashboard/migrations/move_filters_to_query.ts create mode 100644 src/legacy/core_plugins/kibana/public/dashboard/migrations/types.ts diff --git a/src/legacy/core_plugins/kibana/migrations/index.ts b/src/legacy/core_plugins/kibana/migrations/index.ts new file mode 100644 index 0000000000000..68c843d2343c8 --- /dev/null +++ b/src/legacy/core_plugins/kibana/migrations/index.ts @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// @ts-ignore +export { migrations } from './migrations'; diff --git a/src/legacy/core_plugins/kibana/migrations/is_doc.ts b/src/legacy/core_plugins/kibana/migrations/is_doc.ts new file mode 100644 index 0000000000000..cc50dfa3b2d26 --- /dev/null +++ b/src/legacy/core_plugins/kibana/migrations/is_doc.ts @@ -0,0 +1,31 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Doc } from './types'; + +export function isDoc(doc: { [key: string]: unknown } | Doc): doc is Doc { + return ( + typeof doc.id === 'string' && + typeof doc.type === 'string' && + doc.attributes !== null && + typeof doc.attributes === 'object' && + doc.references !== null && + typeof doc.references === 'object' + ); +} diff --git a/src/legacy/core_plugins/kibana/migrations.js b/src/legacy/core_plugins/kibana/migrations/migrations.js similarity index 99% rename from src/legacy/core_plugins/kibana/migrations.js rename to src/legacy/core_plugins/kibana/migrations/migrations.js index 6452b77db1495..4951c2f06f4db 100644 --- a/src/legacy/core_plugins/kibana/migrations.js +++ b/src/legacy/core_plugins/kibana/migrations/migrations.js @@ -18,6 +18,7 @@ */ import { cloneDeep, get, omit, has, flow } from 'lodash'; +import { migrations730 as dashboardMigrations730 } from '../public/dashboard/migrations'; function migrateIndexPattern(doc) { const searchSourceJSON = get(doc, 'attributes.kibanaSavedObjectMeta.searchSourceJSON'); @@ -422,6 +423,7 @@ export const migrations = { '7.0.0': (doc) => { // Set new "references" attribute doc.references = doc.references || []; + // Migrate index pattern migrateIndexPattern(doc); // Migrate panels @@ -455,6 +457,7 @@ export const migrations = { doc.attributes.panelsJSON = JSON.stringify(panels); return doc; }, + '7.3.0': dashboardMigrations730 }, search: { '7.0.0': (doc) => { diff --git a/src/legacy/core_plugins/kibana/migrations.test.js b/src/legacy/core_plugins/kibana/migrations/migrations.test.js similarity index 100% rename from src/legacy/core_plugins/kibana/migrations.test.js rename to src/legacy/core_plugins/kibana/migrations/migrations.test.js diff --git a/src/legacy/core_plugins/kibana/migrations/types.ts b/src/legacy/core_plugins/kibana/migrations/types.ts new file mode 100644 index 0000000000000..144151ed80d43 --- /dev/null +++ b/src/legacy/core_plugins/kibana/migrations/types.ts @@ -0,0 +1,39 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { SavedObjectReference } from '../../../../legacy/server/saved_objects/routes/types'; + +export interface SavedObjectAttributes { + kibanaSavedObjectMeta: { + searchSourceJSON: string; + }; +} + +export interface Doc { + references: SavedObjectReference[]; + attributes: Attributes; + id: string; + type: string; +} + +export interface DocPre700 { + attributes: Attributes; + id: string; + type: string; +} diff --git a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/get_saved_dashboard_mock.ts b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/get_saved_dashboard_mock.ts index 0fc74f30a997c..f9f5cfe0214b2 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/__tests__/get_saved_dashboard_mock.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/__tests__/get_saved_dashboard_mock.ts @@ -40,6 +40,8 @@ export function getSavedDashboardMock( save: () => { return Promise.resolve('123'); }, + getQuery: () => ({ query: '', language: 'kuery' }), + getFilters: () => [], ...config, }; } diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state_manager.ts b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state_manager.ts index 40dfd633d5e99..1b357a5d658b8 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state_manager.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state_manager.ts @@ -24,9 +24,9 @@ import { stateMonitorFactory, StateMonitor } from 'ui/state_management/state_mon import { StaticIndexPattern } from 'ui/index_patterns'; import { AppStateClass as TAppStateClass } from 'ui/state_management/app_state'; import { Timefilter } from 'ui/timefilter'; +import { RefreshInterval } from 'ui/timefilter/timefilter'; import { Filter } from '@kbn/es-query'; import moment from 'moment'; -import { RefreshInterval } from 'ui/timefilter/timefilter'; import { Query } from 'src/legacy/core_plugins/data/public'; import { TimeRange } from 'ui/timefilter/time_history'; import { DashboardViewMode } from './dashboard_view_mode'; @@ -278,7 +278,7 @@ export class DashboardStateManager { _pushFiltersToStore() { const state = store.getState(); - const dashboardFilters = this.getDashboardFilterBars(); + const dashboardFilters = this.savedDashboard.getFilters(); if ( !_.isEqual( FilterUtils.cleanFiltersForComparison(dashboardFilters), @@ -386,8 +386,8 @@ export class DashboardStateManager { return { timeTo: this.savedDashboard.timeTo, timeFrom: this.savedDashboard.timeFrom, - filterBars: this.getDashboardFilterBars(), - query: this.getDashboardQuery(), + filterBars: this.savedDashboard.getFilters(), + query: this.savedDashboard.getQuery(), }; } @@ -455,14 +455,6 @@ export class DashboardStateManager { return this.savedDashboard.timeRestore; } - public getDashboardFilterBars() { - return FilterUtils.getFilterBarsForDashboard(this.savedDashboard); - } - - public getDashboardQuery() { - return FilterUtils.getQueryFilterForDashboard(this.savedDashboard); - } - public getLastSavedFilterBars(): Filter[] { return this.lastSavedDashboardFilters.filterBars; } diff --git a/src/legacy/core_plugins/kibana/public/dashboard/lib/filter_utils.ts b/src/legacy/core_plugins/kibana/public/dashboard/lib/filter_utils.ts index eddf8289fabbb..3b6b99dcb6d25 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/lib/filter_utils.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/lib/filter_utils.ts @@ -19,9 +19,7 @@ import _ from 'lodash'; import moment, { Moment } from 'moment'; -import { QueryFilter } from 'ui/filter_manager/query_filter'; import { Filter } from '@kbn/es-query'; -import { SavedObjectDashboard } from '../saved_dashboard/saved_dashboard'; /** * @typedef {Object} QueryFilter @@ -30,51 +28,6 @@ import { SavedObjectDashboard } from '../saved_dashboard/saved_dashboard'; */ export class FilterUtils { - /** - * - * @param filter - * @returns {Boolean} True if the filter is of the special query type - * (e.g. goes in the query input bar), false otherwise (e.g. is in the filter bar). - */ - public static isQueryFilter(filter: Filter) { - return filter.query && !filter.meta; - } - - /** - * - * @param {SavedDashboard} dashboard - * @returns {Array.} An array of filters stored with the dashboard. Includes - * both query filters and filter bar filters. - */ - public static getDashboardFilters(dashboard: SavedObjectDashboard): Filter[] { - return dashboard.searchSource.getOwnField('filter'); - } - - /** - * Grabs a saved query to use from the dashboard, or if none exists, creates a default one. - * @param {SavedDashboard} dashboard - * @returns {QueryFilter} - */ - public static getQueryFilterForDashboard(dashboard: SavedObjectDashboard): QueryFilter | string { - if (dashboard.searchSource.getOwnField('query')) { - return dashboard.searchSource.getOwnField('query'); - } - - const dashboardFilters = this.getDashboardFilters(dashboard); - const dashboardQueryFilter = _.find(dashboardFilters, this.isQueryFilter); - return dashboardQueryFilter ? dashboardQueryFilter.query : ''; - } - - /** - * Returns the filters for the dashboard that should appear in the filter bar area. - * @param {SavedDashboard} dashboard - * @return {Array.} Array of filters that should appear in the filter bar for the - * given dashboard - */ - public static getFilterBarsForDashboard(dashboard: SavedObjectDashboard) { - return _.reject(this.getDashboardFilters(dashboard), this.isQueryFilter); - } - /** * Converts the time to a utc formatted string. If the time is not valid (e.g. it might be in a relative format like * 'now-15m', then it just returns what it was passed). diff --git a/src/legacy/core_plugins/kibana/public/dashboard/lib/get_app_state_defaults.ts b/src/legacy/core_plugins/kibana/public/dashboard/lib/get_app_state_defaults.ts index f8132a07df573..7a38d8d6d1d29 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/lib/get_app_state_defaults.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/lib/get_app_state_defaults.ts @@ -18,7 +18,6 @@ */ import { DashboardViewMode } from '../dashboard_view_mode'; -import { FilterUtils } from './filter_utils'; import { SavedObjectDashboard } from '../saved_dashboard/saved_dashboard'; import { Pre61SavedDashboardPanel, @@ -37,8 +36,8 @@ export function getAppStateDefaults( timeRestore: savedDashboard.timeRestore, panels: savedDashboard.panelsJSON ? JSON.parse(savedDashboard.panelsJSON) : [], options: savedDashboard.optionsJSON ? JSON.parse(savedDashboard.optionsJSON) : {}, - query: FilterUtils.getQueryFilterForDashboard(savedDashboard), - filters: FilterUtils.getFilterBarsForDashboard(savedDashboard), + query: savedDashboard.getQuery(), + filters: savedDashboard.getFilters(), viewMode: savedDashboard.id || hideWriteControls ? DashboardViewMode.VIEW : DashboardViewMode.EDIT, }; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/migrations/index.ts b/src/legacy/core_plugins/kibana/public/dashboard/migrations/index.ts new file mode 100644 index 0000000000000..da2542e854c32 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/dashboard/migrations/index.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { migrations730 } from './migrations_730'; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/migrations/is_dashboard_doc.ts b/src/legacy/core_plugins/kibana/public/dashboard/migrations/is_dashboard_doc.ts new file mode 100644 index 0000000000000..094f60f0a73cf --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/dashboard/migrations/is_dashboard_doc.ts @@ -0,0 +1,35 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { DashboardDoc } from './types'; +import { isDoc } from '../../../migrations/is_doc'; + +export function isDashboardDoc( + doc: { [key: string]: unknown } | DashboardDoc +): doc is DashboardDoc { + if (!isDoc(doc)) { + return false; + } + + if (typeof (doc as DashboardDoc).attributes.panelsJSON !== 'string') { + return false; + } + + return true; +} diff --git a/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrations_730.test.ts b/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrations_730.test.ts new file mode 100644 index 0000000000000..04ef7b13d8ff1 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrations_730.test.ts @@ -0,0 +1,60 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { migrations730 } from './migrations_730'; +import { DashboardDoc } from './types'; + +test('dashboard migration 7.3.0 migrates filters to query on search source', () => { + const doc: DashboardDoc = { + id: '1', + type: 'dashboard', + references: [], + attributes: { + description: '', + uiStateJSON: '{}', + version: 1, + timeRestore: false, + kibanaSavedObjectMeta: { + searchSourceJSON: + '{"filter":[{"query":{"query_string":{"query":"n: 6","analyze_wildcard":true}}}],"highlightAll":true,"version":true}', + }, + panelsJSON: + '[{"id":"1","type":"visualization","foo":true},{"id":"2","type":"visualization","bar":true}]', + }, + }; + const newDoc = migrations730(doc); + + expect(newDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "description": "", + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{\\"filter\\":[],\\"highlightAll\\":true,\\"version\\":true,\\"query\\":{\\"query\\":\\"n: 6\\",\\"language\\":\\"lucene\\"}}", + }, + "panelsJSON": "[{\\"id\\":\\"1\\",\\"type\\":\\"visualization\\",\\"foo\\":true},{\\"id\\":\\"2\\",\\"type\\":\\"visualization\\",\\"bar\\":true}]", + "timeRestore": false, + "uiStateJSON": "{}", + "version": 1, + }, + "id": "1", + "references": Array [], + "type": "dashboard", +} +`); +}); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrations_730.ts b/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrations_730.ts new file mode 100644 index 0000000000000..de038cba7385b --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrations_730.ts @@ -0,0 +1,45 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { DashboardDoc } from './types'; +import { isDashboardDoc } from './is_dashboard_doc'; +import { moveFiltersToQuery } from './move_filters_to_query'; + +export function migrations730( + doc: + | { + [key: string]: unknown; + } + | DashboardDoc +): DashboardDoc | { [key: string]: unknown } { + if (!isDashboardDoc(doc)) { + // NOTE: we should probably throw an error here... but for now following suit and in the + // case of errors, just returning the same document. + return doc; + } + + try { + const searchSource = JSON.parse(doc.attributes.kibanaSavedObjectMeta.searchSourceJSON); + doc.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.stringify( + moveFiltersToQuery(searchSource) + ); + return doc; + } catch (e) { + return doc; + } +} diff --git a/src/legacy/core_plugins/kibana/public/dashboard/migrations/move_filters_to_query.test.ts b/src/legacy/core_plugins/kibana/public/dashboard/migrations/move_filters_to_query.test.ts new file mode 100644 index 0000000000000..1f503ee675407 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/dashboard/migrations/move_filters_to_query.test.ts @@ -0,0 +1,64 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { moveFiltersToQuery, Pre600FilterQuery } from './move_filters_to_query'; +import { Filter, FilterStateStore } from '@kbn/es-query'; + +const filter: Filter = { + meta: { disabled: false, negate: false, alias: '' }, + query: {}, + $state: { store: FilterStateStore.APP_STATE }, +}; + +const queryFilter: Pre600FilterQuery = { + query: { query_string: { query: 'hi!', analyze_wildcard: true } }, +}; + +test('Migrates an old filter query into the query field', () => { + const newSearchSource = moveFiltersToQuery({ + filter: [filter, queryFilter], + }); + + expect(newSearchSource).toEqual({ + filter: [ + { + $state: { store: FilterStateStore.APP_STATE }, + meta: { + alias: '', + disabled: false, + negate: false, + }, + query: {}, + }, + ], + query: { + language: 'lucene', + query: 'hi!', + }, + }); +}); + +test('Preserves query if search source is new', () => { + const newSearchSource = moveFiltersToQuery({ + filter: [filter], + query: { query: 'bye', language: 'kuery' }, + }); + + expect(newSearchSource.query).toEqual({ query: 'bye', language: 'kuery' }); +}); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/migrations/move_filters_to_query.ts b/src/legacy/core_plugins/kibana/public/dashboard/migrations/move_filters_to_query.ts new file mode 100644 index 0000000000000..85b200e3b30ee --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/dashboard/migrations/move_filters_to_query.ts @@ -0,0 +1,69 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Query } from 'src/legacy/core_plugins/data/public'; +import { Filter } from '@kbn/es-query'; + +export interface Pre600FilterQuery { + // pre 6.0.0 global query:queryString:options were stored per dashboard and would + // be applied even if the setting was subsequently removed from the advanced + // settings. This is considered a bug, and this migration will fix that behavior. + query: { query_string: { query: string } & { [key: string]: unknown } }; +} + +export interface SearchSourcePre600 { + filter: Array; +} + +export interface SearchSource730 { + filter: Filter[]; + query: Query; + highlightAll?: boolean; + version?: boolean; +} + +function isQueryFilter(filter: Filter | { query: unknown }): filter is Pre600FilterQuery { + return filter.query && !(filter as Filter).meta; +} + +export function moveFiltersToQuery( + searchSource: SearchSourcePre600 | SearchSource730 +): SearchSource730 { + const searchSource730: SearchSource730 = { + ...searchSource, + filter: [], + query: (searchSource as SearchSource730).query || { + query: '', + language: 'kuery', + }, + }; + + searchSource.filter.forEach(filter => { + if (isQueryFilter(filter)) { + searchSource730.query = { + query: filter.query.query_string.query, + language: 'lucene', + }; + } else { + searchSource730.filter.push(filter); + } + }); + + return searchSource730; +} diff --git a/src/legacy/core_plugins/kibana/public/dashboard/migrations/types.ts b/src/legacy/core_plugins/kibana/public/dashboard/migrations/types.ts new file mode 100644 index 0000000000000..18f038f938bb9 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/dashboard/migrations/types.ts @@ -0,0 +1,38 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Doc, DocPre700 } from '../../../migrations/types'; + +export interface SavedObjectAttributes { + kibanaSavedObjectMeta: { + searchSourceJSON: string; + }; +} + +interface DashboardAttributes extends SavedObjectAttributes { + panelsJSON: string; + description: string; + uiStateJSON: string; + version: number; + timeRestore: boolean; +} + +export type DashboardDoc = Doc; + +export type DashboardDocPre700 = DocPre700; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts index 303e02d63a7f6..1f752833f45a8 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts @@ -21,6 +21,8 @@ import { SearchSource } from 'ui/courier'; import { SavedObject } from 'ui/saved_objects/saved_object'; import moment from 'moment'; import { RefreshInterval } from 'ui/timefilter/timefilter'; +import { Query } from 'src/legacy/core_plugins/data/public'; +import { Filter } from '@kbn/es-query'; export interface SavedObjectDashboard extends SavedObject { id?: string; @@ -38,4 +40,6 @@ export interface SavedObjectDashboard extends SavedObject { searchSource: SearchSource; destroy: () => void; refreshInterval?: RefreshInterval; + getQuery(): Query; + getFilters(): Filter[]; } diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js index 06b2920ac28c6..60a4db12ca82c 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.js @@ -71,7 +71,6 @@ module.factory('SavedDashboard', function (Private) { clearSavedIndexPattern: true }); - this.showInRecentlyAccessed = true; } @@ -113,5 +112,15 @@ module.factory('SavedDashboard', function (Private) { return `/app/kibana#${createDashboardEditUrl(this.id)}`; }; + SavedDashboard.prototype.getQuery = function () { + return this.searchSource.getOwnField('query') || + { query: '', language: 'kuery' }; + }; + + SavedDashboard.prototype.getFilters = function () { + return this.searchSource.getOwnField('filter') || []; + }; + + return SavedDashboard; }); diff --git a/test/functional/apps/dashboard/bwc_shared_urls.js b/test/functional/apps/dashboard/bwc_shared_urls.js index 69ded31fcc1d1..8b6bdbf20b5cb 100644 --- a/test/functional/apps/dashboard/bwc_shared_urls.js +++ b/test/functional/apps/dashboard/bwc_shared_urls.js @@ -57,8 +57,39 @@ export default function ({ getService, getPageObjects }) { kibanaBaseUrl = currentUrl.substring(0, currentUrl.indexOf('#')); }); - describe('6.0 urls', () => { + describe('5.6 urls', () => { + it('url with filters and query', async () => { + const url56 = `` + + `_g=(refreshInterval:(display:Off,pause:!f,value:0),` + + `time:(from:'2012-11-17T00:00:00.000Z',mode:absolute,to:'2015-11-17T18:01:36.621Z'))&` + + `_a=(` + + `description:'',` + + `filters:!(('$state':(store:appState),` + + `meta:(alias:!n,disabled:!f,index:'logstash-*',key:bytes,negate:!f,type:phrase,value:'12345'),` + + `query:(match:(bytes:(query:12345,type:phrase))))),` + + `fullScreenMode:!f,` + + `options:(),` + + `panels:!((col:1,id:Visualization-MetricChart,panelIndex:1,row:1,size_x:6,size_y:3,type:visualization),` + + `(col:7,id:Visualization-PieChart,panelIndex:2,row:1,size_x:6,size_y:3,type:visualization)),` + + `query:(query_string:(analyze_wildcard:!t,query:'memory:>220000')),` + + `timeRestore:!f,` + + `title:'New+Dashboard',` + + `uiState:(),` + + `viewMode:edit)`; + const url = `${kibanaBaseUrl}#/dashboard?${url56}`; + log.debug(`Navigating to ${url}`); + await browser.get(url, true); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const query = await queryBar.getQueryString(); + expect(query).to.equal('memory:>220000'); + + await pieChart.expectPieSliceCount(0); + await dashboardExpect.panelCount(2); + }); + }); + describe('6.0 urls', () => { it('loads an unsaved dashboard', async function () { const url = `${kibanaBaseUrl}#/dashboard?${urlQuery}`; log.debug(`Navigating to ${url}`);