From 813a896f51415bec6ea5c3f8ba866c558b6eabac Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Thu, 12 Mar 2020 23:57:05 -0500 Subject: [PATCH 01/81] partial progress on async loading / searching of dashboard titles --- .../dashboard_drilldown_config.tsx | 24 ++++++++---- .../dashboard_drilldowns_services.ts | 5 ++- .../collect_config.tsx | 39 ++++++++++++++----- .../drilldown.tsx | 4 +- 4 files changed, 52 insertions(+), 20 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx index b45ba602b9bb1..5e800ed04a4c7 100644 --- a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; -import { EuiFormRow, EuiSelect, EuiSwitch } from '@elastic/eui'; +import { EuiFormRow, EuiSwitch, EuiComboBox } from '@elastic/eui'; import { txtChooseDestinationDashboard } from './i18n'; export interface DashboardItem { @@ -21,6 +21,8 @@ export interface DashboardDrilldownConfigProps { onDashboardSelect: (dashboardId: string) => void; onCurrentFiltersToggle?: () => void; onKeepRangeToggle?: () => void; + onSearchChange: (searchString: string) => void; + isLoading: boolean; } export const DashboardDrilldownConfig: React.FC = ({ @@ -31,17 +33,25 @@ export const DashboardDrilldownConfig: React.FC = onDashboardSelect, onCurrentFiltersToggle, onKeepRangeToggle, + onSearchChange, + isLoading, }) => { // TODO: use i18n below. + // todo - don't assume selectedTitle is in set + const selectedTitle = dashboards.find(item => item.id === activeDashboardId)?.title || ''; return ( <> - ({ value: id, text: title }))} - value={activeDashboardId} - onChange={e => onDashboardSelect(e.target.value)} + + async + selectedOptions={ + activeDashboardId ? [{ label: selectedTitle, value: activeDashboardId }] : [] + } + options={dashboards.map(({ id, title }) => ({ label: title, value: id }))} + onChange={([{ value = '' } = { value: '' }]) => onDashboardSelect(value)} + onSearchChange={onSearchChange} + isLoading={isLoading} + singleSelection={{ asPlainText: true }} /> {!!onCurrentFiltersToggle && ( diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts index ed0cb425ee106..b936522fe6be2 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts @@ -34,7 +34,8 @@ export class DashboardDrilldownsService { ) { const overlays = async () => (await core.getStartServices())[0].overlays; const drilldowns = async () => (await core.getStartServices())[1].drilldowns; - const savedObjects = async () => (await core.getStartServices())[0].savedObjects.client; + const getSavedObjectsClient = async () => + (await core.getStartServices())[0].savedObjects.client; const actionFlyoutCreateDrilldown = new FlyoutCreateDrilldownAction({ overlays, drilldowns }); plugins.uiActions.registerAction(actionFlyoutCreateDrilldown); @@ -45,7 +46,7 @@ export class DashboardDrilldownsService { plugins.uiActions.attachAction(CONTEXT_MENU_DRILLDOWNS_TRIGGER, actionFlyoutEditDrilldown); const dashboardToDashboardDrilldown = new DashboardToDashboardDrilldown({ - savedObjects, + getSavedObjectsClient, }); plugins.drilldowns.registerDrilldown(dashboardToDashboardDrilldown); } diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx index 778a6b3ef6b31..9d42662734d1a 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx @@ -8,6 +8,7 @@ import React, { useState, useEffect } from 'react'; import { CollectConfigProps } from './types'; import { DashboardDrilldownConfig } from '../../../components/dashboard_drilldown_config'; import { Params } from './drilldown'; +import { SimpleSavedObject } from '../../../../../../../src/core/public'; export interface CollectConfigContainerProps extends CollectConfigProps { params: Params; @@ -16,18 +17,36 @@ export interface CollectConfigContainerProps extends CollectConfigProps { export const CollectConfigContainer: React.FC = ({ config, onConfig, - params: { savedObjects }, + params: { getSavedObjectsClient }, }) => { - const [dashboards] = useState([ - { id: 'dashboard1', title: 'Dashboard 1' }, - { id: 'dashboard2', title: 'Dashboard 2' }, - { id: 'dashboard3', title: 'Dashboard 3' }, - { id: 'dashboard4', title: 'Dashboard 4' }, - ]); + const [dashboards, setDashboards] = useState([]); + const [searchString, setSearchString] = useState(); + const [isLoading, setIsLoading] = useState(false); useEffect(() => { - // TODO: Load dashboards... - }, [savedObjects]); + setIsLoading(true); + getSavedObjectsClient().then(savedObjectsClient => { + savedObjectsClient + .find({ + type: 'dashboard', + search: searchString ? `${searchString}*` : undefined, + // todo search by id + searchFields: ['title^3', 'description'], + defaultSearchOperator: 'AND', + perPage: 100, + }) + .then(({ savedObjects }) => { + const dashboardList = savedObjects.map( + (savedObject: SimpleSavedObject<{ id: string; title: string }>) => ({ + id: savedObject.id, + title: savedObject.attributes.title, + }) + ); + setDashboards(dashboardList); + setIsLoading(false); + }); + }); + }, [getSavedObjectsClient, searchString]); return ( = ({ dashboards={dashboards} currentFilters={config.useCurrentDashboardFilters} keepRange={config.useCurrentDashboardDataRange} + isLoading={isLoading} onDashboardSelect={dashboardId => { onConfig({ ...config, dashboardId }); }} + onSearchChange={setSearchString} onCurrentFiltersToggle={() => onConfig({ ...config, diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index c839ef8ee04ef..f991ef7d25c13 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -19,7 +19,7 @@ export const dashboards = [ ]; export interface Params { - savedObjects: () => Promise; + getSavedObjectsClient: () => Promise; } export class DashboardToDashboardDrilldown @@ -43,7 +43,7 @@ export class DashboardToDashboardDrilldown public readonly CollectConfig = reactToUiComponent(this.ReactCollectConfig); public readonly createConfig = () => ({ - dashboardId: '123', + dashboardId: '', useCurrentDashboardDataRange: true, useCurrentDashboardFilters: true, }); From 65ff148de0bc01e7c7850a3357f01c313acf2332 Mon Sep 17 00:00:00 2001 From: streamich Date: Fri, 13 Mar 2020 09:01:38 +0100 Subject: [PATCH 02/81] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20make=20combobox=20?= =?UTF-8?q?full=20width?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard_drilldown_config/dashboard_drilldown_config.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx index 5e800ed04a4c7..3dc9c5626ab3b 100644 --- a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx @@ -41,7 +41,7 @@ export const DashboardDrilldownConfig: React.FC = const selectedTitle = dashboards.find(item => item.id === activeDashboardId)?.title || ''; return ( <> - + async selectedOptions={ @@ -52,6 +52,7 @@ export const DashboardDrilldownConfig: React.FC = onSearchChange={onSearchChange} isLoading={isLoading} singleSelection={{ asPlainText: true }} + fullWidth /> {!!onCurrentFiltersToggle && ( From d46fcf067962d68ebfebcb19d9b6bd005e123aeb Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Mon, 16 Mar 2020 17:28:45 -0500 Subject: [PATCH 03/81] filtering combobox polish --- .../dashboard_drilldown_config.story.tsx | 6 + .../dashboard_drilldown_config.tsx | 26 ++- .../dashboard_drilldown_config/i18n.ts | 14 ++ .../collect_config.tsx | 148 ++++++++++++------ 4 files changed, 131 insertions(+), 63 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx index 8e204b044a136..de6897e56104d 100644 --- a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx @@ -30,6 +30,8 @@ const InteractiveDemo: React.FC = () => { onDashboardSelect={id => setActiveDashboardId(id)} onCurrentFiltersToggle={() => setCurrentFilters(old => !old)} onKeepRangeToggle={() => setKeepRange(old => !old)} + onSearchChange={() => {}} + isLoading={false} /> ); }; @@ -40,6 +42,8 @@ storiesOf('components/DashboardDrilldownConfig', module) activeDashboardId={'dashboard2'} dashboards={dashboards} onDashboardSelect={e => console.log('onDashboardSelect', e)} + onSearchChange={() => {}} + isLoading={false} /> )) .add('with switches', () => ( @@ -49,6 +53,8 @@ storiesOf('components/DashboardDrilldownConfig', module) onDashboardSelect={e => console.log('onDashboardSelect', e)} onCurrentFiltersToggle={() => console.log('onCurrentFiltersToggle')} onKeepRangeToggle={() => console.log('onKeepRangeToggle')} + onSearchChange={() => {}} + isLoading={false} /> )) .add('interactive demo', () => ); diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx index 5e800ed04a4c7..a9c0a610c3b40 100644 --- a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx @@ -5,17 +5,16 @@ */ import React from 'react'; -import { EuiFormRow, EuiSwitch, EuiComboBox } from '@elastic/eui'; -import { txtChooseDestinationDashboard } from './i18n'; - -export interface DashboardItem { - id: string; - title: string; -} +import { EuiFormRow, EuiSwitch, EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; +import { + txtChooseDestinationDashboard, + txtUseCurrentFilters, + txtUseCurrentDateRange, +} from './i18n'; export interface DashboardDrilldownConfigProps { activeDashboardId?: string; - dashboards: DashboardItem[]; + dashboards: Array>; currentFilters?: boolean; keepRange?: boolean; onDashboardSelect: (dashboardId: string) => void; @@ -36,9 +35,8 @@ export const DashboardDrilldownConfig: React.FC = onSearchChange, isLoading, }) => { - // TODO: use i18n below. - // todo - don't assume selectedTitle is in set - const selectedTitle = dashboards.find(item => item.id === activeDashboardId)?.title || ''; + const selectedTitle = dashboards.find(item => item.value === activeDashboardId)?.label || ''; + return ( <> @@ -47,7 +45,7 @@ export const DashboardDrilldownConfig: React.FC = selectedOptions={ activeDashboardId ? [{ label: selectedTitle, value: activeDashboardId }] : [] } - options={dashboards.map(({ id, title }) => ({ label: title, value: id }))} + options={dashboards} onChange={([{ value = '' } = { value: '' }]) => onDashboardSelect(value)} onSearchChange={onSearchChange} isLoading={isLoading} @@ -58,7 +56,7 @@ export const DashboardDrilldownConfig: React.FC = @@ -68,7 +66,7 @@ export const DashboardDrilldownConfig: React.FC = diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/i18n.ts b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/i18n.ts index 38fe6dd150853..6f2c29693fcb0 100644 --- a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/i18n.ts +++ b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/i18n.ts @@ -12,3 +12,17 @@ export const txtChooseDestinationDashboard = i18n.translate( defaultMessage: 'Choose destination dashboard', } ); + +export const txtUseCurrentFilters = i18n.translate( + 'xpack.dashboard.components.DashboardDrilldownConfig.useCurrentFilters', + { + defaultMessage: "Use current dashboard's filters", + } +); + +export const txtUseCurrentDateRange = i18n.translate( + 'xpack.dashboard.components.DashboardDrilldownConfig.useCurrentDateRange', + { + defaultMessage: "Use current dashboard's date range", + } +); diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx index 9d42662734d1a..cbced9024a8d3 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx @@ -4,73 +4,123 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState, useEffect } from 'react'; +import React from 'react'; +import { EuiComboBoxOptionOption } from '@elastic/eui'; +import { debounce, findIndex } from 'lodash'; import { CollectConfigProps } from './types'; import { DashboardDrilldownConfig } from '../../../components/dashboard_drilldown_config'; import { Params } from './drilldown'; import { SimpleSavedObject } from '../../../../../../../src/core/public'; +const mergeDashboards = ( + dashboards: Array>, + selectedDashboard?: EuiComboBoxOptionOption +) => { + // if we have a selected dashboard and its not in the list, append it + if (selectedDashboard && findIndex(dashboards, { value: selectedDashboard.value }) === -1) { + return [selectedDashboard, ...dashboards]; + } + return dashboards; +}; + +const dashboardSavedObjectToMenuItem = ( + savedObject: SimpleSavedObject<{ + title: string; + }> +) => ({ + value: savedObject.id, + label: savedObject.attributes.title, +}); + export interface CollectConfigContainerProps extends CollectConfigProps { params: Params; } -export const CollectConfigContainer: React.FC = ({ - config, - onConfig, - params: { getSavedObjectsClient }, -}) => { - const [dashboards, setDashboards] = useState([]); - const [searchString, setSearchString] = useState(); - const [isLoading, setIsLoading] = useState(false); +interface CollectConfigContainerState { + dashboards: Array>; + searchString?: string; + isLoading: boolean; + selectedDashboard?: EuiComboBoxOptionOption; + delay: boolean; +} + +export class CollectConfigContainer extends React.Component< + CollectConfigContainerProps, + CollectConfigContainerState +> { + state = { + dashboards: [], + isLoading: false, + searchString: undefined, + selectedDashboard: undefined, + delay: false, + }; + + componentDidMount() { + this.loadSelectedDashboard(); + this.loadDashboards(); + } - useEffect(() => { - setIsLoading(true); - getSavedObjectsClient().then(savedObjectsClient => { + loadSelectedDashboard() { + const { config } = this.props; + this.props.params.getSavedObjectsClient().then(savedObjectsClient => { + if (config.dashboardId) { + savedObjectsClient + .get<{ title: string }>('dashboard', config.dashboardId) + .then(dashboard => { + this.setState({ selectedDashboard: dashboardSavedObjectToMenuItem(dashboard) }); + }); + } + }); + } + + loadDashboards(searchString?: string) { + this.setState({ searchString, isLoading: true }); + this.props.params.getSavedObjectsClient().then(savedObjectsClient => { savedObjectsClient - .find({ + .find<{ title: string }>({ type: 'dashboard', search: searchString ? `${searchString}*` : undefined, - // todo search by id searchFields: ['title^3', 'description'], defaultSearchOperator: 'AND', perPage: 100, }) .then(({ savedObjects }) => { - const dashboardList = savedObjects.map( - (savedObject: SimpleSavedObject<{ id: string; title: string }>) => ({ - id: savedObject.id, - title: savedObject.attributes.title, - }) - ); - setDashboards(dashboardList); - setIsLoading(false); + if (searchString === this.state.searchString) { + const dashboardList = savedObjects.map(dashboardSavedObjectToMenuItem); + this.setState({ dashboards: dashboardList, isLoading: false }); + } }); }); - }, [getSavedObjectsClient, searchString]); + } - return ( - { - onConfig({ ...config, dashboardId }); - }} - onSearchChange={setSearchString} - onCurrentFiltersToggle={() => - onConfig({ - ...config, - useCurrentDashboardFilters: !config.useCurrentDashboardFilters, - }) - } - onKeepRangeToggle={() => - onConfig({ - ...config, - useCurrentDashboardDataRange: !config.useCurrentDashboardDataRange, - }) - } - /> - ); -}; + render() { + const { config, onConfig } = this.props; + const { dashboards, selectedDashboard, isLoading } = this.state; + return ( + { + onConfig({ ...config, dashboardId }); + }} + onSearchChange={debounce(() => this.loadDashboards(), 500)} + onCurrentFiltersToggle={() => + onConfig({ + ...config, + useCurrentDashboardFilters: !config.useCurrentDashboardFilters, + }) + } + onKeepRangeToggle={() => + onConfig({ + ...config, + useCurrentDashboardDataRange: !config.useCurrentDashboardDataRange, + }) + } + /> + ); + } +} From 699d853b1e338eb2a641f02bb95dbf64d6eef51b Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Mon, 16 Mar 2020 18:59:29 -0500 Subject: [PATCH 04/81] storybook fix --- .../dashboard_drilldown_config.story.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx index de6897e56104d..0978af654e9c4 100644 --- a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx @@ -11,9 +11,9 @@ import { storiesOf } from '@storybook/react'; import { DashboardDrilldownConfig } from '.'; export const dashboards = [ - { id: 'dashboard1', title: 'Dashboard 1' }, - { id: 'dashboard2', title: 'Dashboard 2' }, - { id: 'dashboard3', title: 'Dashboard 3' }, + { value: 'dashboard1', label: 'Dashboard 1' }, + { value: 'dashboard2', label: 'Dashboard 2' }, + { value: 'dashboard3', label: 'Dashboard 3' }, ]; const InteractiveDemo: React.FC = () => { From d3ac7ad32b15051e41d55cc1d3ffff54a6f0d64a Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Mon, 16 Mar 2020 23:54:13 -0500 Subject: [PATCH 05/81] implement navigating to dashboard, seems like a type problem --- .../dashboard_to_dashboard_drilldown/drilldown.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index f991ef7d25c13..bc2341f2c8dac 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -53,7 +53,12 @@ export class DashboardToDashboardDrilldown return true; }; - public readonly execute = () => { - alert('Go to another dashboard!'); + // it seems like tthtis fn is being execute with the wrong arguments + // first param should be Config but its { config: Config; name: string; actionFactory: string; } ( I thtink ) + + // @ts-ignore + public readonly execute = async ({ config }: Config, context: ActionContext) => { + console.log('context', context); // eslint-disable-line + window.location.hash = `#/dashboard/${config.dashboardId}`; }; } From 43693993b02401d6c9e4a53d2e4b07032756ba44 Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Tue, 17 Mar 2020 00:45:32 -0500 Subject: [PATCH 06/81] try navToApp --- .../dashboard_to_dashboard_drilldown/drilldown.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index 5ba27423c5b8e..422d2d74ea99b 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -15,6 +15,7 @@ import { txtGoToDashboard } from './i18n'; export interface Params { getSavedObjectsClient: () => Promise; + getNavigateToApp: () => Promise; } export class DashboardToDashboardDrilldown @@ -48,12 +49,15 @@ export class DashboardToDashboardDrilldown return true; }; - // it seems like tthtis fn is being execute with the wrong arguments + // it seems like this fn is being execute with the wrong arguments // first param should be Config but its { config: Config; name: string; actionFactory: string; } ( I thtink ) // @ts-ignore public readonly execute = async ({ config }: Config, context: ActionContext) => { - console.log('context', context); // eslint-disable-line - window.location.hash = `#/dashboard/${config.dashboardId}`; + // todo - need to complete this + await this.params.getNavigateToApp().then(navigateToApp => { + navigateToApp('kibana', { path: `#/dashboard/${config.dashboardId}` }); + }); + // window.location.hash = `#/dashboard/${config.dashboardId}`; }; } From a276b964d07f6a5ab2065b92ec5fc107d5597083 Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Tue, 17 Mar 2020 17:39:14 -0500 Subject: [PATCH 07/81] filter out current dashboard --- .../collect_config.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx index cbced9024a8d3..2880f8dc9f902 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx @@ -11,6 +11,7 @@ import { CollectConfigProps } from './types'; import { DashboardDrilldownConfig } from '../../../components/dashboard_drilldown_config'; import { Params } from './drilldown'; import { SimpleSavedObject } from '../../../../../../../src/core/public'; +import { IEmbeddable } from '../../../../../../../src/plugins/embeddable/public'; const mergeDashboards = ( dashboards: Array>, @@ -34,6 +35,12 @@ const dashboardSavedObjectToMenuItem = ( export interface CollectConfigContainerProps extends CollectConfigProps { params: Params; + context: { + place: string; + placeContext: { + embeddable: IEmbeddable; + }; + }; } interface CollectConfigContainerState { @@ -75,6 +82,8 @@ export class CollectConfigContainer extends React.Component< } loadDashboards(searchString?: string) { + const currentDashboard = this.props.context.placeContext.embeddable.parent; + const currentDashboardId = currentDashboard && currentDashboard.id; this.setState({ searchString, isLoading: true }); this.props.params.getSavedObjectsClient().then(savedObjectsClient => { savedObjectsClient @@ -87,7 +96,9 @@ export class CollectConfigContainer extends React.Component< }) .then(({ savedObjects }) => { if (searchString === this.state.searchString) { - const dashboardList = savedObjects.map(dashboardSavedObjectToMenuItem); + const dashboardList = savedObjects + .map(dashboardSavedObjectToMenuItem) + .filter(({ value }) => value !== currentDashboardId); this.setState({ dashboards: dashboardList, isLoading: false }); } }); @@ -97,6 +108,7 @@ export class CollectConfigContainer extends React.Component< render() { const { config, onConfig } = this.props; const { dashboards, selectedDashboard, isLoading } = this.state; + return ( Date: Wed, 18 Mar 2020 01:13:13 -0500 Subject: [PATCH 08/81] rough draft linking to a dashboard --- .../public/np_ready/public/index.ts | 1 + src/plugins/dashboard/public/url_generator.ts | 4 +-- .../public/lib/triggers/triggers.ts | 6 ++-- x-pack/plugins/dashboard_enhanced/kibana.json | 2 +- .../dashboard_enhanced/public/plugin.ts | 2 ++ .../dashboard_drilldowns_services.ts | 8 +++++ .../collect_config.tsx | 14 ++++----- .../drilldown.tsx | 30 ++++++++++++------- .../dashboard_to_dashboard_drilldown/types.ts | 5 ++-- 9 files changed, 48 insertions(+), 24 deletions(-) diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts index b59eb2277411c..92c5af1413545 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts @@ -41,6 +41,7 @@ export { VisTypeAlias, VisType } from './vis_types'; export { VisSavedObject } from './types'; export { Vis, VisParams, VisState } from './vis'; import { VisualizeEmbeddableFactory, VisualizeEmbeddable } from './embeddable'; +export { VisualizeEmbeddable }; export type VisualizeEmbeddableFactoryContract = PublicContract; export type VisualizeEmbeddableContract = PublicContract; export { TypesService } from './vis_types/types_service'; diff --git a/src/plugins/dashboard/public/url_generator.ts b/src/plugins/dashboard/public/url_generator.ts index 5f1255bc9d45f..174493eaad50e 100644 --- a/src/plugins/dashboard/public/url_generator.ts +++ b/src/plugins/dashboard/public/url_generator.ts @@ -61,7 +61,7 @@ export const createDirectAccessDashboardLinkGenerator = ( createUrl: async state => { const startServices = await getStartServices(); const useHash = state.useHash ?? startServices.useHashedUrl; - const appBasePath = startServices.appBasePath; + // const appBasePath = startServices.appBasePath; const hash = state.dashboardId ? `dashboard/${state.dashboardId}` : `dashboard`; const appStateUrl = setStateToKbnUrl( @@ -71,7 +71,7 @@ export const createDirectAccessDashboardLinkGenerator = ( filters: state.filters, }, { useHash }, - `${appBasePath}#/${hash}` + `kibana#/${hash}` // use appBasePath once dashboards is migrated, using 'kibana' for now ); return setStateToKbnUrl( diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index 0052403816eb8..651b64eddd58b 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -24,8 +24,10 @@ export interface EmbeddableContext { embeddable: IEmbeddable; } -export interface EmbeddableVisTriggerContext { - embeddable: IEmbeddable; +// I think this could benefit using a type variable for IEmbeddable +// but I'm concerned that the change will touch many places +export interface EmbeddableVisTriggerContext { + embeddable: T; timeFieldName: string; data: { e: MouseEvent; diff --git a/x-pack/plugins/dashboard_enhanced/kibana.json b/x-pack/plugins/dashboard_enhanced/kibana.json index a9b6920ae369e..11ef2c925f6c8 100644 --- a/x-pack/plugins/dashboard_enhanced/kibana.json +++ b/x-pack/plugins/dashboard_enhanced/kibana.json @@ -3,5 +3,5 @@ "version": "kibana", "server": false, "ui": true, - "requiredPlugins": ["uiActions", "embeddable", "drilldowns"] + "requiredPlugins": ["uiActions", "embeddable", "drilldowns", "share"] } diff --git a/x-pack/plugins/dashboard_enhanced/public/plugin.ts b/x-pack/plugins/dashboard_enhanced/public/plugin.ts index 447ceff4b8cb2..5f28ab109bfa0 100644 --- a/x-pack/plugins/dashboard_enhanced/public/plugin.ts +++ b/x-pack/plugins/dashboard_enhanced/public/plugin.ts @@ -6,6 +6,7 @@ import { CoreStart, CoreSetup, Plugin } from 'src/core/public'; import { UiActionsSetup, UiActionsStart } from '../../../../src/plugins/ui_actions/public'; +import { SharePluginStart } from '../../../../src/plugins/share/public'; import { DashboardDrilldownsService } from './services'; import { DrilldownsSetupContract, DrilldownsStartContract } from '../../drilldowns/public'; @@ -17,6 +18,7 @@ export interface SetupDependencies { export interface StartDependencies { uiActions: UiActionsStart; drilldowns: DrilldownsStartContract; + share: SharePluginStart; } // eslint-disable-next-line diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts index 34d1ccafc8861..69c48a6f44fdb 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts @@ -35,6 +35,12 @@ export class DashboardDrilldownsService { const drilldowns = async () => (await core.getStartServices())[1].drilldowns; const getSavedObjectsClient = async () => (await core.getStartServices())[0].savedObjects.client; + const getNavigateToApp = async () => + (await core.getStartServices())[0].application.navigateToApp; + + const getGetUrlGenerator = async () => + // @ts-ignore + (await core.getStartServices())[1].share.urlGenerators.getUrlGenerator; const actionFlyoutCreateDrilldown = new FlyoutCreateDrilldownAction({ overlays, drilldowns }); plugins.uiActions.registerAction(actionFlyoutCreateDrilldown); @@ -46,6 +52,8 @@ export class DashboardDrilldownsService { const dashboardToDashboardDrilldown = new DashboardToDashboardDrilldown({ getSavedObjectsClient, + getGetUrlGenerator, + getNavigateToApp, }); plugins.drilldowns.registerDrilldown(dashboardToDashboardDrilldown); } diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx index 2880f8dc9f902..b95d855ed52b3 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx @@ -82,8 +82,8 @@ export class CollectConfigContainer extends React.Component< } loadDashboards(searchString?: string) { - const currentDashboard = this.props.context.placeContext.embeddable.parent; - const currentDashboardId = currentDashboard && currentDashboard.id; + // const currentDashboard = this.props.context.placeContext.embeddable.parent; + // const currentDashboardId = currentDashboard && currentDashboard.id; this.setState({ searchString, isLoading: true }); this.props.params.getSavedObjectsClient().then(savedObjectsClient => { savedObjectsClient @@ -96,9 +96,9 @@ export class CollectConfigContainer extends React.Component< }) .then(({ savedObjects }) => { if (searchString === this.state.searchString) { - const dashboardList = savedObjects - .map(dashboardSavedObjectToMenuItem) - .filter(({ value }) => value !== currentDashboardId); + const dashboardList = savedObjects.map(dashboardSavedObjectToMenuItem); + // temporarily disable for dev purposes + // .filter(({ value }) => value !== currentDashboardId); this.setState({ dashboards: dashboardList, isLoading: false }); } }); @@ -114,7 +114,7 @@ export class CollectConfigContainer extends React.Component< activeDashboardId={config.dashboardId} dashboards={mergeDashboards(dashboards, selectedDashboard)} currentFilters={config.useCurrentDashboardFilters} - keepRange={config.useCurrentDashboardDataRange} + keepRange={config.useCurrentDashboardDateRange} isLoading={isLoading} onDashboardSelect={dashboardId => { onConfig({ ...config, dashboardId }); @@ -129,7 +129,7 @@ export class CollectConfigContainer extends React.Component< onKeepRangeToggle={() => onConfig({ ...config, - useCurrentDashboardDataRange: !config.useCurrentDashboardDataRange, + useCurrentDashboardDateRange: !config.useCurrentDashboardDateRange, }) } /> diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index 422d2d74ea99b..28c2a8ef726b4 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -7,6 +7,9 @@ import React from 'react'; import { CoreStart } from 'src/core/public'; import { reactToUiComponent } from '../../../../../../../src/plugins/kibana_react/public'; +import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; +import { DASHBOARD_APP_URL_GENERATOR } from '../../../../../../../src/plugins/dashboard/public'; +import { VisualizeEmbeddable } from '../../../../../../../src/legacy/core_plugins/visualizations/public'; import { FactoryContext, ActionContext, Config, CollectConfigProps } from './types'; import { CollectConfigContainer } from './collect_config'; import { DASHBOARD_TO_DASHBOARD_DRILLDOWN } from './constants'; @@ -16,10 +19,11 @@ import { txtGoToDashboard } from './i18n'; export interface Params { getSavedObjectsClient: () => Promise; getNavigateToApp: () => Promise; + getGetUrlGenerator: () => Promise; } export class DashboardToDashboardDrilldown - implements Drilldown { + implements Drilldown> { constructor(protected readonly params: Params) {} // TODO: public readonly places = ['dashboard']; @@ -40,7 +44,7 @@ export class DashboardToDashboardDrilldown public readonly createConfig = () => ({ dashboardId: '', - useCurrentDashboardDataRange: true, + useCurrentDashboardDateRange: true, useCurrentDashboardFilters: true, }); @@ -49,15 +53,21 @@ export class DashboardToDashboardDrilldown return true; }; - // it seems like this fn is being execute with the wrong arguments - // first param should be Config but its { config: Config; name: string; actionFactory: string; } ( I thtink ) - - // @ts-ignore - public readonly execute = async ({ config }: Config, context: ActionContext) => { + public readonly execute = async (config: Config, context: ActionContext) => { // todo - need to complete this - await this.params.getNavigateToApp().then(navigateToApp => { - navigateToApp('kibana', { path: `#/dashboard/${config.dashboardId}` }); + // console.log('DEBUG', config, context); + // need to change date range and filter based on config + const getUrlGenerator = await this.params.getGetUrlGenerator(); + const navigateToApp = await this.params.getNavigateToApp(); + const { timeRange, query, filters } = context.embeddable.getInput(); + + const dashboardPath = await getUrlGenerator(DASHBOARD_APP_URL_GENERATOR).createUrl({ + dashboardId: config.dashboardId, + timeRange, + query, + filters, }); - // window.location.hash = `#/dashboard/${config.dashboardId}`; + + navigateToApp(dashboardPath); }; } diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts index 74be9c328f7f2..800896dffa9e3 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts @@ -7,16 +7,17 @@ import { EmbeddableVisTriggerContext, EmbeddableContext, + IEmbeddable, } from '../../../../../../../src/plugins/embeddable/public'; import { UiActionsCollectConfigProps } from '../../../../../../../src/plugins/ui_actions/public'; export type FactoryContext = EmbeddableContext; -export type ActionContext = EmbeddableVisTriggerContext; +export type ActionContext = EmbeddableVisTriggerContext; export interface Config { dashboardId?: string; useCurrentDashboardFilters: boolean; - useCurrentDashboardDataRange: boolean; + useCurrentDashboardDateRange: boolean; } export type CollectConfigProps = UiActionsCollectConfigProps; From 0bbf360b1779feb959838df983c799e97f41334e Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Wed, 18 Mar 2020 01:27:22 -0500 Subject: [PATCH 09/81] remove note --- src/plugins/embeddable/public/lib/triggers/triggers.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index 651b64eddd58b..4b1d3575f2950 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -24,8 +24,6 @@ export interface EmbeddableContext { embeddable: IEmbeddable; } -// I think this could benefit using a type variable for IEmbeddable -// but I'm concerned that the change will touch many places export interface EmbeddableVisTriggerContext { embeddable: T; timeFieldName: string; From 636d9abbad2d394efec0731df7f4ee1054e1eb45 Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Wed, 18 Mar 2020 01:31:54 -0500 Subject: [PATCH 10/81] typefix --- x-pack/plugins/dashboard_enhanced/public/plugin.ts | 3 ++- .../services/drilldowns/dashboard_drilldowns_services.ts | 9 ++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/plugin.ts b/x-pack/plugins/dashboard_enhanced/public/plugin.ts index 5f28ab109bfa0..922e149ee86ea 100644 --- a/x-pack/plugins/dashboard_enhanced/public/plugin.ts +++ b/x-pack/plugins/dashboard_enhanced/public/plugin.ts @@ -6,13 +6,14 @@ import { CoreStart, CoreSetup, Plugin } from 'src/core/public'; import { UiActionsSetup, UiActionsStart } from '../../../../src/plugins/ui_actions/public'; -import { SharePluginStart } from '../../../../src/plugins/share/public'; +import { SharePluginStart, SharePluginSetup } from '../../../../src/plugins/share/public'; import { DashboardDrilldownsService } from './services'; import { DrilldownsSetupContract, DrilldownsStartContract } from '../../drilldowns/public'; export interface SetupDependencies { uiActions: UiActionsSetup; drilldowns: DrilldownsSetupContract; + share: SharePluginSetup; } export interface StartDependencies { diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts index 69c48a6f44fdb..8920bc6decda3 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts @@ -5,7 +5,7 @@ */ import { CoreSetup } from 'src/core/public'; -import { SetupDependencies } from '../../plugin'; +import { SetupDependencies, StartDependencies } from '../../plugin'; import { CONTEXT_MENU_TRIGGER, EmbeddableContext, @@ -16,7 +16,6 @@ import { OPEN_FLYOUT_ADD_DRILLDOWN, OPEN_FLYOUT_EDIT_DRILLDOWN, } from './actions'; -import { DrilldownsStartContract } from '../../../../drilldowns/public'; import { DashboardToDashboardDrilldown } from './dashboard_to_dashboard_drilldown'; declare module '../../../../../../src/plugins/ui_actions/public' { @@ -27,10 +26,7 @@ declare module '../../../../../../src/plugins/ui_actions/public' { } export class DashboardDrilldownsService { - async bootstrap( - core: CoreSetup<{ drilldowns: DrilldownsStartContract }>, - plugins: SetupDependencies - ) { + async bootstrap(core: CoreSetup, plugins: SetupDependencies) { const overlays = async () => (await core.getStartServices())[0].overlays; const drilldowns = async () => (await core.getStartServices())[1].drilldowns; const getSavedObjectsClient = async () => @@ -39,7 +35,6 @@ export class DashboardDrilldownsService { (await core.getStartServices())[0].application.navigateToApp; const getGetUrlGenerator = async () => - // @ts-ignore (await core.getStartServices())[1].share.urlGenerators.getUrlGenerator; const actionFlyoutCreateDrilldown = new FlyoutCreateDrilldownAction({ overlays, drilldowns }); From 6ea19aa12776d5551afe35f57625b1fb1ce9b344 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 18 Mar 2020 18:41:03 +0100 Subject: [PATCH 11/81] fix navigation from dashboard to dashboard except for back button - that would be addressed separatly --- .../np_ready/dashboard_state_manager.ts | 7 +++++ .../dashboard/np_ready/url_helper.test.ts | 27 +++++++++++++++++ .../public/dashboard/np_ready/url_helper.ts | 21 ++++++++++++++ .../public/np_ready/public/index.ts | 1 - .../dashboard/public/url_generator.test.ts | 2 +- src/plugins/dashboard/public/url_generator.ts | 29 ++++++++++++------- .../drilldown.tsx | 25 +++++++++------- 7 files changed, 90 insertions(+), 22 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts index f29721e3c3d5c..6b426d8d5344e 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts @@ -50,6 +50,7 @@ import { ReduxLikeStateContainer, syncState, } from '../../../../../../plugins/kibana_utils/public'; +import { getDashboardIdFromUrl } from './url_helper'; /** * Dashboard state manager handles connecting angular and redux state between the angular and react portions of the @@ -174,6 +175,12 @@ export class DashboardStateManager { // sync state required state container to be able to handle null // overriding set() so it could handle null coming from url if (state) { + // Skip this update if current dashboardId in the url is different from what we have in current instance of state manager + // Because dashboard is driven by angular, the destroy cycle happens async, + // And we should not to interfere into state change longer as this instance will be destroyed soon + const currentDashboardIdInUrl = getDashboardIdFromUrl(history.location.pathname); + if (currentDashboardIdInUrl !== this.savedDashboard.id) return; + this.stateContainer.set({ ...this.stateDefaults, ...state, diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.test.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.test.ts index 60ca1b39d29d6..15079d86f2679 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.test.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.test.ts @@ -45,6 +45,7 @@ jest.mock('../legacy_imports', () => { import { addEmbeddableToDashboardUrl, + getDashboardIdFromUrl, getLensUrlFromDashboardAbsoluteUrl, getUrlVars, } from './url_helper'; @@ -115,4 +116,30 @@ describe('Dashboard URL Helper', () => { 'http://localhost:5601/app/kibana#/lens/edit/1244' ); }); + + it('getDashboardIdFromDashboardUrl', () => { + let url = + "http://localhost:5601/wev/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()"; + expect(getDashboardIdFromUrl(url)).toEqual(undefined); + + url = + "http://localhost:5601/wev/app/kibana#/dashboard/625357282?_a=(description:'',filters:!()&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))"; + expect(getDashboardIdFromUrl(url)).toEqual('625357282'); + + url = 'http://myserver.mydomain.com:5601/wev/app/kibana#/dashboard/777182'; + expect(getDashboardIdFromUrl(url)).toEqual('777182'); + + url = + "http://localhost:5601/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()"; + expect(getDashboardIdFromUrl(url)).toEqual(undefined); + + url = '/dashboard/test/?_g=(refreshInterval:'; + expect(getDashboardIdFromUrl(url)).toEqual('test'); + + url = 'dashboard/test/?_g=(refreshInterval:'; + expect(getDashboardIdFromUrl(url)).toEqual('test'); + + url = '/other-app/test/'; + expect(getDashboardIdFromUrl(url)).toEqual(undefined); + }); }); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.ts index 73383f2ff3f68..dfa1e77fa54cd 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.ts @@ -98,3 +98,24 @@ export function getLensUrlFromDashboardAbsoluteUrl( function getUrlWithoutQueryParams(url: string): string { return url.split('?')[0]; } + +/** + * Returns dashboard id from URL + * literally looks from id after `dashboard/` string and before `/`, `?` and end of string + * @param url to extract dashboardId from + * input: http://localhost:5601/lib/app/kibana#/dashboard?param1=x¶m2=y¶m3=z + * output: undefined + * input: http://localhost:5601/lib/app/kibana#/dashboard/39292992?param1=x¶m2=y¶m3=z + * output: 39292992 + */ +export function getDashboardIdFromUrl(url: string): string | undefined { + const [, match1, match2, match3] = url.match( + /dashboard\/(.*)\/|dashboard\/(.*)\?|dashboard\/(.*)$/ + ) ?? [ + undefined, // full match + undefined, // group1 - dashboardId is before `/` + undefined, // group2 - dashboardId is before `?` + undefined, // group3 - dashboardID is in the end + ]; + return match1 ?? match2 ?? match3 ?? undefined; +} diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts index 92c5af1413545..b59eb2277411c 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts @@ -41,7 +41,6 @@ export { VisTypeAlias, VisType } from './vis_types'; export { VisSavedObject } from './types'; export { Vis, VisParams, VisState } from './vis'; import { VisualizeEmbeddableFactory, VisualizeEmbeddable } from './embeddable'; -export { VisualizeEmbeddable }; export type VisualizeEmbeddableFactoryContract = PublicContract; export type VisualizeEmbeddableContract = PublicContract; export { TypesService } from './vis_types/types_service'; diff --git a/src/plugins/dashboard/public/url_generator.test.ts b/src/plugins/dashboard/public/url_generator.test.ts index 5dfc47b694f60..8005619aad9d2 100644 --- a/src/plugins/dashboard/public/url_generator.test.ts +++ b/src/plugins/dashboard/public/url_generator.test.ts @@ -70,7 +70,7 @@ describe('dashboard url generator', () => { query: { query: 'bye', language: 'kuery' }, }); expect(url).toMatchInlineSnapshot( - `"xyz/app/kibana#/dashboard/123?_a=(filters:!((meta:(alias:!n,disabled:!f,negate:!f),query:(query:hi))),query:(language:kuery,query:bye))&_g=(time:(from:now-15m,mode:relative,to:now))"` + `"xyz/app/kibana#/dashboard/123?_a=(filters:!((meta:(alias:!n,disabled:!f,negate:!f),query:(query:hi))),query:(language:kuery,query:bye))&_g=(filters:!(),time:(from:now-15m,mode:relative,to:now))"` ); }); diff --git a/src/plugins/dashboard/public/url_generator.ts b/src/plugins/dashboard/public/url_generator.ts index 174493eaad50e..f7af0f13bf1f2 100644 --- a/src/plugins/dashboard/public/url_generator.ts +++ b/src/plugins/dashboard/public/url_generator.ts @@ -17,7 +17,7 @@ * under the License. */ -import { TimeRange, Filter, Query } from '../../data/public'; +import { TimeRange, Filter, Query, esFilters } from '../../data/public'; import { setStateToKbnUrl } from '../../kibana_utils/public'; import { UrlGeneratorsDefinition, UrlGeneratorState } from '../../share/public'; @@ -38,8 +38,7 @@ export type DashboardAppLinkGeneratorState = UrlGeneratorState<{ timeRange?: TimeRange; /** * Optionally apply filers. NOTE: if given and used in conjunction with `dashboardId`, and the - * saved dashboard has filters saved with it, this will _replace_ those filters. This will set - * app filters, not global filters. + * saved dashboard has filters saved with it, this will _replace_ those filters. */ filters?: Filter[]; /** @@ -61,24 +60,34 @@ export const createDirectAccessDashboardLinkGenerator = ( createUrl: async state => { const startServices = await getStartServices(); const useHash = state.useHash ?? startServices.useHashedUrl; - // const appBasePath = startServices.appBasePath; + const appBasePath = startServices.appBasePath; const hash = state.dashboardId ? `dashboard/${state.dashboardId}` : `dashboard`; + const cleanEmptyStateKeys = (stateObj: Record) => { + Object.keys(stateObj).forEach(key => { + if (stateObj[key] === undefined) { + delete stateObj[key]; + } + }); + return stateObj; + }; + const appStateUrl = setStateToKbnUrl( STATE_STORAGE_KEY, - { + cleanEmptyStateKeys({ query: state.query, - filters: state.filters, - }, + filters: state.filters?.filter(f => !esFilters.isFilterPinned(f)), + }), { useHash }, - `kibana#/${hash}` // use appBasePath once dashboards is migrated, using 'kibana' for now + `${appBasePath}#/${hash}` ); return setStateToKbnUrl( GLOBAL_STATE_STORAGE_KEY, - { + cleanEmptyStateKeys({ time: state.timeRange, - }, + filters: state.filters?.filter(f => esFilters.isFilterPinned(f)), + }), { useHash }, appStateUrl ); diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index 28c2a8ef726b4..778953fe1e8f1 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -9,12 +9,13 @@ import { CoreStart } from 'src/core/public'; import { reactToUiComponent } from '../../../../../../../src/plugins/kibana_react/public'; import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; import { DASHBOARD_APP_URL_GENERATOR } from '../../../../../../../src/plugins/dashboard/public'; -import { VisualizeEmbeddable } from '../../../../../../../src/legacy/core_plugins/visualizations/public'; +import { VisualizeEmbeddableContract } from '../../../../../../../src/legacy/core_plugins/visualizations/public'; import { FactoryContext, ActionContext, Config, CollectConfigProps } from './types'; import { CollectConfigContainer } from './collect_config'; import { DASHBOARD_TO_DASHBOARD_DRILLDOWN } from './constants'; import { DrilldownsDrilldown as Drilldown } from '../../../../../drilldowns/public'; import { txtGoToDashboard } from './i18n'; +import { esFilters } from '../../../../../../../src/plugins/data/public'; export interface Params { getSavedObjectsClient: () => Promise; @@ -23,7 +24,7 @@ export interface Params { } export class DashboardToDashboardDrilldown - implements Drilldown> { + implements Drilldown> { constructor(protected readonly params: Params) {} // TODO: public readonly places = ['dashboard']; @@ -53,21 +54,25 @@ export class DashboardToDashboardDrilldown return true; }; - public readonly execute = async (config: Config, context: ActionContext) => { - // todo - need to complete this - // console.log('DEBUG', config, context); - // need to change date range and filter based on config + public readonly execute = async ( + config: Config, + context: ActionContext + ) => { const getUrlGenerator = await this.params.getGetUrlGenerator(); const navigateToApp = await this.params.getNavigateToApp(); const { timeRange, query, filters } = context.embeddable.getInput(); const dashboardPath = await getUrlGenerator(DASHBOARD_APP_URL_GENERATOR).createUrl({ dashboardId: config.dashboardId, - timeRange, query, - filters, + timeRange: config.useCurrentDashboardDateRange ? timeRange : undefined, + filters: config.useCurrentDashboardFilters + ? filters + : filters?.filter(f => esFilters.isFilterPinned(f)), + }); + const dashboardHash = dashboardPath.split('#')[1]; + await navigateToApp('kibana', { + path: `#${dashboardHash}`, }); - - navigateToApp(dashboardPath); }; } From a431e86daf420d6ac8985073e0eeb2e1431d9dfb Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Fri, 20 Mar 2020 01:19:32 -0500 Subject: [PATCH 12/81] partial progress getting filters from action data --- .../filters/create_filters_from_event.ts | 5 + src/plugins/data/public/actions/index.ts | 4 +- .../public/actions/select_range_action.ts | 69 ++++---- .../data/public/actions/value_click_action.ts | 147 ++++++++++-------- src/plugins/data/public/index.ts | 2 + .../collect_config.tsx | 22 +-- .../drilldown.tsx | 35 ++++- .../dashboard_to_dashboard_drilldown/types.ts | 18 ++- 8 files changed, 183 insertions(+), 119 deletions(-) diff --git a/src/plugins/data/public/actions/filters/create_filters_from_event.ts b/src/plugins/data/public/actions/filters/create_filters_from_event.ts index e62945a592072..8b6135a246ce1 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_event.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_event.ts @@ -84,6 +84,11 @@ const createFilter = async (table: EventData['table'], columnIndex: number, rowI if (!column.meta || !column.meta.indexPatternId) { return; } + console.log('aggConfig', column.meta.indexPatternId); // eslint-disable-line + console.log( // eslint-disable-line + 'This fails, but not always', + await getIndexPatterns().get(column.meta.indexPatternId) + ); const aggConfig = deserializeAggConfig({ type: column.meta.type, aggConfigParams: column.meta.aggConfigParams ? column.meta.aggConfigParams : {}, diff --git a/src/plugins/data/public/actions/index.ts b/src/plugins/data/public/actions/index.ts index cdb84ff13f25e..105229e2bd81a 100644 --- a/src/plugins/data/public/actions/index.ts +++ b/src/plugins/data/public/actions/index.ts @@ -19,5 +19,5 @@ export { ACTION_GLOBAL_APPLY_FILTER, createFilterAction } from './apply_filter_action'; export { createFiltersFromEvent } from './filters/create_filters_from_event'; -export { selectRangeAction } from './select_range_action'; -export { valueClickAction } from './value_click_action'; +export { selectRangeAction, selectRangeActionGetFilters } from './select_range_action'; +export { valueClickAction, valueClickActionGetFilters } from './value_click_action'; diff --git a/src/plugins/data/public/actions/select_range_action.ts b/src/plugins/data/public/actions/select_range_action.ts index 6e1f16a09e803..c5358285acf1b 100644 --- a/src/plugins/data/public/actions/select_range_action.ts +++ b/src/plugins/data/public/actions/select_range_action.ts @@ -34,13 +34,45 @@ export interface SelectRangeActionContext { } async function isCompatible(context: SelectRangeActionContext) { - try { - return Boolean(await onBrushEvent(context.data)); - } catch { - return false; - } + // try { + return Boolean(await onBrushEvent(context.data)); + // } catch { + // return false; + // } } +export const selectRangeActionGetFilters = async ({ + timeFieldName, + data, +}: SelectRangeActionContext) => { + if (!(await isCompatible({ timeFieldName, data }))) { + throw new IncompatibleActionError(); + } + + const filter = await onBrushEvent(data); + + if (!filter) { + return; + } + + const selectedFilters = esFilters.mapAndFlattenFilters([filter]); + + return esFilters.extractTimeFilter(timeFieldName || '', selectedFilters); +}; + +const selectRangeActionExecute = ( + filterManager: FilterManager, + timeFilter: TimefilterContract +) => async ({ timeFieldName, data }: SelectRangeActionContext) => { + const { timeRangeFilter, restOfFilters } = + (await selectRangeActionGetFilters({ timeFieldName, data })) || {}; + + filterManager.addFilters(restOfFilters || []); + if (timeRangeFilter) { + esFilters.changeTimeFilter(timeFilter, timeRangeFilter); + } +}; + export function selectRangeAction( filterManager: FilterManager, timeFilter: TimefilterContract @@ -54,31 +86,6 @@ export function selectRangeAction( }); }, isCompatible, - execute: async ({ timeFieldName, data }: SelectRangeActionContext) => { - if (!(await isCompatible({ timeFieldName, data }))) { - throw new IncompatibleActionError(); - } - - const filter = await onBrushEvent(data); - - if (!filter) { - return; - } - - const selectedFilters = esFilters.mapAndFlattenFilters([filter]); - - if (timeFieldName) { - const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( - timeFieldName, - selectedFilters - ); - filterManager.addFilters(restOfFilters); - if (timeRangeFilter) { - esFilters.changeTimeFilter(timeFilter, timeRangeFilter); - } - } else { - filterManager.addFilters(selectedFilters); - } - }, + execute: selectRangeActionExecute(filterManager, timeFilter), }); } diff --git a/src/plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts index 01c32e27da07d..d2f7d7cc0272f 100644 --- a/src/plugins/data/public/actions/value_click_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -18,6 +18,7 @@ */ import { i18n } from '@kbn/i18n'; +import { RangeFilter } from 'src/plugins/data/public'; import { toMountPoint } from '../../../../plugins/kibana_react/public'; import { ActionByType, @@ -37,16 +38,90 @@ export interface ValueClickActionContext { } async function isCompatible(context: ValueClickActionContext) { - try { - const filters: Filter[] = - (await createFiltersFromEvent(context.data.data || [context.data], context.data.negate)) || - []; - return filters.length > 0; - } catch { - return false; - } + // try { + const filters: Filter[] = + (await createFiltersFromEvent(context.data.data || [context.data], context.data.negate)) || []; + return filters.length > 0; + // } catch { + // return false; + // } } +// this allows the user to select which filter to use +const filterSelectionFn = (filters: Filter[]): Promise => + new Promise(async resolve => { + const indexPatterns = await Promise.all( + filters.map(filter => { + return getIndexPatterns().get(filter.meta.index!); + }) + ); + + const overlay = getOverlays().openModal( + toMountPoint( + applyFiltersPopover( + filters, + indexPatterns, + () => { + overlay.close(); + resolve([]); + }, + (filterSelection: Filter[]) => { + overlay.close(); + resolve(filterSelection); + } + ) + ), + { + 'data-test-subj': 'selectFilterOverlay', + } + ); + }); + +// given a ValueClickActionContext, returns timeRangeFilter and Filters +export const valueClickActionGetFilters = async ( + { timeFieldName, data }: ValueClickActionContext, + filterSelection: (filters: Filter[]) => Promise = async (filters: Filter[]) => filters +): Promise<{ + timeRangeFilter?: RangeFilter; + restOfFilters: Filter[]; +}> => { + if (!(await isCompatible({ timeFieldName, data }))) { + throw new IncompatibleActionError(); + } + + // + const filters: Filter[] = (await createFiltersFromEvent(data.data || [data], data.negate)) || []; + + let selectedFilters: Filter[] = esFilters.mapAndFlattenFilters(filters); + // filters + + if (selectedFilters.length > 1) { + selectedFilters = await filterSelection(filters); + } + + return esFilters.extractTimeFilter(timeFieldName || '', selectedFilters); +}; + +// gets and applies the filters +export const valueClickActionExecute = ( + filterManager: FilterManager, + timeFilter: TimefilterContract, + filterSelection: (filters: Filter[]) => Promise = async (filters: Filter[]) => filters +) => async ({ timeFieldName, data }: ValueClickActionContext) => { + const { timeRangeFilter, restOfFilters } = await valueClickActionGetFilters( + { + timeFieldName, + data, + }, + filterSelection + ); + + filterManager.addFilters(restOfFilters); + if (timeRangeFilter) { + esFilters.changeTimeFilter(timeFilter, timeRangeFilter); + } +}; + export function valueClickAction( filterManager: FilterManager, timeFilter: TimefilterContract @@ -60,60 +135,6 @@ export function valueClickAction( }); }, isCompatible, - execute: async ({ timeFieldName, data }: ValueClickActionContext) => { - if (!(await isCompatible({ timeFieldName, data }))) { - throw new IncompatibleActionError(); - } - - const filters: Filter[] = - (await createFiltersFromEvent(data.data || [data], data.negate)) || []; - - let selectedFilters: Filter[] = esFilters.mapAndFlattenFilters(filters); - - if (selectedFilters.length > 1) { - const indexPatterns = await Promise.all( - filters.map(filter => { - return getIndexPatterns().get(filter.meta.index!); - }) - ); - - const filterSelectionPromise: Promise = new Promise(resolve => { - const overlay = getOverlays().openModal( - toMountPoint( - applyFiltersPopover( - filters, - indexPatterns, - () => { - overlay.close(); - resolve([]); - }, - (filterSelection: Filter[]) => { - overlay.close(); - resolve(filterSelection); - } - ) - ), - { - 'data-test-subj': 'selectFilterOverlay', - } - ); - }); - - selectedFilters = await filterSelectionPromise; - } - - if (timeFieldName) { - const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( - timeFieldName, - selectedFilters - ); - filterManager.addFilters(restOfFilters); - if (timeRangeFilter) { - esFilters.changeTimeFilter(timeFilter, timeRangeFilter); - } - } else { - filterManager.addFilters(selectedFilters); - } - }, + execute: valueClickActionExecute(filterManager, timeFilter, filterSelectionFn), }); } diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 58bd9a5ab05d7..e4d708c3f28a8 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -450,6 +450,8 @@ export { getKbnTypeNames, } from '../common'; +export { valueClickActionGetFilters, selectRangeActionGetFilters } from './actions'; + /* * Plugin setup */ diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx index b95d855ed52b3..3866fe95f5011 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx @@ -9,9 +9,7 @@ import { EuiComboBoxOptionOption } from '@elastic/eui'; import { debounce, findIndex } from 'lodash'; import { CollectConfigProps } from './types'; import { DashboardDrilldownConfig } from '../../../components/dashboard_drilldown_config'; -import { Params } from './drilldown'; import { SimpleSavedObject } from '../../../../../../../src/core/public'; -import { IEmbeddable } from '../../../../../../../src/plugins/embeddable/public'; const mergeDashboards = ( dashboards: Array>, @@ -33,16 +31,6 @@ const dashboardSavedObjectToMenuItem = ( label: savedObject.attributes.title, }); -export interface CollectConfigContainerProps extends CollectConfigProps { - params: Params; - context: { - place: string; - placeContext: { - embeddable: IEmbeddable; - }; - }; -} - interface CollectConfigContainerState { dashboards: Array>; searchString?: string; @@ -52,7 +40,7 @@ interface CollectConfigContainerState { } export class CollectConfigContainer extends React.Component< - CollectConfigContainerProps, + CollectConfigProps, CollectConfigContainerState > { state = { @@ -70,7 +58,7 @@ export class CollectConfigContainer extends React.Component< loadSelectedDashboard() { const { config } = this.props; - this.props.params.getSavedObjectsClient().then(savedObjectsClient => { + this.props.deps.getSavedObjectsClient().then(savedObjectsClient => { if (config.dashboardId) { savedObjectsClient .get<{ title: string }>('dashboard', config.dashboardId) @@ -85,7 +73,7 @@ export class CollectConfigContainer extends React.Component< // const currentDashboard = this.props.context.placeContext.embeddable.parent; // const currentDashboardId = currentDashboard && currentDashboard.id; this.setState({ searchString, isLoading: true }); - this.props.params.getSavedObjectsClient().then(savedObjectsClient => { + this.props.deps.getSavedObjectsClient().then(savedObjectsClient => { savedObjectsClient .find<{ title: string }>({ type: 'dashboard', @@ -114,7 +102,7 @@ export class CollectConfigContainer extends React.Component< activeDashboardId={config.dashboardId} dashboards={mergeDashboards(dashboards, selectedDashboard)} currentFilters={config.useCurrentDashboardFilters} - keepRange={config.useCurrentDashboardDateRange} + keepRange={config.useCurrentDashboardDataRange} isLoading={isLoading} onDashboardSelect={dashboardId => { onConfig({ ...config, dashboardId }); @@ -129,7 +117,7 @@ export class CollectConfigContainer extends React.Component< onKeepRangeToggle={() => onConfig({ ...config, - useCurrentDashboardDateRange: !config.useCurrentDashboardDateRange, + useCurrentDashboardDataRange: !config.useCurrentDashboardDataRange, }) } /> diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index 778953fe1e8f1..f1be2e7b72ca4 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -15,7 +15,11 @@ import { CollectConfigContainer } from './collect_config'; import { DASHBOARD_TO_DASHBOARD_DRILLDOWN } from './constants'; import { DrilldownsDrilldown as Drilldown } from '../../../../../drilldowns/public'; import { txtGoToDashboard } from './i18n'; -import { esFilters } from '../../../../../../../src/plugins/data/public'; +import { + esFilters, + valueClickActionGetFilters, + selectRangeActionGetFilters, +} from '../../../../../../../src/plugins/data/public'; export interface Params { getSavedObjectsClient: () => Promise; @@ -38,14 +42,14 @@ export class DashboardToDashboardDrilldown public readonly euiIcon = 'dashboardApp'; private readonly ReactCollectConfig: React.FC = props => ( - + ); public readonly CollectConfig = reactToUiComponent(this.ReactCollectConfig); public readonly createConfig = () => ({ dashboardId: '', - useCurrentDashboardDateRange: true, + useCurrentDashboardDataRange: true, useCurrentDashboardFilters: true, }); @@ -58,19 +62,42 @@ export class DashboardToDashboardDrilldown config: Config, context: ActionContext ) => { + console.log('drilldown execute'); // eslint-disable-line const getUrlGenerator = await this.params.getGetUrlGenerator(); const navigateToApp = await this.params.getNavigateToApp(); const { timeRange, query, filters } = context.embeddable.getInput(); + // @ts-ignore + if (context.data.range) { + // look up by range + const { restOfFilters, timeRangeFilter } = + (await selectRangeActionGetFilters({ + timeFieldName: context.timeFieldName, + data: context.data, + })) || {}; + console.log('select range action filters', restOfFilters, timeRangeFilter); // eslint-disable-line + // selectRangeActionGetFilters + } else { + const { restOfFilters, timeRangeFilter } = await valueClickActionGetFilters({ + timeFieldName: context.timeFieldName, + data: context.data, + }); + console.log('value click action filters', restOfFilters, timeRangeFilter); // eslint-disable-line + } + const dashboardPath = await getUrlGenerator(DASHBOARD_APP_URL_GENERATOR).createUrl({ dashboardId: config.dashboardId, query, - timeRange: config.useCurrentDashboardDateRange ? timeRange : undefined, + // todo - how to get destination dashboard timerange? + timeRange: config.useCurrentDashboardDataRange ? timeRange : undefined, filters: config.useCurrentDashboardFilters ? filters : filters?.filter(f => esFilters.isFilterPinned(f)), }); + const dashboardHash = dashboardPath.split('#')[1]; + + console.log('dashboard hash', dashboardHash); // eslint-disable-line await navigateToApp('kibana', { path: `#${dashboardHash}`, }); diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts index 800896dffa9e3..bbc9a815dc79e 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { CoreStart } from 'src/core/public'; +import { SharePluginStart } from 'src/plugins/share/public'; import { EmbeddableVisTriggerContext, EmbeddableContext, @@ -17,7 +19,19 @@ export type ActionContext = EmbeddableVisTr export interface Config { dashboardId?: string; useCurrentDashboardFilters: boolean; - useCurrentDashboardDateRange: boolean; + useCurrentDashboardDataRange: boolean; } -export type CollectConfigProps = UiActionsCollectConfigProps; +export interface CollectConfigProps extends UiActionsCollectConfigProps { + deps: { + getSavedObjectsClient: () => Promise; + getNavigateToApp: () => Promise; + getGetUrlGenerator: () => Promise; + }; + context: { + place: string; + placeContext: { + embeddable: IEmbeddable; + }; + }; +} From 4217b18e304adcf8271b39b85e5347d712c40b4f Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 20 Mar 2020 11:53:12 +0100 Subject: [PATCH 13/81] fix issue with getIndexPatterns undefined MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit we can’t import those functions as static functions, instead we have to expose them on plugin contract because they are statefull --- src/plugins/data/public/index.ts | 2 -- src/plugins/data/public/mocks.ts | 2 ++ src/plugins/data/public/plugin.ts | 10 +++++++++- src/plugins/data/public/types.ts | 8 +++++++- x-pack/plugins/dashboard_enhanced/kibana.json | 2 +- x-pack/plugins/dashboard_enhanced/public/plugin.ts | 2 ++ .../drilldowns/dashboard_drilldowns_services.ts | 5 ++++- .../dashboard_to_dashboard_drilldown/drilldown.tsx | 13 +++++++------ 8 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index e4d708c3f28a8..58bd9a5ab05d7 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -450,8 +450,6 @@ export { getKbnTypeNames, } from '../common'; -export { valueClickActionGetFilters, selectRangeActionGetFilters } from './actions'; - /* * Plugin setup */ diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index c5cff1c5c68d9..395ba81bd48b7 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -56,6 +56,8 @@ const createStartContract = (): Start => { const startContract = { actions: { createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']), + selectRangeActionGetFilters: jest.fn(), + valueClickActionGetFilters: jest.fn(), }, autocomplete: autocompleteMock, getSuggestions: jest.fn(), diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 1dbaed6aac6bd..bfcb60ccd2a0d 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -54,7 +54,13 @@ import { VALUE_CLICK_TRIGGER, APPLY_FILTER_TRIGGER, } from '../../ui_actions/public'; -import { ACTION_GLOBAL_APPLY_FILTER, createFilterAction, createFiltersFromEvent } from './actions'; +import { + ACTION_GLOBAL_APPLY_FILTER, + createFilterAction, + createFiltersFromEvent, + selectRangeActionGetFilters, + valueClickActionGetFilters, +} from './actions'; import { ApplyGlobalFilterActionContext } from './actions/apply_filter_action'; import { selectRangeAction, @@ -152,6 +158,8 @@ export class DataPublicPlugin implements Plugin, plugins: SetupDependencies) { + bootstrap(core: CoreSetup, plugins: SetupDependencies) { const overlays = async () => (await core.getStartServices())[0].overlays; const drilldowns = async () => (await core.getStartServices())[1].drilldowns; const getSavedObjectsClient = async () => @@ -37,6 +37,8 @@ export class DashboardDrilldownsService { const getGetUrlGenerator = async () => (await core.getStartServices())[1].share.urlGenerators.getUrlGenerator; + const getDataPluginActions = async () => (await core.getStartServices())[1].data.actions; + const actionFlyoutCreateDrilldown = new FlyoutCreateDrilldownAction({ overlays, drilldowns }); plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, actionFlyoutCreateDrilldown); @@ -47,6 +49,7 @@ export class DashboardDrilldownsService { getSavedObjectsClient, getGetUrlGenerator, getNavigateToApp, + getDataPluginActions, }); plugins.drilldowns.registerDrilldown(dashboardToDashboardDrilldown); } diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index f1be2e7b72ca4..ddbaba95a7956 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -10,21 +10,18 @@ import { reactToUiComponent } from '../../../../../../../src/plugins/kibana_reac import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; import { DASHBOARD_APP_URL_GENERATOR } from '../../../../../../../src/plugins/dashboard/public'; import { VisualizeEmbeddableContract } from '../../../../../../../src/legacy/core_plugins/visualizations/public'; -import { FactoryContext, ActionContext, Config, CollectConfigProps } from './types'; +import { ActionContext, CollectConfigProps, Config, FactoryContext } from './types'; import { CollectConfigContainer } from './collect_config'; import { DASHBOARD_TO_DASHBOARD_DRILLDOWN } from './constants'; import { DrilldownsDrilldown as Drilldown } from '../../../../../drilldowns/public'; import { txtGoToDashboard } from './i18n'; -import { - esFilters, - valueClickActionGetFilters, - selectRangeActionGetFilters, -} from '../../../../../../../src/plugins/data/public'; +import { DataPublicPluginStart, esFilters } from '../../../../../../../src/plugins/data/public'; export interface Params { getSavedObjectsClient: () => Promise; getNavigateToApp: () => Promise; getGetUrlGenerator: () => Promise; + getDataPluginActions: () => Promise; } export class DashboardToDashboardDrilldown @@ -65,6 +62,10 @@ export class DashboardToDashboardDrilldown console.log('drilldown execute'); // eslint-disable-line const getUrlGenerator = await this.params.getGetUrlGenerator(); const navigateToApp = await this.params.getNavigateToApp(); + const { + selectRangeActionGetFilters, + valueClickActionGetFilters, + } = await this.params.getDataPluginActions(); const { timeRange, query, filters } = context.embeddable.getInput(); // @ts-ignore From 177822fb8f15029a28c667ce5eb58007231bbd3c Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 20 Mar 2020 12:39:22 +0100 Subject: [PATCH 14/81] fix filter / time passing into url --- src/plugins/data/public/index.ts | 2 + .../data/public/query/timefilter/index.ts | 2 +- .../timefilter/lib/change_time_filter.ts | 10 ++++- .../public/lib/triggers/triggers.ts | 1 + .../drilldown.tsx | 39 +++++++++++++------ 5 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 58bd9a5ab05d7..1e89b23fe510f 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -59,6 +59,7 @@ import { changeTimeFilter, mapAndFlattenFilters, extractTimeFilter, + convertRangeFilterToTimeRangeString, } from './query'; // Filter helpers namespace: @@ -96,6 +97,7 @@ export const esFilters = { onlyDisabledFiltersChanged, changeTimeFilter, + convertRangeFilterToTimeRangeString, mapAndFlattenFilters, extractTimeFilter, }; diff --git a/src/plugins/data/public/query/timefilter/index.ts b/src/plugins/data/public/query/timefilter/index.ts index a6260e782c12f..3b7de45799a00 100644 --- a/src/plugins/data/public/query/timefilter/index.ts +++ b/src/plugins/data/public/query/timefilter/index.ts @@ -23,5 +23,5 @@ export * from './types'; export { Timefilter, TimefilterContract } from './timefilter'; export { TimeHistory, TimeHistoryContract } from './time_history'; export { getTime } from './get_time'; -export { changeTimeFilter } from './lib/change_time_filter'; +export { changeTimeFilter, convertRangeFilterToTimeRangeString } from './lib/change_time_filter'; export { extractTimeFilter } from './lib/extract_time_filter'; diff --git a/src/plugins/data/public/query/timefilter/lib/change_time_filter.ts b/src/plugins/data/public/query/timefilter/lib/change_time_filter.ts index 8da83580ef5d6..cbbf2f2754312 100644 --- a/src/plugins/data/public/query/timefilter/lib/change_time_filter.ts +++ b/src/plugins/data/public/query/timefilter/lib/change_time_filter.ts @@ -20,7 +20,7 @@ import moment from 'moment'; import { keys } from 'lodash'; import { TimefilterContract } from '../../timefilter'; -import { RangeFilter } from '../../../../common'; +import { RangeFilter, TimeRange } from '../../../../common'; export function convertRangeFilterToTimeRange(filter: RangeFilter) { const key = keys(filter.range)[0]; @@ -32,6 +32,14 @@ export function convertRangeFilterToTimeRange(filter: RangeFilter) { }; } +export function convertRangeFilterToTimeRangeString(filter: RangeFilter): TimeRange { + const { from, to } = convertRangeFilterToTimeRange(filter); + return { + from: from?.toISOString(), + to: to?.toISOString(), + }; +} + export function changeTimeFilter(timeFilter: TimefilterContract, filter: RangeFilter) { timeFilter.setTime(convertRangeFilterToTimeRange(filter)); } diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index 4b1d3575f2950..d7da47a9317a0 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -30,6 +30,7 @@ export interface EmbeddableVisTriggerContext ) => { - console.log('drilldown execute'); // eslint-disable-line const getUrlGenerator = await this.params.getGetUrlGenerator(); const navigateToApp = await this.params.getNavigateToApp(); const { selectRangeActionGetFilters, valueClickActionGetFilters, } = await this.params.getDataPluginActions(); - const { timeRange, query, filters } = context.embeddable.getInput(); + const { + timeRange: currentTimeRange, + query, + filters: currentFilters, + } = context.embeddable.getInput(); + + // if useCurrentDashboardFilters enabled, then preserve all the filters (pinned and unpinned) + // otherwise preserve only pinned + const filters = + (config.useCurrentDashboardFilters + ? currentFilters + : currentFilters?.filter(f => esFilters.isFilterPinned(f))) ?? []; + + // if useCurrentDashboardDataRange is enabled, then preserve current time range + // if undefined is passed, then destination dashboard will figure out time range itself + // for brush event this time range would be overwritten + let timeRange = config.useCurrentDashboardDataRange ? currentTimeRange : undefined; - // @ts-ignore if (context.data.range) { // look up by range const { restOfFilters, timeRangeFilter } = @@ -76,29 +90,30 @@ export class DashboardToDashboardDrilldown timeFieldName: context.timeFieldName, data: context.data, })) || {}; - console.log('select range action filters', restOfFilters, timeRangeFilter); // eslint-disable-line - // selectRangeActionGetFilters + filters.push(...(restOfFilters || [])); + if (timeRangeFilter) { + timeRange = esFilters.convertRangeFilterToTimeRangeString(timeRangeFilter); + } } else { const { restOfFilters, timeRangeFilter } = await valueClickActionGetFilters({ timeFieldName: context.timeFieldName, data: context.data, }); - console.log('value click action filters', restOfFilters, timeRangeFilter); // eslint-disable-line + filters.push(...(restOfFilters || [])); + if (timeRangeFilter) { + timeRange = esFilters.convertRangeFilterToTimeRangeString(timeRangeFilter); + } } const dashboardPath = await getUrlGenerator(DASHBOARD_APP_URL_GENERATOR).createUrl({ dashboardId: config.dashboardId, query, - // todo - how to get destination dashboard timerange? - timeRange: config.useCurrentDashboardDataRange ? timeRange : undefined, - filters: config.useCurrentDashboardFilters - ? filters - : filters?.filter(f => esFilters.isFilterPinned(f)), + timeRange, + filters, }); const dashboardHash = dashboardPath.split('#')[1]; - console.log('dashboard hash', dashboardHash); // eslint-disable-line await navigateToApp('kibana', { path: `#${dashboardHash}`, }); From f7b7add5118eb99fe23aff6b7d473989d7c10846 Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Sat, 21 Mar 2020 00:31:09 -0500 Subject: [PATCH 15/81] typefix --- .../dashboard_to_dashboard_drilldown/types.ts | 10 ++++------ x-pack/plugins/drilldowns/public/index.ts | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts index 22c4c52ffbd56..39d6507e277d8 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts @@ -6,6 +6,7 @@ import { CoreStart } from 'src/core/public'; import { SharePluginStart } from 'src/plugins/share/public'; +import { DrilldownFactoryContext } from '../../../../../drilldowns/public'; import { EmbeddableVisTriggerContext, EmbeddableContext, @@ -28,10 +29,7 @@ export interface CollectConfigProps extends UiActionsCollectConfigProps getNavigateToApp: () => Promise; getGetUrlGenerator: () => Promise; }; - context: { - place: string; - placeContext: { - embeddable: IEmbeddable; - }; - }; + context: DrilldownFactoryContext<{ + embeddable: IEmbeddable; + }>; } diff --git a/x-pack/plugins/drilldowns/public/index.ts b/x-pack/plugins/drilldowns/public/index.ts index 044e29c671de4..17ccd60e17ce4 100644 --- a/x-pack/plugins/drilldowns/public/index.ts +++ b/x-pack/plugins/drilldowns/public/index.ts @@ -17,4 +17,4 @@ export function plugin() { return new DrilldownsPlugin(); } -export { DrilldownDefinition } from './types'; +export { DrilldownDefinition, DrilldownFactoryContext } from './types'; From bd7a91c50232aee9b94120f7a3c8a00fda7f474d Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Sat, 21 Mar 2020 12:55:04 +0100 Subject: [PATCH 16/81] dashboard to dashboard drilldown functional test and back button fix --- config/kibana.yml | 2 +- .../np_ready/dashboard_state_manager.ts | 4 +- .../ui/public/chrome/api/sub_url_hooks.js | 10 +- .../lib/panel/panel_header/panel_header.tsx | 5 +- .../public/context_menu/open_context_menu.tsx | 6 +- .../public/triggers/trigger_internal.ts | 4 +- .../functional/page_objects/dashboard_page.ts | 14 + .../action_wizard/action_wizard.test.tsx | 6 +- .../action_wizard/action_wizard.tsx | 8 +- .../dashboard_drilldown_config.tsx | 1 + .../flyout_create_drilldown.tsx | 1 + .../flyout_edit_drilldown.tsx | 1 + .../drilldown_hello_bar.tsx | 2 +- .../flyout_drilldown_wizard.tsx | 1 + .../form_drilldown_wizard.test.tsx | 8 +- .../form_drilldown_wizard.tsx | 2 +- .../list_manage_drilldowns.tsx | 10 +- .../drilldowns/dashboard_drilldowns.ts | 166 ++++++++++++ .../apps/dashboard/drilldowns/index.ts | 13 + .../test/functional/apps/dashboard/index.ts | 1 + .../dashboard/drilldowns/data.json.gz | Bin 0 -> 2640 bytes .../dashboard/drilldowns/mappings.json | 244 ++++++++++++++++++ .../services/dashboard/drilldowns_manage.ts | 97 +++++++ .../functional/services/dashboard/index.ts | 8 + .../dashboard/panel_drilldown_actions.ts | 68 +++++ x-pack/test/functional/services/index.ts | 6 + 26 files changed, 659 insertions(+), 29 deletions(-) create mode 100644 x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts create mode 100644 x-pack/test/functional/apps/dashboard/drilldowns/index.ts create mode 100644 x-pack/test/functional/es_archives/dashboard/drilldowns/data.json.gz create mode 100644 x-pack/test/functional/es_archives/dashboard/drilldowns/mappings.json create mode 100644 x-pack/test/functional/services/dashboard/drilldowns_manage.ts create mode 100644 x-pack/test/functional/services/dashboard/index.ts create mode 100644 x-pack/test/functional/services/dashboard/panel_drilldown_actions.ts diff --git a/config/kibana.yml b/config/kibana.yml index 7b11a32bbdb42..13728a7bf212a 100644 --- a/config/kibana.yml +++ b/config/kibana.yml @@ -112,4 +112,4 @@ #i18n.locale: "en" # Enables "Drilldowns" functionality on dashboard. Set to false by default. -# xpack.dashboardEnhanced.drilldowns.enabled: false +xpack.dashboardEnhanced.drilldowns.enabled: true diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts index 6b426d8d5344e..d26948e06c8cb 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts @@ -236,8 +236,8 @@ export class DashboardStateManager { if ( !_.isEqual( - convertedPanelStateMap[panelState.explicitInput.id], - savedDashboardPanelMap[panelState.explicitInput.id] + _.omit(convertedPanelStateMap[panelState.explicitInput.id], 'version'), + _.omit(savedDashboardPanelMap[panelState.explicitInput.id], 'version') ) ) { // A panel was changed diff --git a/src/legacy/ui/public/chrome/api/sub_url_hooks.js b/src/legacy/ui/public/chrome/api/sub_url_hooks.js index 27d147b1ffc72..ca4a4e6d120fa 100644 --- a/src/legacy/ui/public/chrome/api/sub_url_hooks.js +++ b/src/legacy/ui/public/chrome/api/sub_url_hooks.js @@ -17,8 +17,6 @@ * under the License. */ -import url from 'url'; - import { unhashUrl } from '../../../../../plugins/kibana_utils/public'; import { toastNotifications } from '../../notify/toasts'; import { npSetup } from '../../new_platform'; @@ -47,14 +45,14 @@ export function registerSubUrlHooks(angularModule, internals) { } $rootScope.$on('$locationChangeStart', (e, newUrl) => { + const getHash = url => url.split('#')[1] || ''; + // This handler fixes issue #31238 where browser back navigation // fails due to angular 1.6 parsing url encoded params wrong. - const parsedAbsUrl = url.parse($location.absUrl()); - const absUrlHash = parsedAbsUrl.hash ? parsedAbsUrl.hash.slice(1) : ''; + const absUrlHash = getHash($location.absUrl()); const decodedAbsUrlHash = decodeURIComponent(absUrlHash); - const parsedNewUrl = url.parse(newUrl); - const newHash = parsedNewUrl.hash ? parsedNewUrl.hash.slice(1) : ''; + const newHash = getHash(newUrl); const decodedHash = decodeURIComponent(newHash); if (absUrlHash !== newHash && decodedHash === decodedAbsUrlHash) { diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx index ed1ae739502a7..416f78824252d 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx @@ -151,7 +151,10 @@ export function PanelHeader({ {renderBadges(badges, embeddable)} {!isViewMode && !!drilldownCount && ( - + {drilldownCount} )} diff --git a/src/plugins/ui_actions/public/context_menu/open_context_menu.tsx b/src/plugins/ui_actions/public/context_menu/open_context_menu.tsx index 4d794618e85ab..c723388c021e9 100644 --- a/src/plugins/ui_actions/public/context_menu/open_context_menu.tsx +++ b/src/plugins/ui_actions/public/context_menu/open_context_menu.tsx @@ -149,7 +149,11 @@ export function openContextMenu( anchorPosition="downRight" withTitle > - + , container ); diff --git a/src/plugins/ui_actions/public/triggers/trigger_internal.ts b/src/plugins/ui_actions/public/triggers/trigger_internal.ts index 9885ed3abe93b..c65e9ad29a5a2 100644 --- a/src/plugins/ui_actions/public/triggers/trigger_internal.ts +++ b/src/plugins/ui_actions/public/triggers/trigger_internal.ts @@ -75,6 +75,8 @@ export class TriggerInternal { title: this.trigger.title, closeMenu: () => session.close(), }); - const session = openContextMenu([panel]); + const session = openContextMenu([panel], { + 'data-test-subj': 'multipleActionsContextMenu', + }); } } diff --git a/test/functional/page_objects/dashboard_page.ts b/test/functional/page_objects/dashboard_page.ts index 0f01097cf50dc..4bdd4cbcd1433 100644 --- a/test/functional/page_objects/dashboard_page.ts +++ b/test/functional/page_objects/dashboard_page.ts @@ -510,6 +510,20 @@ export function DashboardPageProvider({ getService, getPageObjects }: FtrProvide return checkList.filter(viz => viz.isPresent === false).map(viz => viz.name); } + + public async getPanelDrilldownCount(panelIndex = 0): Promise { + log.debug('getPanelDrilldownCount'); + const panel = (await this.getDashboardPanels())[panelIndex]; + try { + const count = await panel.findByCssSelector( + '[data-test-subj="embeddablePanelDrilldownCount"]' + ); + return Number.parseInt(await count.getVisibleText(), 10); + } catch (e) { + // if not found then this is 0 (we don't show badge with 0) + return 0; + } + } } return new DashboardPage(); diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx index cc56714fcb2f8..f43d832b1edae 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx @@ -18,7 +18,7 @@ test('Pick and configure action', () => { const screen = render(); // check that all factories are displayed to pick - expect(screen.getAllByTestId(TEST_SUBJ_ACTION_FACTORY_ITEM)).toHaveLength(2); + expect(screen.getAllByTestId(new RegExp(TEST_SUBJ_ACTION_FACTORY_ITEM))).toHaveLength(2); // select URL one fireEvent.click(screen.getByText(/Go to URL/i)); @@ -43,8 +43,8 @@ test('If only one actions factory is available then actionFactory selection is e const screen = render(); // check that no factories are displayed to pick from - expect(screen.queryByTestId(TEST_SUBJ_ACTION_FACTORY_ITEM)).not.toBeInTheDocument(); - expect(screen.queryByTestId(TEST_SUBJ_SELECTED_ACTION_FACTORY)).toBeInTheDocument(); + expect(screen.queryByTestId(new RegExp(TEST_SUBJ_ACTION_FACTORY_ITEM))).not.toBeInTheDocument(); + expect(screen.queryByTestId(new RegExp(TEST_SUBJ_SELECTED_ACTION_FACTORY))).toBeInTheDocument(); // Input url const URL = 'https://elastic.co'; diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx index 846f6d41eb30d..b4aa3c1ba4608 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx @@ -105,7 +105,7 @@ interface SelectedActionFactoryProps { onDeselect: () => void; } -export const TEST_SUBJ_SELECTED_ACTION_FACTORY = 'selected-action-factory'; +export const TEST_SUBJ_SELECTED_ACTION_FACTORY = 'selectedActionFactory'; const SelectedActionFactory: React.FC = ({ actionFactory, @@ -118,7 +118,7 @@ const SelectedActionFactory: React.FC = ({ return (
@@ -159,7 +159,7 @@ interface ActionFactorySelectorProps { onActionFactorySelected: (actionFactory: ActionFactory) => void; } -export const TEST_SUBJ_ACTION_FACTORY_ITEM = 'action-factory-item'; +export const TEST_SUBJ_ACTION_FACTORY_ITEM = 'actionFactoryItem'; const ActionFactorySelector: React.FC = ({ actionFactories, @@ -181,7 +181,7 @@ const ActionFactorySelector: React.FC = ({ onActionFactorySelected(actionFactory)} > {actionFactory.getIconType(context) && ( diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx index da5a3cfa34697..386664da4f625 100644 --- a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx @@ -51,6 +51,7 @@ export const DashboardDrilldownConfig: React.FC = isLoading={isLoading} singleSelection={{ asPlainText: true }} fullWidth + data-test-subj={'dashboardDrilldownSelectDashboard'} /> {!!onCurrentFiltersToggle && ( diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx index 792238adff313..f0926af2a348d 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx @@ -68,6 +68,7 @@ export class FlyoutCreateDrilldownAction implements ActionByType void; } -export const WELCOME_MESSAGE_TEST_SUBJ = 'drilldowns-welcome-message-test-subj'; +export const WELCOME_MESSAGE_TEST_SUBJ = 'drilldownsWelcomeMessage'; export const DrilldownHelloBar: React.FC = ({ docsLink, diff --git a/x-pack/plugins/drilldowns/public/components/flyout_drilldown_wizard/flyout_drilldown_wizard.tsx b/x-pack/plugins/drilldowns/public/components/flyout_drilldown_wizard/flyout_drilldown_wizard.tsx index faa965a98a4bb..8541aae06ff0c 100644 --- a/x-pack/plugins/drilldowns/public/components/flyout_drilldown_wizard/flyout_drilldown_wizard.tsx +++ b/x-pack/plugins/drilldowns/public/components/flyout_drilldown_wizard/flyout_drilldown_wizard.tsx @@ -79,6 +79,7 @@ export function FlyoutDrilldownWizard {mode === 'edit' ? txtEditDrilldownButtonLabel : txtCreateDrilldownButtonLabel} diff --git a/x-pack/plugins/drilldowns/public/components/form_drilldown_wizard/form_drilldown_wizard.test.tsx b/x-pack/plugins/drilldowns/public/components/form_drilldown_wizard/form_drilldown_wizard.test.tsx index 4560773cc8a6d..d9c53ae6f737a 100644 --- a/x-pack/plugins/drilldowns/public/components/form_drilldown_wizard/form_drilldown_wizard.test.tsx +++ b/x-pack/plugins/drilldowns/public/components/form_drilldown_wizard/form_drilldown_wizard.test.tsx @@ -24,9 +24,7 @@ describe('', () => { render(, div); - const input = div.querySelector( - '[data-test-subj="dynamicActionNameInput"]' - ) as HTMLInputElement; + const input = div.querySelector('[data-test-subj="drilldownNameInput"]') as HTMLInputElement; expect(input?.value).toBe(''); }); @@ -36,9 +34,7 @@ describe('', () => { render(, div); - const input = div.querySelector( - '[data-test-subj="dynamicActionNameInput"]' - ) as HTMLInputElement; + const input = div.querySelector('[data-test-subj="drilldownNameInput"]') as HTMLInputElement; expect(input?.value).toBe('foo'); diff --git a/x-pack/plugins/drilldowns/public/components/form_drilldown_wizard/form_drilldown_wizard.tsx b/x-pack/plugins/drilldowns/public/components/form_drilldown_wizard/form_drilldown_wizard.tsx index 4c9a7a2e514c6..9778e1dc6e95a 100644 --- a/x-pack/plugins/drilldowns/public/components/form_drilldown_wizard/form_drilldown_wizard.tsx +++ b/x-pack/plugins/drilldowns/public/components/form_drilldown_wizard/form_drilldown_wizard.tsx @@ -47,7 +47,7 @@ export const FormDrilldownWizard: React.FC = ({ value={name} disabled={onNameChange === noopFn} onChange={event => onNameChange(event.target.value)} - data-test-subj="dynamicActionNameInput" + data-test-subj="drilldownNameInput" /> ); diff --git a/x-pack/plugins/drilldowns/public/components/list_manage_drilldowns/list_manage_drilldowns.tsx b/x-pack/plugins/drilldowns/public/components/list_manage_drilldowns/list_manage_drilldowns.tsx index 5a15781a1faf2..ab51c0a829ed3 100644 --- a/x-pack/plugins/drilldowns/public/components/list_manage_drilldowns/list_manage_drilldowns.tsx +++ b/x-pack/plugins/drilldowns/public/components/list_manage_drilldowns/list_manage_drilldowns.tsx @@ -40,7 +40,7 @@ export interface ListManageDrilldownsProps { const noop = () => {}; -export const TEST_SUBJ_DRILLDOWN_ITEM = 'list-manage-drilldowns-item'; +export const TEST_SUBJ_DRILLDOWN_ITEM = 'listManageDrilldownsItem'; export function ListManageDrilldowns({ drilldowns, @@ -56,6 +56,7 @@ export function ListManageDrilldowns({ name: 'Name', truncateText: true, width: '50%', + 'data-test-subj': 'drilldownListItemName', }, { name: 'Action', @@ -107,7 +108,12 @@ export function ListManageDrilldowns({ {txtCreateDrilldown} ) : ( - onDelete(selectedDrilldowns)}> + onDelete(selectedDrilldowns)} + data-test-subj={'listManageDeleteDrilldowns'} + > {txtDeleteDrilldowns(selectedDrilldowns.length)} )} diff --git a/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts b/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts new file mode 100644 index 0000000000000..1121921c7d315 --- /dev/null +++ b/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts @@ -0,0 +1,166 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const DASHBOARD_WITH_PIE_CHART_NAME = 'Dashboard with Pie Chart'; +const DASHBOARD_WITH_AREA_CHART_NAME = 'Dashboard With Area Chart'; + +const DRILLDOWN_TO_PIE_CHART_NAME = 'Go to pie chart dashboard'; +const DRILLDOWN_TO_AREA_CHART_NAME = 'Go to area chart dashboard'; + +export default function({ getService, getPageObjects }: FtrProviderContext) { + const dashboardPanelActions = getService('dashboardPanelActions'); + const dashboardDrilldownPanelActions = getService('dashboardDrilldownPanelActions'); + const dashboardDrilldownsManage = getService('dashboardDrilldownsManage'); + const PageObjects = getPageObjects(['dashboard', 'common', 'header', 'timePicker']); + const kibanaServer = getService('kibanaServer'); + const esArchiver = getService('esArchiver'); + const pieChart = getService('pieChart'); + const log = getService('log'); + const browser = getService('browser'); + const retry = getService('retry'); + const testSubjects = getService('testSubjects'); + const filterBar = getService('filterBar'); + + describe('Dashboard Drilldowns', function() { + before(async () => { + log.debug('Dashboard Drilldowns:initTests'); + await esArchiver.loadIfNeeded('logstash_functional'); + await esArchiver.load('dashboard/drilldowns'); + await kibanaServer.uiSettings.replace({ defaultIndex: 'logstash-*' }); + await PageObjects.common.navigateToApp('dashboard'); + await PageObjects.dashboard.preserveCrossAppState(); + }); + + after(async () => { + await esArchiver.unload('dashboard/drilldowns'); + }); + + it('should create dashboard to dashboard drilldown, use it, and then delete it', async () => { + await PageObjects.dashboard.gotoDashboardEditMode(DASHBOARD_WITH_PIE_CHART_NAME); + + // create drilldown + await dashboardPanelActions.openContextMenu(); + await dashboardDrilldownPanelActions.expectExistsCreateDrilldownAction(); + await dashboardDrilldownPanelActions.clickCreateDrilldown(); + await dashboardDrilldownsManage.expectsCreateDrilldownFlyoutOpen(); + await dashboardDrilldownsManage.fillInDashboardToDashboardDrilldownWizard({ + drilldownName: DRILLDOWN_TO_AREA_CHART_NAME, + destinationDashboardTitle: DASHBOARD_WITH_AREA_CHART_NAME, + }); + await dashboardDrilldownsManage.saveChanges(); + await dashboardDrilldownsManage.expectsCreateDrilldownFlyoutClose(); + + // check that drilldown notification badge is shown + expect(await PageObjects.dashboard.getPanelDrilldownCount()).to.be(1); + + // save dashboard, navigate to view mode + await PageObjects.dashboard.saveDashboard(DASHBOARD_WITH_PIE_CHART_NAME, { + saveAsNew: false, + waitDialogIsClosed: true, + }); + + // trigger drilldown action by clicking on a pie and picking drilldown action by it's name + await pieChart.filterOnPieSlice('40,000'); + await dashboardDrilldownPanelActions.expectMultipleActionsMenuOpened(); + await navigateWithinDashboard(async () => { + await dashboardDrilldownPanelActions.clickActionByText(DRILLDOWN_TO_AREA_CHART_NAME); + }); + + // check that we drilled-down with filter from pie chart + expect(await filterBar.getFilterCount()).to.be(1); + + const originalTimeRangeDurationHours = await PageObjects.timePicker.getTimeDurationInHours(); + + // brush area chart and drilldown back to pie chat dashboard + await brushAreaChart(); + await dashboardDrilldownPanelActions.expectMultipleActionsMenuOpened(); + await navigateWithinDashboard(async () => { + await dashboardDrilldownPanelActions.clickActionByText(DRILLDOWN_TO_PIE_CHART_NAME); + }); + + // because filters are preserved during navigation, we expect that only one slice is displayed (filter is still applied) + expect(await filterBar.getFilterCount()).to.be(1); + await pieChart.expectPieSliceCount(1); + + // check that new time range duration was applied + const newTimeRangeDurationHours = await PageObjects.timePicker.getTimeDurationInHours(); + expect(newTimeRangeDurationHours).to.be.lessThan(originalTimeRangeDurationHours); + + // delete drilldown + await PageObjects.dashboard.switchToEditMode(); + await dashboardPanelActions.openContextMenu(); + await dashboardDrilldownPanelActions.expectExistsManageDrilldownsAction(); + await dashboardDrilldownPanelActions.clickManageDrilldowns(); + await dashboardDrilldownsManage.expectsManageDrilldownsFlyoutOpen(); + + await dashboardDrilldownsManage.deleteDrilldownsByTitles([DRILLDOWN_TO_AREA_CHART_NAME]); + await dashboardDrilldownsManage.closeFlyout(); + + // check that drilldown notification badge is shown + expect(await PageObjects.dashboard.getPanelDrilldownCount()).to.be(0); + }); + + it('browser back/forward navigation works after drilldown navigation', async () => { + await PageObjects.dashboard.loadSavedDashboard(DASHBOARD_WITH_AREA_CHART_NAME); + const originalTimeRangeDurationHours = await PageObjects.timePicker.getTimeDurationInHours(); + await brushAreaChart(); + await dashboardDrilldownPanelActions.expectMultipleActionsMenuOpened(); + await navigateWithinDashboard(async () => { + await dashboardDrilldownPanelActions.clickActionByText(DRILLDOWN_TO_PIE_CHART_NAME); + }); + // check that new time range duration was applied + const newTimeRangeDurationHours = await PageObjects.timePicker.getTimeDurationInHours(); + expect(newTimeRangeDurationHours).to.be.lessThan(originalTimeRangeDurationHours); + + await navigateWithinDashboard(async () => { + await browser.goBack(); + }); + + expect(await PageObjects.timePicker.getTimeDurationInHours()).to.be( + originalTimeRangeDurationHours + ); + }); + }); + + // utils which shouldn't be a part of test flow, but also too specific to be moved to pageobject or service + async function brushAreaChart() { + const areaChart = await testSubjects.find('visualizationLoader'); + expect(await areaChart.getAttribute('data-title')).to.be('Visualization漢字 AreaChart'); + await browser.dragAndDrop( + { + location: areaChart, + offset: { + x: 150, + y: 100, + }, + }, + { + location: areaChart, + offset: { + x: 200, + y: 100, + }, + } + ); + } + + async function navigateWithinDashboard(navigationTrigger: () => Promise) { + // before executing action which would trigger navigation: remember current dashboard id in url + const oldDashboardId = await PageObjects.dashboard.getDashboardIdFromCurrentUrl(); + // execute navigation action + await navigationTrigger(); + // wait until dashboard navigates to a new dashboard with area chart + await retry.waitFor('navigate to different dashboard', async () => { + const newDashboardId = await PageObjects.dashboard.getDashboardIdFromCurrentUrl(); + return typeof newDashboardId === 'string' && oldDashboardId !== newDashboardId; + }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.waitForRenderComplete(); + } +} diff --git a/x-pack/test/functional/apps/dashboard/drilldowns/index.ts b/x-pack/test/functional/apps/dashboard/drilldowns/index.ts new file mode 100644 index 0000000000000..ab273018dc3f7 --- /dev/null +++ b/x-pack/test/functional/apps/dashboard/drilldowns/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function({ loadTestFile }: FtrProviderContext) { + describe('drilldowns', function() { + this.tags(['skipFirefox']); + loadTestFile(require.resolve('./dashboard_drilldowns')); + }); +} diff --git a/x-pack/test/functional/apps/dashboard/index.ts b/x-pack/test/functional/apps/dashboard/index.ts index 5f4d3fcbd8c04..b734dea1a80a5 100644 --- a/x-pack/test/functional/apps/dashboard/index.ts +++ b/x-pack/test/functional/apps/dashboard/index.ts @@ -10,5 +10,6 @@ export default function({ loadTestFile }: FtrProviderContext) { this.tags('ciGroup7'); loadTestFile(require.resolve('./feature_controls')); + loadTestFile(require.resolve('./drilldowns')); }); } diff --git a/x-pack/test/functional/es_archives/dashboard/drilldowns/data.json.gz b/x-pack/test/functional/es_archives/dashboard/drilldowns/data.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..febf312799eee0de78a6de2226c17d4fe6183c68 GIT binary patch literal 2640 zcmV-W3a|AaiwFoL|8-sf17u-zVJ>QOZ*BnXT-|cpxD~$7Q?R=1L^3JKlBKISwl{U_ z*d9rn%*OI?AQBYOkOY?iEju1PM|<7-zCfo>)0y@;dH{kHDanqr>jM^`AYmPU%k42y0|xlr6?d@kYI24p?vkPzy9Mt|NPs(|NfWeG2&=~W&!?o zedJtJ#wi3{BR{6LbspqB+2~_*gWZeSpRvQ=V~#4_2&OPf9DgiX`{VfHT=aH7&19H1 zhSNqs=ZqufH-A5Eyq-3GPH}Pv4fpD&&3Hnhd5I#Q%5H|?gS#)-UXZ|bP~t)pPg1;G zLYqedjuW6*pd{Z1cfZqL5!12G#7VRCNwdhE-q2R2?|DZA@1=|z_4loix7t$ z^1~oF!#6l6+J%PDd@io9ggIO}qE%(Up=rb=i8($FktBu~4C1V@1sY%V(ysOb5y$Bq z?p*I_mO7s?-w@CvILJDh-EquhJBh%S5JEt1o2HN(-*OB-uc0M?@o)r| z$Y@3Iey1pHe!!r82L*3Ya^!<0G=}K|ti0@KH6D|Chv8cF^Rh=X;0phAcuSZPSt!GG zCzJ-9#1+~Zo`YMjNDSo4x(`SM#*ux8)XivM3J4)LERrtgXzIP9o6-6t{#6MVl>4kw?fSsbHnO zuPASWRH)a=ug_@`3ZbwlpH{;xashB8${M!>GHH^l*(ZaoR;OjkTLN^K z#qP9`5j?>@mjn_*owXMWuM?(8Pz2?EBC)4XCI3^Va)Cf!DEJC z{4T)RK-0!@mvB1A)Q7;b=LvDY9ZccrmP2Xc5-^9V#sr97CfFfLp-LHXiPZj1=qLfB z8H3(&5)D_N@$HaU>8Xl&QhFwO5w;O8gHja<_Hd$HtI%$aORo!a4P{v_L9^oKa==P7 zX0TPhN8}wTcU~z-yA~XPKPqEA^Z1HV8D707R5cI?Ksln3C=^Eupq80hL#m z?3fa@EV1)?1vH}>XymMt;;KGQlY6vWaMqrXHdbe9!4->X#B{UqCd7>CFBOsA>jRHgO^-ij-lGbKwL%}ZwbeX}UOYlCXKQC>`LYhGTdU$g=r zHCW(=fYmZP!mTb(lF^`*2>z+SO{y zkFM3%?5$AuXDag3G>;_PzD=voC!e*0zS_ca{w^D*vw$#P_Y$$a{;9`~XNB$O`9Am8 zaKIdz;9rk4-^Rjqqq6ZN#6O5n&Ck_#;}!lkw(UhUDs3?cZe+(j~#V_c^Yy z@RGM7Z4-5e`;cOi#mF;lXC&;HMk!x~r2bvVU*7^#TE;8wCG47Y+K8;q3OFN?_TXIS z;RQ#hIw)YP#5)X9u{HQPqg0$6kZmd~JVU>seFrNh!FiQHc}5<&uT@cJd~YX(h)Yy*DcfIJ31n^UQbd=dSL{gyOwr5dI( z24$-xy}c_*kMB$7=7!BK9uj38&&1P@l4w{yQQ4?8Rw~0Gl ztJfZ&_5k<39gT|qABCE7Ncn_|?e^v~fzCR%NZm`#2Pm4S+38u+#^Rm zGU5Gm5|x6~CoaB35e_CI{#WxpWnp8{UUYP|b~Hu5)mKMTi1QlM85(epsNvdOF~n3I zwjp3uynx=R|4CLa_Bwrc-!q%2k9*B-ue0Agu&~?g47~QtLdfZP-Arc5$7zAjPkT^! zYB5 z(V39>JahA_Y2(A;*^ejo(b?(IpX|x#^xeCYk-Tesa&~ewu}6pJ?@m??5|PwbLc{Vj z-#cn>YQzK^V&f+_3g1+-d@BKp7R7hh!u|fhdNej0+ztSkMe`3?+yf@Az>1hqo7pqhot=VXrQZN2h0J#}^;Z#i=3Jh22KjJ1=&v34#qy zQ=MK+u$N%w=Kv&PM>rpF1V1HvD||555@v{hNN6bhvu#@YO%oI_m{|Q`r#rOFR(sI@ zv_6puB^?M;bX{$n&~jJp&crl_=3r>`Th@WO)|JZD$GJI-kA(X&O&c3|x|E7HW<;~o zIwA)PWVtGyso+P3hfgWS)C2j!kV@s%#_d(u3Qg3n>y1g<6<`)kX)JP-Ya^a%u5CiV zNF!Lo{lRd*)9Rbnr(Zt7yUGDi@$=tufE?<7B?lZh`>xlUwVS5n44U18gMJgW!MHs% yK-Qq`b-HGMYYuqYgAe3@|3_?E2yD89?6M1JT3>llch(z|Ui}y8AnvUGR{#K}ArO`T literal 0 HcmV?d00001 diff --git a/x-pack/test/functional/es_archives/dashboard/drilldowns/mappings.json b/x-pack/test/functional/es_archives/dashboard/drilldowns/mappings.json new file mode 100644 index 0000000000000..210fade40c648 --- /dev/null +++ b/x-pack/test/functional/es_archives/dashboard/drilldowns/mappings.json @@ -0,0 +1,244 @@ +{ + "type": "index", + "value": { + "index": ".kibana", + "mappings": { + "properties": { + "config": { + "dynamic": "true", + "properties": { + "buildNum": { + "type": "keyword" + } + } + }, + "dashboard": { + "dynamic": "strict", + "properties": { + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "optionsJSON": { + "type": "text" + }, + "panelsJSON": { + "type": "text" + }, + "refreshInterval": { + "properties": { + "display": { + "type": "keyword" + }, + "pause": { + "type": "boolean" + }, + "section": { + "type": "integer" + }, + "value": { + "type": "integer" + } + } + }, + "timeFrom": { + "type": "keyword" + }, + "timeRestore": { + "type": "boolean" + }, + "timeTo": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "index-pattern": { + "dynamic": "strict", + "properties": { + "fieldFormatMap": { + "type": "text" + }, + "fields": { + "type": "text" + }, + "intervalName": { + "type": "keyword" + }, + "notExpandable": { + "type": "boolean" + }, + "sourceFilters": { + "type": "text" + }, + "timeFieldName": { + "type": "keyword" + }, + "title": { + "type": "text" + } + } + }, + "search": { + "dynamic": "strict", + "properties": { + "columns": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "sort": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "server": { + "dynamic": "strict", + "properties": { + "uuid": { + "type": "keyword" + } + } + }, + "timelion-sheet": { + "dynamic": "strict", + "properties": { + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "timelion_chart_height": { + "type": "integer" + }, + "timelion_columns": { + "type": "integer" + }, + "timelion_interval": { + "type": "keyword" + }, + "timelion_other_interval": { + "type": "keyword" + }, + "timelion_rows": { + "type": "integer" + }, + "timelion_sheet": { + "type": "text" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "type": { + "type": "keyword" + }, + "url": { + "dynamic": "strict", + "properties": { + "accessCount": { + "type": "long" + }, + "accessDate": { + "type": "date" + }, + "createDate": { + "type": "date" + }, + "url": { + "fields": { + "keyword": { + "ignore_above": 2048, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "visualization": { + "dynamic": "strict", + "properties": { + "description": { + "type": "text" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "savedSearchId": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "uiStateJSON": { + "type": "text" + }, + "version": { + "type": "integer" + }, + "visState": { + "type": "text" + } + } + } + } + }, + "settings": { + "index": { + "number_of_replicas": "1", + "number_of_shards": "1" + } + } + } +} diff --git a/x-pack/test/functional/services/dashboard/drilldowns_manage.ts b/x-pack/test/functional/services/dashboard/drilldowns_manage.ts new file mode 100644 index 0000000000000..4d1b856b7c38a --- /dev/null +++ b/x-pack/test/functional/services/dashboard/drilldowns_manage.ts @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +const CREATE_DRILLDOWN_FLYOUT_DATA_TEST_SUBJ = 'dashboardCreateDrilldownFlyout'; +const MANAGE_DRILLDOWNS_FLYOUT_DATA_TEST_SUBJ = 'dashboardEditDrilldownFlyout'; +const DASHBOARD_TO_DASHBOARD_ACTION_LIST_ITEM = + 'actionFactoryItem-DASHBOARD_TO_DASHBOARD_DRILLDOWN'; +const DASHBOARD_TO_DASHBOARD_ACTION_WIZARD = + 'selectedActionFactory-DASHBOARD_TO_DASHBOARD_DRILLDOWN'; +const DESTINATION_DASHBOARD_SELECT = 'dashboardDrilldownSelectDashboard'; +const DRILLDOWN_WIZARD_SUBMIT = 'drilldownWizardSubmit'; + +export function DashboardDrilldownsManageProvider({ getService }: FtrProviderContext) { + const log = getService('log'); + const testSubjects = getService('testSubjects'); + const flyout = getService('flyout'); + const comboBox = getService('comboBox'); + + return new (class DashboardDrilldownsManage { + async expectsCreateDrilldownFlyoutOpen() { + log.debug('expectsCreateDrilldownFlyoutOpen'); + await testSubjects.existOrFail(CREATE_DRILLDOWN_FLYOUT_DATA_TEST_SUBJ); + } + + async expectsManageDrilldownsFlyoutOpen() { + log.debug('expectsManageDrilldownsFlyoutOpen'); + await testSubjects.existOrFail(MANAGE_DRILLDOWNS_FLYOUT_DATA_TEST_SUBJ); + } + + async expectsCreateDrilldownFlyoutClose() { + log.debug('expectsCreateDrilldownFlyoutClose'); + await testSubjects.missingOrFail(CREATE_DRILLDOWN_FLYOUT_DATA_TEST_SUBJ); + } + + async expectsManageDrilldownsFlyoutClose() { + log.debug('expectsManageDrilldownsFlyoutClose'); + await testSubjects.missingOrFail(MANAGE_DRILLDOWNS_FLYOUT_DATA_TEST_SUBJ); + } + + async fillInDashboardToDashboardDrilldownWizard({ + drilldownName, + destinationDashboardTitle, + }: { + drilldownName: string; + destinationDashboardTitle: string; + }) { + await this.fillInDrilldownName(drilldownName); + await this.selectDashboardToDashboardActionIfNeeded(); + await this.selectDestinationDashboard(destinationDashboardTitle); + } + + async fillInDrilldownName(name: string) { + await testSubjects.setValue('drilldownNameInput', name); + } + + async selectDashboardToDashboardActionIfNeeded() { + if (await testSubjects.exists(DASHBOARD_TO_DASHBOARD_ACTION_LIST_ITEM)) { + await testSubjects.click(DASHBOARD_TO_DASHBOARD_ACTION_LIST_ITEM); + } + await testSubjects.existOrFail(DASHBOARD_TO_DASHBOARD_ACTION_WIZARD); + } + + async selectDestinationDashboard(title: string) { + await comboBox.set(DESTINATION_DASHBOARD_SELECT, title); + } + + async saveChanges() { + await testSubjects.click(DRILLDOWN_WIZARD_SUBMIT); + } + + async deleteDrilldownsByTitles(titles: string[]) { + const drilldowns = await testSubjects.findAll('listManageDrilldownsItem'); + + for (const drilldown of drilldowns) { + const nameColumn = await drilldown.findByCssSelector( + '[data-test-subj="drilldownListItemName"]' + ); + const name = await nameColumn.getVisibleText(); + if (titles.includes(name)) { + const checkbox = await drilldown.findByTagName('input'); + await checkbox.click(); + } + } + const deleteBtn = await testSubjects.find('listManageDeleteDrilldowns'); + await deleteBtn.click(); + } + + async closeFlyout() { + await flyout.ensureAllClosed(); + } + })(); +} diff --git a/x-pack/test/functional/services/dashboard/index.ts b/x-pack/test/functional/services/dashboard/index.ts new file mode 100644 index 0000000000000..dee525fa0a388 --- /dev/null +++ b/x-pack/test/functional/services/dashboard/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { DashboardDrilldownPanelActionsProvider } from './panel_drilldown_actions'; +export { DashboardDrilldownsManageProvider } from './drilldowns_manage'; diff --git a/x-pack/test/functional/services/dashboard/panel_drilldown_actions.ts b/x-pack/test/functional/services/dashboard/panel_drilldown_actions.ts new file mode 100644 index 0000000000000..52f7540f9f2f7 --- /dev/null +++ b/x-pack/test/functional/services/dashboard/panel_drilldown_actions.ts @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +const CREATE_DRILLDOWN_DATA_TEST_SUBJ = 'embeddablePanelAction-OPEN_FLYOUT_ADD_DRILLDOWN'; +const MANAGE_DRILLDOWNS_DATA_TEST_SUBJ = 'embeddablePanelAction-OPEN_FLYOUT_EDIT_DRILLDOWN'; + +export function DashboardDrilldownPanelActionsProvider({ getService }: FtrProviderContext) { + const log = getService('log'); + const testSubjects = getService('testSubjects'); + + return new (class DashboardDrilldownPanelActions { + async expectExistsCreateDrilldownAction() { + log.debug('expectExistsCreateDrilldownAction'); + await testSubjects.existOrFail(CREATE_DRILLDOWN_DATA_TEST_SUBJ); + } + + async expectMissingCreateDrilldwonAction() { + log.debug('expectMissingCreateDrilldownAction'); + await testSubjects.existOrFail(MANAGE_DRILLDOWNS_DATA_TEST_SUBJ); + } + + async clickCreateDrilldown() { + log.debug('clickCreateDrilldown'); + await this.expectExistsCreateDrilldownAction(); + await testSubjects.clickWhenNotDisabled(CREATE_DRILLDOWN_DATA_TEST_SUBJ); + } + + async expectExistsManageDrilldownsAction() { + log.debug('expectExistsCreateDrilldownAction'); + await testSubjects.existOrFail(CREATE_DRILLDOWN_DATA_TEST_SUBJ); + } + + async expectMissingManageDrilldownsAction() { + log.debug('expectExistsRemovePanelAction'); + await testSubjects.existOrFail(MANAGE_DRILLDOWNS_DATA_TEST_SUBJ); + } + + async clickManageDrilldowns() { + log.debug('clickManageDrilldowns'); + await this.expectExistsManageDrilldownsAction(); + await testSubjects.clickWhenNotDisabled(MANAGE_DRILLDOWNS_DATA_TEST_SUBJ); + } + + async expectMultipleActionsMenuOpened() { + log.debug('exceptMultipleActionsMenuOpened'); + await testSubjects.existOrFail('multipleActionsContextMenu'); + } + + async clickActionByText(text: string) { + log.debug(`clickActionByText: "${text}"`); + const menu = await testSubjects.find('multipleActionsContextMenu'); + const items = await menu.findAllByCssSelector('[data-test-subj*="embeddablePanelAction-"]'); + for (const item of items) { + const currentText = await item.getVisibleText(); + if (currentText === text) { + return await item.click(); + } + } + + throw new Error(`No action matching text "${text}"`); + } + })(); +} diff --git a/x-pack/test/functional/services/index.ts b/x-pack/test/functional/services/index.ts index aec91ba9e9034..f1d84f3054aa0 100644 --- a/x-pack/test/functional/services/index.ts +++ b/x-pack/test/functional/services/index.ts @@ -49,6 +49,10 @@ import { InfraSourceConfigurationFormProvider } from './infra_source_configurati import { LogsUiProvider } from './logs_ui'; import { MachineLearningProvider } from './ml'; import { TransformProvider } from './transform'; +import { + DashboardDrilldownPanelActionsProvider, + DashboardDrilldownsManageProvider, +} from './dashboard'; // define the name and providers for services that should be // available to your tests. If you don't specify anything here @@ -91,4 +95,6 @@ export const services = { logsUi: LogsUiProvider, ml: MachineLearningProvider, transform: TransformProvider, + dashboardDrilldownPanelActions: DashboardDrilldownPanelActionsProvider, + dashboardDrilldownsManage: DashboardDrilldownsManageProvider, }; From 5ea78184ad63bda26dc93c1ffd0eb5ab053f100a Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Sat, 21 Mar 2020 10:00:35 -0500 Subject: [PATCH 17/81] documentation update --- ...ta-public.datapublicpluginstart.actions.md | 2 + ...ugins-data-public.datapublicpluginstart.md | 2 +- ...na-plugin-plugins-data-public.esfilters.md | 1 + src/plugins/data/public/public.api.md | 107 ++++++++++-------- 4 files changed, 61 insertions(+), 51 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md index 3e966caa30799..1476e6b574d8e 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md @@ -9,5 +9,7 @@ ```typescript actions: { createFiltersFromEvent: typeof createFiltersFromEvent; + valueClickActionGetFilters: typeof valueClickActionGetFilters; + selectRangeActionGetFilters: typeof selectRangeActionGetFilters; }; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md index a623e91388fd6..7c5e65bc1708e 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md @@ -14,7 +14,7 @@ export interface DataPublicPluginStart | Property | Type | Description | | --- | --- | --- | -| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromEvent: typeof createFiltersFromEvent;
} | | +| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromEvent: typeof createFiltersFromEvent;
valueClickActionGetFilters: typeof valueClickActionGetFilters;
selectRangeActionGetFilters: typeof selectRangeActionGetFilters;
} | | | [autocomplete](./kibana-plugin-plugins-data-public.datapublicpluginstart.autocomplete.md) | AutocompleteStart | | | [fieldFormats](./kibana-plugin-plugins-data-public.datapublicpluginstart.fieldformats.md) | FieldFormatsStart | | | [indexPatterns](./kibana-plugin-plugins-data-public.datapublicpluginstart.indexpatterns.md) | IndexPatternsContract | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md index 7fd65e5db35f3..37142cf1794c3 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md @@ -49,6 +49,7 @@ esFilters: { generateFilters: typeof generateFilters; onlyDisabledFiltersChanged: (newFilters?: import("../common").Filter[] | undefined, oldFilters?: import("../common").Filter[] | undefined) => boolean; changeTimeFilter: typeof changeTimeFilter; + convertRangeFilterToTimeRangeString: typeof convertRangeFilterToTimeRangeString; mapAndFlattenFilters: (filters: import("../common").Filter[]) => import("../common").Filter[]; extractTimeFilter: typeof extractTimeFilter; } diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index dad3a8e639bc5..270e21820a52a 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -39,6 +39,7 @@ import { Plugin as Plugin_2 } from 'src/core/public'; import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/public'; import { PopoverAnchorPosition } from '@elastic/eui'; import { PublicUiSettingsParams } from 'src/core/server/types'; +import { RangeFilter as RangeFilter_2 } from 'src/plugins/data/public'; import React from 'react'; import * as React_2 from 'react'; import { Required } from '@kbn/utility-types'; @@ -225,6 +226,8 @@ export interface DataPublicPluginStart { // (undocumented) actions: { createFiltersFromEvent: typeof createFiltersFromEvent; + valueClickActionGetFilters: typeof valueClickActionGetFilters; + selectRangeActionGetFilters: typeof selectRangeActionGetFilters; }; // Warning: (ae-forgotten-export) The symbol "AutocompleteStart" needs to be exported by the entry point index.d.ts // @@ -367,6 +370,7 @@ export const esFilters: { generateFilters: typeof generateFilters; onlyDisabledFiltersChanged: (newFilters?: import("../common").Filter[] | undefined, oldFilters?: import("../common").Filter[] | undefined) => boolean; changeTimeFilter: typeof changeTimeFilter; + convertRangeFilterToTimeRangeString: typeof convertRangeFilterToTimeRangeString; mapAndFlattenFilters: (filters: import("../common").Filter[]) => import("../common").Filter[]; extractTimeFilter: typeof extractTimeFilter; }; @@ -1795,58 +1799,61 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/common/es_query/filters/match_all_filter.ts:28:3 - (ae-forgotten-export) The symbol "MatchAllFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrase_filter.ts:33:3 - (ae-forgotten-export) The symbol "PhraseFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrases_filter.ts:31:3 - (ae-forgotten-export) The symbol "PhrasesFilterMeta" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "FilterLabel" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "generateFilters" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:379:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:379:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:379:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:379:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:384:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:385:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:387:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:396:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:397:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:398:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FilterLabel" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "generateFilters" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "convertRangeFilterToTimeRangeString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:381:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:381:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:381:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:381:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:386:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:387:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:398:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:399:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:403:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:404:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:407:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromEvent" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:60:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:56:5 - (ae-forgotten-export) The symbol "createFiltersFromEvent" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:57:5 - (ae-forgotten-export) The symbol "valueClickActionGetFilters" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:58:5 - (ae-forgotten-export) The symbol "selectRangeActionGetFilters" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:66:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) From 100c4f090dac36a9388579dba45b6f021c7700b0 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 23 Mar 2020 11:49:12 +0100 Subject: [PATCH 18/81] chore clean-ups fix type --- .../filters/create_filters_from_event.ts | 5 ---- .../public/actions/select_range_action.ts | 10 +++---- .../data/public/actions/value_click_action.ts | 15 +++++----- .../dashboard_drilldowns_services.ts | 2 -- .../collect_config.tsx | 29 +++++++++++++------ .../drilldown.tsx | 1 - 6 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/plugins/data/public/actions/filters/create_filters_from_event.ts b/src/plugins/data/public/actions/filters/create_filters_from_event.ts index 8b6135a246ce1..e62945a592072 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_event.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_event.ts @@ -84,11 +84,6 @@ const createFilter = async (table: EventData['table'], columnIndex: number, rowI if (!column.meta || !column.meta.indexPatternId) { return; } - console.log('aggConfig', column.meta.indexPatternId); // eslint-disable-line - console.log( // eslint-disable-line - 'This fails, but not always', - await getIndexPatterns().get(column.meta.indexPatternId) - ); const aggConfig = deserializeAggConfig({ type: column.meta.type, aggConfigParams: column.meta.aggConfigParams ? column.meta.aggConfigParams : {}, diff --git a/src/plugins/data/public/actions/select_range_action.ts b/src/plugins/data/public/actions/select_range_action.ts index c5358285acf1b..e17d336a852d1 100644 --- a/src/plugins/data/public/actions/select_range_action.ts +++ b/src/plugins/data/public/actions/select_range_action.ts @@ -34,11 +34,11 @@ export interface SelectRangeActionContext { } async function isCompatible(context: SelectRangeActionContext) { - // try { - return Boolean(await onBrushEvent(context.data)); - // } catch { - // return false; - // } + try { + return Boolean(await onBrushEvent(context.data)); + } catch { + return false; + } } export const selectRangeActionGetFilters = async ({ diff --git a/src/plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts index d2f7d7cc0272f..90549f1e9e292 100644 --- a/src/plugins/data/public/actions/value_click_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -38,13 +38,14 @@ export interface ValueClickActionContext { } async function isCompatible(context: ValueClickActionContext) { - // try { - const filters: Filter[] = - (await createFiltersFromEvent(context.data.data || [context.data], context.data.negate)) || []; - return filters.length > 0; - // } catch { - // return false; - // } + try { + const filters: Filter[] = + (await createFiltersFromEvent(context.data.data || [context.data], context.data.negate)) || + []; + return filters.length > 0; + } catch { + return false; + } } // this allows the user to select which filter to use diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts index dd887130d4b5c..71502a7dce026 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts @@ -31,9 +31,7 @@ interface BootstrapParams { } export class DashboardDrilldownsService { - // async bootstrap(core: CoreSetup, plugins: SetupDependencies) { bootstrap( - // core: CoreSetup<{ drilldowns: DrilldownsStart }>, core: CoreSetup, plugins: SetupDependencies, { enableDrilldowns }: BootstrapParams diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx index 0cc2d97b8ee56..572bc1c04b2ad 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx @@ -43,6 +43,7 @@ export class CollectConfigContainer extends React.Component< CollectConfigProps, CollectConfigContainerState > { + private isMounted = true; state = { dashboards: [], isLoading: false, @@ -51,11 +52,20 @@ export class CollectConfigContainer extends React.Component< delay: false, }; + constructor(props: CollectConfigProps) { + super(props); + this.debouncedLoadDashboards = debounce(this.loadDashboards.bind(this), 500); + } + componentDidMount() { this.loadSelectedDashboard(); this.loadDashboards(); } + componentWillUnmount() { + this.isMounted = false; + } + loadSelectedDashboard() { const { config } = this.props; this.props.deps.getSavedObjectsClient().then(savedObjectsClient => { @@ -63,15 +73,16 @@ export class CollectConfigContainer extends React.Component< savedObjectsClient .get<{ title: string }>('dashboard', config.dashboardId) .then(dashboard => { + if (!this.isMounted) return; this.setState({ selectedDashboard: dashboardSavedObjectToMenuItem(dashboard) }); }); } }); } + private readonly debouncedLoadDashboards: (searchString?: string) => void; loadDashboards(searchString?: string) { - // const currentDashboard = this.props.context.placeContext.embeddable.parent; - // const currentDashboardId = currentDashboard && currentDashboard.id; + const currentDashboardId = this.props.context.placeContext.embeddable?.parent?.id; this.setState({ searchString, isLoading: true }); this.props.deps.getSavedObjectsClient().then(savedObjectsClient => { savedObjectsClient @@ -83,12 +94,12 @@ export class CollectConfigContainer extends React.Component< perPage: 100, }) .then(({ savedObjects }) => { - if (searchString === this.state.searchString) { - const dashboardList = savedObjects.map(dashboardSavedObjectToMenuItem); - // temporarily disable for dev purposes - // .filter(({ value }) => value !== currentDashboardId); - this.setState({ dashboards: dashboardList, isLoading: false }); - } + if (!this.isMounted) return; + if (searchString !== this.state.searchString) return; + const dashboardList = savedObjects + .map(dashboardSavedObjectToMenuItem) + .filter(({ value }) => !currentDashboardId || value !== currentDashboardId); + this.setState({ dashboards: dashboardList, isLoading: false }); }); }); } @@ -107,7 +118,7 @@ export class CollectConfigContainer extends React.Component< onDashboardSelect={dashboardId => { onConfig({ ...config, dashboardId }); }} - onSearchChange={debounce(() => this.loadDashboards(), 500)} + onSearchChange={this.debouncedLoadDashboards} onCurrentFiltersToggle={() => onConfig({ ...config, diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index 4ae76527bc083..3e95c86a4a0ee 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -82,7 +82,6 @@ export class DashboardToDashboardDrilldown // for brush event this time range would be overwritten let timeRange = config.useCurrentDateRange ? currentTimeRange : undefined; - // @ts-ignore TODO if (context.data.range) { // look up by range const { restOfFilters, timeRangeFilter } = From 340fd890d6cbd12593ca4108cd05cd0239605a51 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 23 Mar 2020 14:28:03 +0100 Subject: [PATCH 19/81] basic unit test for dashboard drilldown --- .../drilldown.test.tsx | 310 +++++++++++++++++- 1 file changed, 301 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx index 0fb60bb1064a1..08a150cb78088 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx @@ -4,17 +4,309 @@ * you may not use this file except in compliance with the Elastic License. */ +import { DashboardToDashboardDrilldown } from './drilldown'; +import { UrlGeneratorContract } from '../../../../../../../src/plugins/share/public'; +import { savedObjectsServiceMock } from '../../../../../../../src/core/public/mocks'; +import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; +import { ActionContext, Config } from './types'; +import { VisualizeEmbeddableContract } from '../../../../../../../src/legacy/core_plugins/visualizations/public/'; +import { + Filter, + FilterStateStore, + Query, + RangeFilter, + TimeRange, +} from '../../../../../../../src/plugins/data/common'; +import { esFilters } from '../../../../../../../src/plugins/data/public'; + +// convenient to use real implementation here. +import { createDirectAccessDashboardLinkGenerator } from '../../../../../../../src/plugins/dashboard/public/url_generator'; + describe('.isConfigValid()', () => { - test.todo('returns false for incorrect config'); - test.todo('returns true for incorrect config'); + const drilldown = new DashboardToDashboardDrilldown({} as any); + + test('returns false for invalid config with missing dashboard id', () => { + expect( + drilldown.isConfigValid({ + dashboardId: '', + useCurrentDateRange: false, + useCurrentFilters: false, + }) + ).toBe(false); + }); + + test('returns true for valid config', () => { + expect( + drilldown.isConfigValid({ + dashboardId: 'id', + useCurrentDateRange: false, + useCurrentFilters: false, + }) + ).toBe(true); + }); +}); + +test('config component exist', () => { + const drilldown = new DashboardToDashboardDrilldown({} as any); + expect(drilldown.CollectConfig).toEqual(expect.any(Function)); }); describe('.execute()', () => { - test.todo('navigates to correct dashboard'); - test.todo( - 'when user chooses to keep current filters, current fileters are set on destination dashboard' - ); - test.todo( - 'when user chooses to keep current time range, current time range is set on destination dashboard' - ); + /** + * A convenience test setup helper + * Beware: `dataPluginMock.createStartContract().actions` and extracting filters from event is mocked! + * The url generation is not mocked and uses real implementation + * So this tests are mostly focused on making sure the filters returned from `dataPluginMock.createStartContract().actions` helpers + * end up in resulting navigation path + */ + async function setupTestBed( + config: Partial, + embeddableInput: { filters?: Filter[]; timeRange?: TimeRange; query?: Query }, + filtersFromEvent: { restOfFilters?: Filter[]; timeRangeFilter?: RangeFilter }, + useRangeEvent = false + ) { + const navigateToApp = jest.fn(); + const dataPluginActions = dataPluginMock.createStartContract().actions; + const drilldown = new DashboardToDashboardDrilldown({ + getNavigateToApp: () => Promise.resolve(navigateToApp), + getGetUrlGenerator: () => + Promise.resolve( + () => + createDirectAccessDashboardLinkGenerator(() => + Promise.resolve({ appBasePath: 'test', useHashedUrl: false }) + ) as UrlGeneratorContract + ), + getDataPluginActions: () => Promise.resolve(dataPluginActions), + getSavedObjectsClient: () => + Promise.resolve(savedObjectsServiceMock.createStartContract().client), + }); + const selectRangeFiltersSpy = jest + .spyOn(dataPluginActions, 'selectRangeActionGetFilters') + .mockImplementationOnce(() => + Promise.resolve({ + restOfFilters: filtersFromEvent.restOfFilters || [], + timeRangeFilter: filtersFromEvent.timeRangeFilter, + }) + ); + const valueClickFiltersSpy = jest + .spyOn(dataPluginActions, 'valueClickActionGetFilters') + .mockImplementationOnce(() => + Promise.resolve({ + restOfFilters: filtersFromEvent.restOfFilters || [], + timeRangeFilter: filtersFromEvent.timeRangeFilter, + }) + ); + + await drilldown.execute( + { + dashboardId: 'id', + useCurrentFilters: false, + useCurrentDateRange: false, + ...config, + }, + ({ + data: { + range: useRangeEvent ? {} : undefined, + }, + embeddable: { + getInput: () => ({ + filters: [], + timeRange: { from: 'now-15m', to: 'now' }, + query: { query: 'test', language: 'kuery' }, + ...embeddableInput, + }), + }, + } as unknown) as ActionContext + ); + + if (useRangeEvent) { + expect(selectRangeFiltersSpy).toBeCalledTimes(1); + expect(valueClickFiltersSpy).toBeCalledTimes(0); + } else { + expect(selectRangeFiltersSpy).toBeCalledTimes(0); + expect(valueClickFiltersSpy).toBeCalledTimes(1); + } + + expect(navigateToApp).toBeCalledTimes(1); + expect(navigateToApp.mock.calls[0][0]).toBe('kibana'); + + return { + navigatedPath: navigateToApp.mock.calls[0][1]?.path, + }; + } + + test('navigates to correct dashboard', async () => { + const testDashboardId = 'dashboardId'; + const { navigatedPath } = await setupTestBed( + { + dashboardId: testDashboardId, + }, + {}, + {}, + false + ); + + expect(navigatedPath).toEqual(expect.stringContaining(`dashboard/${testDashboardId}`)); + }); + + test('navigates with query', async () => { + const queryString = 'querystring'; + const queryLanguage = 'kuery'; + const { navigatedPath } = await setupTestBed( + {}, + { + query: { query: queryString, language: queryLanguage }, + }, + {}, + true + ); + + expect(navigatedPath).toEqual(expect.stringContaining(queryString)); + expect(navigatedPath).toEqual(expect.stringContaining(queryLanguage)); + }); + + test('when user chooses to keep current filters, current filters are set on destination dashboard', async () => { + const existingAppFilterKey = 'appExistingFilter'; + const existingGlobalFilterKey = 'existingGlobalFilter'; + const newAppliedFilterKey = 'newAppliedFilter'; + + const { navigatedPath } = await setupTestBed( + { + useCurrentFilters: true, + }, + { + filters: [getFilter(false, existingAppFilterKey), getFilter(true, existingGlobalFilterKey)], + }, + { + restOfFilters: [getFilter(false, newAppliedFilterKey)], + }, + false + ); + + expect(navigatedPath).toEqual(expect.stringContaining(existingAppFilterKey)); + expect(navigatedPath).toEqual(expect.stringContaining(existingGlobalFilterKey)); + expect(navigatedPath).toEqual(expect.stringContaining(newAppliedFilterKey)); + }); + + test('when user chooses to remove current filters, current app filters are remove on destination dashboard', async () => { + const existingAppFilterKey = 'appExistingFilter'; + const existingGlobalFilterKey = 'existingGlobalFilter'; + const newAppliedFilterKey = 'newAppliedFilter'; + + const { navigatedPath } = await setupTestBed( + { + useCurrentFilters: false, + }, + { + filters: [getFilter(false, existingAppFilterKey), getFilter(true, existingGlobalFilterKey)], + }, + { + restOfFilters: [getFilter(false, newAppliedFilterKey)], + }, + false + ); + + expect(navigatedPath).not.toEqual(expect.stringContaining(existingAppFilterKey)); + expect(navigatedPath).toEqual(expect.stringContaining(existingGlobalFilterKey)); + expect(navigatedPath).toEqual(expect.stringContaining(newAppliedFilterKey)); + }); + + test('when user chooses to keep current time range, current time range is passed in url', async () => { + const { navigatedPath } = await setupTestBed( + { + useCurrentDateRange: true, + }, + { + timeRange: { + from: 'now-300m', + to: 'now', + }, + }, + {}, + false + ); + + expect(navigatedPath).toEqual(expect.stringContaining('now-300m')); + }); + + test('when user chooses to not keep current time range, no current time range is passed in url', async () => { + const { navigatedPath } = await setupTestBed( + { + useCurrentDateRange: false, + }, + { + timeRange: { + from: 'now-300m', + to: 'now', + }, + }, + {}, + false + ); + + expect(navigatedPath).not.toEqual(expect.stringContaining('now-300m')); + }); + + test('if range filter contains date, then it is passed as time', async () => { + const { navigatedPath } = await setupTestBed( + { + useCurrentDateRange: true, + }, + { + timeRange: { + from: 'now-300m', + to: 'now', + }, + }, + { timeRangeFilter: getMockTimeRangeFilter() }, + true + ); + + expect(navigatedPath).not.toEqual(expect.stringContaining('now-300m')); + expect(navigatedPath).toEqual(expect.stringContaining('2020-03-23')); + }); }); + +function getFilter(isPinned: boolean, queryKey: string): Filter { + return { + $state: { + store: isPinned ? esFilters.FilterStateStore.GLOBAL_STATE : FilterStateStore.APP_STATE, + }, + meta: { + index: 'logstash-*', + disabled: false, + negate: false, + alias: null, + }, + query: { + match: { + [queryKey]: 'any', + }, + }, + }; +} + +function getMockTimeRangeFilter(): RangeFilter { + return { + meta: { + index: 'logstash-*', + params: { + gte: '2020-03-23T13:10:29.665Z', + lt: '2020-03-23T13:10:36.736Z', + format: 'strict_date_optional_time', + }, + type: 'range', + key: 'order_date', + disabled: false, + negate: false, + alias: null, + }, + range: { + order_date: { + gte: '2020-03-23T13:10:29.665Z', + lt: '2020-03-23T13:10:36.736Z', + format: 'strict_date_optional_time', + }, + }, + }; +} From 406facde4c6e0d9726e1760f8b9986e98d0ca1c5 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 23 Mar 2020 15:46:51 +0100 Subject: [PATCH 20/81] remove test todos decided to skip those tests because not clear how to test due to EuiCombobox is using react-virtualized and options list is not rendered in jsdom env --- .../dashboard_drilldown_config.test.tsx | 11 ----------- .../collect_config.test.tsx | 9 --------- 2 files changed, 20 deletions(-) delete mode 100644 x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.test.tsx delete mode 100644 x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.test.tsx diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.test.tsx b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.test.tsx deleted file mode 100644 index 911ff6f632635..0000000000000 --- a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.test.tsx +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -test.todo('renders list of dashboards'); -test.todo('renders correct selected dashboard'); -test.todo('can change dashboard'); -test.todo('can toggle "use current filters" switch'); -test.todo('can toggle "date range" switch'); diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.test.tsx deleted file mode 100644 index 95101605ce468..0000000000000 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.test.tsx +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -test.todo('displays all dashboard in a list'); -test.todo('does not display dashboard on which drilldown is being created'); -test.todo('updates config object correctly'); From bf9e50548c20de1b11423cd07353839d87fad5b4 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 23 Mar 2020 16:07:07 +0100 Subject: [PATCH 21/81] remove config --- config/kibana.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/config/kibana.yml b/config/kibana.yml index d387f7468a972..0780841ca057e 100644 --- a/config/kibana.yml +++ b/config/kibana.yml @@ -110,6 +110,3 @@ # Specifies locale to be used for all localizable strings, dates and number formats. # Supported languages are the following: English - en , by default , Chinese - zh-CN . #i18n.locale: "en" - -# Enables "Drilldowns" functionality on dashboard. Set to true by default. -# xpack.dashboardEnhanced.drilldowns.enabled: false From d7633b3e28c2c8b256005d5e39a896d5a3b9f5d2 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 23 Mar 2020 17:23:23 +0100 Subject: [PATCH 22/81] improve back button with filter comparison tweak --- .../filter_manager/compare_filters.test.ts | 22 +++++++++++++++++++ .../query/filter_manager/compare_filters.ts | 6 +++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/plugins/data/common/query/filter_manager/compare_filters.test.ts b/src/plugins/data/common/query/filter_manager/compare_filters.test.ts index b0bb2f754d6cf..c42bd720d3b7f 100644 --- a/src/plugins/data/common/query/filter_manager/compare_filters.test.ts +++ b/src/plugins/data/common/query/filter_manager/compare_filters.test.ts @@ -92,6 +92,28 @@ describe('filter manager utilities', () => { expect(compareFilters(f1, f2)).toBeTruthy(); }); + test('should compare duplicates, assuming $state: { store: FilterStateStore.APP_STATE } is default', () => { + const f1 = { + $state: { store: FilterStateStore.APP_STATE }, + ...buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index', ''), + }; + const f2 = { + ...buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index', ''), + }; + const f3 = { + $state: { store: FilterStateStore.GLOBAL_STATE }, + ...buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index', ''), + }; + + // don't take state into account at all: + expect(compareFilters(f1, f2)).toBeTruthy(); + expect(compareFilters(f2, f3)).toBeTruthy(); + + // compare with state: + expect(compareFilters(f1, f2, { state: true })).toBeTruthy(); + expect(compareFilters(f2, f3, { state: true })).toBeFalsy(); + }); + test('should compare filters array to non array', () => { const f1 = buildQueryFilter( { _type: { match: { query: 'apache', type: 'phrase' } } }, diff --git a/src/plugins/data/common/query/filter_manager/compare_filters.ts b/src/plugins/data/common/query/filter_manager/compare_filters.ts index e047d5e0665d5..c19d00faaf251 100644 --- a/src/plugins/data/common/query/filter_manager/compare_filters.ts +++ b/src/plugins/data/common/query/filter_manager/compare_filters.ts @@ -18,7 +18,7 @@ */ import { defaults, isEqual, omit, map } from 'lodash'; -import { FilterMeta, Filter } from '../../es_query'; +import { FilterMeta, Filter, FilterStateStore } from '../../es_query'; export interface FilterCompareOptions { disabled?: boolean; @@ -42,11 +42,13 @@ const mapFilter = ( comparators: FilterCompareOptions, excludedAttributes: string[] ) => { - const cleaned: FilterMeta = omit(filter, excludedAttributes); + const cleaned: Filter & FilterMeta = omit(filter, excludedAttributes); if (comparators.negate) cleaned.negate = filter.meta && Boolean(filter.meta.negate); if (comparators.disabled) cleaned.disabled = filter.meta && Boolean(filter.meta.disabled); if (comparators.disabled) cleaned.alias = filter.meta?.alias; + if (comparators.state) + cleaned.$state = { store: filter.$state?.store ?? FilterStateStore.APP_STATE }; return cleaned; }; From 59101ef1ea3e1e89bd8226c5e1f555f7f5b413c3 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 23 Mar 2020 17:29:28 +0100 Subject: [PATCH 23/81] dashboard filters/date option off by default --- .../drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index 3e95c86a4a0ee..1425c6033578c 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -45,8 +45,8 @@ export class DashboardToDashboardDrilldown public readonly createConfig = () => ({ dashboardId: '', - useCurrentFilters: true, - useCurrentDateRange: true, + useCurrentFilters: false, + useCurrentDateRange: false, }); public readonly isConfigValid = (config: Config): config is Config => { From bb308d6858f61f3706d8deea8c8889fe6040387c Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Mon, 23 Mar 2020 12:08:00 -0500 Subject: [PATCH 24/81] revert change to config/kibana.yml --- config/kibana.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/config/kibana.yml b/config/kibana.yml index 13728a7bf212a..0780841ca057e 100644 --- a/config/kibana.yml +++ b/config/kibana.yml @@ -110,6 +110,3 @@ # Specifies locale to be used for all localizable strings, dates and number formats. # Supported languages are the following: English - en , by default , Chinese - zh-CN . #i18n.locale: "en" - -# Enables "Drilldowns" functionality on dashboard. Set to false by default. -xpack.dashboardEnhanced.drilldowns.enabled: true From 31e28a3eb965eb1330bd9a4bf9f544781ffb757f Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Mon, 23 Mar 2020 13:27:23 -0500 Subject: [PATCH 25/81] remove unneeded comments --- src/plugins/data/public/actions/value_click_action.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts index 90549f1e9e292..ae1483c99bcd1 100644 --- a/src/plugins/data/public/actions/value_click_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -90,11 +90,9 @@ export const valueClickActionGetFilters = async ( throw new IncompatibleActionError(); } - // const filters: Filter[] = (await createFiltersFromEvent(data.data || [data], data.negate)) || []; let selectedFilters: Filter[] = esFilters.mapAndFlattenFilters(filters); - // filters if (selectedFilters.length > 1) { selectedFilters = await filterSelection(filters); From 38ec7a03a2b09794bcfb2680cb511b82c5f267dd Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Mon, 23 Mar 2020 21:09:33 -0500 Subject: [PATCH 26/81] use default time range as appropriate --- .../drilldown.tsx | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index 1425c6033578c..fd88213bff6b3 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -8,7 +8,10 @@ import React from 'react'; import { CoreStart } from 'src/core/public'; import { reactToUiComponent } from '../../../../../../../src/plugins/kibana_react/public'; import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; -import { DASHBOARD_APP_URL_GENERATOR } from '../../../../../../../src/plugins/dashboard/public'; +import { + DASHBOARD_APP_URL_GENERATOR, + DashboardContainerInput, +} from '../../../../../../../src/plugins/dashboard/public'; import { VisualizeEmbeddableContract } from '../../../../../../../src/legacy/core_plugins/visualizations/public'; import { PlaceContext, ActionContext, Config, CollectConfigProps } from './types'; @@ -60,6 +63,8 @@ export class DashboardToDashboardDrilldown ) => { const getUrlGenerator = await this.params.getGetUrlGenerator(); const navigateToApp = await this.params.getNavigateToApp(); + const savedObjectsClient = await this.params.getSavedObjectsClient(); + const { selectRangeActionGetFilters, valueClickActionGetFilters, @@ -70,6 +75,16 @@ export class DashboardToDashboardDrilldown filters: currentFilters, } = context.embeddable.getInput(); + const savedDashboard = await savedObjectsClient.get<{ timeTo: string; timeFrom: string }>( + 'dashboard', + config.dashboardId as string + ); + + const defaultTimeRange = { + to: savedDashboard.attributes.timeTo, + from: savedDashboard.attributes.timeFrom, + }; + // if useCurrentDashboardFilters enabled, then preserve all the filters (pinned and unpinned) // otherwise preserve only pinned const filters = @@ -80,7 +95,7 @@ export class DashboardToDashboardDrilldown // if useCurrentDashboardDataRange is enabled, then preserve current time range // if undefined is passed, then destination dashboard will figure out time range itself // for brush event this time range would be overwritten - let timeRange = config.useCurrentDateRange ? currentTimeRange : undefined; + let timeRange = config.useCurrentDateRange ? currentTimeRange : defaultTimeRange; if (context.data.range) { // look up by range From 4a8d4a1eb8c7b0dd676f97453f63c09b459e09a7 Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Mon, 23 Mar 2020 22:22:20 -0500 Subject: [PATCH 27/81] fix type, add filter icon, add text --- src/plugins/data/public/actions/apply_filter_action.ts | 1 + src/plugins/data/public/actions/select_range_action.ts | 1 + src/plugins/data/public/actions/value_click_action.ts | 1 + .../dashboard_to_dashboard_drilldown/drilldown.tsx | 5 +---- .../components/connected_flyout_manage_drilldowns/i18n.ts | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/data/public/actions/apply_filter_action.ts b/src/plugins/data/public/actions/apply_filter_action.ts index bd20c6f632a3a..ebaac6b745bec 100644 --- a/src/plugins/data/public/actions/apply_filter_action.ts +++ b/src/plugins/data/public/actions/apply_filter_action.ts @@ -42,6 +42,7 @@ export function createFilterAction( return createAction({ type: ACTION_GLOBAL_APPLY_FILTER, id: ACTION_GLOBAL_APPLY_FILTER, + getIconType: () => 'filter', getDisplayName: () => { return i18n.translate('data.filter.applyFilterActionTitle', { defaultMessage: 'Apply filter to current view', diff --git a/src/plugins/data/public/actions/select_range_action.ts b/src/plugins/data/public/actions/select_range_action.ts index e17d336a852d1..11fb287c9ae2c 100644 --- a/src/plugins/data/public/actions/select_range_action.ts +++ b/src/plugins/data/public/actions/select_range_action.ts @@ -80,6 +80,7 @@ export function selectRangeAction( return createAction({ type: ACTION_SELECT_RANGE, id: ACTION_SELECT_RANGE, + getIconType: () => 'filter', getDisplayName: () => { return i18n.translate('data.filter.applyFilterActionTitle', { defaultMessage: 'Apply filter to current view', diff --git a/src/plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts index ae1483c99bcd1..d51b604a0c392 100644 --- a/src/plugins/data/public/actions/value_click_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -128,6 +128,7 @@ export function valueClickAction( return createAction({ type: ACTION_VALUE_CLICK, id: ACTION_VALUE_CLICK, + getIconType: () => 'filter', getDisplayName: () => { return i18n.translate('data.filter.applyFilterActionTitle', { defaultMessage: 'Apply filter to current view', diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index fd88213bff6b3..d78959789e4a2 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -8,10 +8,7 @@ import React from 'react'; import { CoreStart } from 'src/core/public'; import { reactToUiComponent } from '../../../../../../../src/plugins/kibana_react/public'; import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; -import { - DASHBOARD_APP_URL_GENERATOR, - DashboardContainerInput, -} from '../../../../../../../src/plugins/dashboard/public'; +import { DASHBOARD_APP_URL_GENERATOR } from '../../../../../../../src/plugins/dashboard/public'; import { VisualizeEmbeddableContract } from '../../../../../../../src/legacy/core_plugins/visualizations/public'; import { PlaceContext, ActionContext, Config, CollectConfigProps } from './types'; diff --git a/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/i18n.ts b/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/i18n.ts index 70f4d735e2a74..9fa366445ebae 100644 --- a/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/i18n.ts +++ b/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/i18n.ts @@ -15,7 +15,7 @@ export const toastDrilldownCreated = { ), text: (drilldownName: string) => i18n.translate('xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownCreatedText', { - defaultMessage: 'You created "{drilldownName}"', + defaultMessage: 'You created "{drilldownName}", save dashboard to test.', values: { drilldownName, }, @@ -31,7 +31,7 @@ export const toastDrilldownEdited = { ), text: (drilldownName: string) => i18n.translate('xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownEditedText', { - defaultMessage: 'You edited "{drilldownName}"', + defaultMessage: 'You edited "{drilldownName}", save dashboard to test.', values: { drilldownName, }, From 0deb6b4614db9749693cc5610e0feca201f7f344 Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Tue, 24 Mar 2020 00:13:45 -0500 Subject: [PATCH 28/81] fix test --- .../dashboard_to_dashboard_drilldown/drilldown.test.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx index 08a150cb78088..bc73592501cd6 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx @@ -67,6 +67,11 @@ describe('.execute()', () => { ) { const navigateToApp = jest.fn(); const dataPluginActions = dataPluginMock.createStartContract().actions; + const savedObjectsClient = savedObjectsServiceMock.createStartContract().client; + savedObjectsClient.get = jest + .fn() + .mockReturnValue({ attributes: { from: 'now-15m', to: 'now' } }); + const drilldown = new DashboardToDashboardDrilldown({ getNavigateToApp: () => Promise.resolve(navigateToApp), getGetUrlGenerator: () => @@ -77,8 +82,7 @@ describe('.execute()', () => { ) as UrlGeneratorContract ), getDataPluginActions: () => Promise.resolve(dataPluginActions), - getSavedObjectsClient: () => - Promise.resolve(savedObjectsServiceMock.createStartContract().client), + getSavedObjectsClient: () => Promise.resolve(savedObjectsClient), }); const selectRangeFiltersSpy = jest .spyOn(dataPluginActions, 'selectRangeActionGetFilters') From 6a78486b8423348376d13fdaa26cba55fbf651cd Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 24 Mar 2020 16:25:28 +0100 Subject: [PATCH 29/81] change how time range is restored and improve back button for drilldowns --- .../np_ready/dashboard_app_controller.tsx | 21 +++++++++------ .../apps/management/_kibana_settings.js | 27 ++++++++++--------- .../drilldown.test.tsx | 3 --- .../drilldown.tsx | 13 +-------- 4 files changed, 29 insertions(+), 35 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx index d1e4c9d2d2a0c..e2236f2894c41 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx @@ -36,6 +36,7 @@ import { IndexPattern, IndexPatternsContract, Query, + QueryState, SavedQuery, syncQueryStateWithUrl, } from '../../../../../../plugins/data/public'; @@ -132,13 +133,6 @@ export class DashboardAppController { const queryFilter = filterManager; const timefilter = queryService.timefilter.timefilter; - // starts syncing `_g` portion of url with query services - // note: dashboard_state_manager.ts syncs `_a` portion of url - const { - stop: stopSyncingQueryServiceStateWithUrl, - hasInheritedQueryFromUrl: hasInheritedGlobalStateFromUrl, - } = syncQueryStateWithUrl(queryService, kbnUrlStateStorage); - let lastReloadRequestTime = 0; const dash = ($scope.dash = $route.current.locals.dash); if (dash.id) { @@ -170,9 +164,20 @@ export class DashboardAppController { // The hash check is so we only update the time filter on dashboard open, not during // normal cross app navigation. - if (dashboardStateManager.getIsTimeSavedWithDashboard() && !hasInheritedGlobalStateFromUrl) { + const initialGlobalStateInUrl = kbnUrlStateStorage.get('_g'); + const hasInheritedTimeRange = Boolean(initialGlobalStateInUrl?.time); + if (dashboardStateManager.getIsTimeSavedWithDashboard() && !hasInheritedTimeRange) { dashboardStateManager.syncTimefilterWithDashboard(timefilter); } + // starts syncing `_g` portion of url with query services + // note: dashboard_state_manager.ts syncs `_a` portion of url + // it is important to start this syncing after `dashboardStateManager.syncTimefilterWithDashboard(timefilter);` above is run, + // otherwise it will case redundant browser history record + const { stop: stopSyncingQueryServiceStateWithUrl } = syncQueryStateWithUrl( + queryService, + kbnUrlStateStorage + ); + $scope.showSaveQuery = dashboardCapabilities.saveQuery as boolean; const getShouldShowEditHelp = () => diff --git a/test/functional/apps/management/_kibana_settings.js b/test/functional/apps/management/_kibana_settings.js index c99368ba4e859..97337d4573e2a 100644 --- a/test/functional/apps/management/_kibana_settings.js +++ b/test/functional/apps/management/_kibana_settings.js @@ -46,6 +46,18 @@ export default function({ getService, getPageObjects }) { }); describe('state:storeInSessionStorage', () => { + async function getStateFromUrl() { + const currentUrl = await browser.getCurrentUrl(); + let match = currentUrl.match(/(.*)?_g=(.*)&_a=(.*)/); + if (match) return [match[2], match[3]]; + match = currentUrl.match(/(.*)?_a=(.*)&_g=(.*)/); + if (match) return [match[3], match[2]]; + + if (!match) { + throw new Error('State in url is missing or malformed'); + } + } + it('defaults to null', async () => { await PageObjects.settings.clickKibanaSettings(); const storeInSessionStorage = await PageObjects.settings.getAdvancedSettingCheckbox( @@ -58,10 +70,7 @@ export default function({ getService, getPageObjects }) { await PageObjects.common.navigateToApp('dashboard'); await PageObjects.dashboard.clickNewDashboard(); await PageObjects.timePicker.setDefaultAbsoluteRange(); - const currentUrl = await browser.getCurrentUrl(); - const urlPieces = currentUrl.match(/(.*)?_g=(.*)&_a=(.*)/); - const globalState = urlPieces[2]; - const appState = urlPieces[3]; + const [globalState, appState] = await getStateFromUrl(); // We don't have to be exact, just need to ensure it's greater than when the hashed variation is being used, // which is less than 20 characters. @@ -83,10 +92,7 @@ export default function({ getService, getPageObjects }) { await PageObjects.common.navigateToApp('dashboard'); await PageObjects.dashboard.clickNewDashboard(); await PageObjects.timePicker.setDefaultAbsoluteRange(); - const currentUrl = await browser.getCurrentUrl(); - const urlPieces = currentUrl.match(/(.*)?_g=(.*)&_a=(.*)/); - const globalState = urlPieces[2]; - const appState = urlPieces[3]; + const [globalState, appState] = await getStateFromUrl(); // We don't have to be exact, just need to ensure it's less than the unhashed version, which will be // greater than 20 characters with the default state plus a time. @@ -100,10 +106,7 @@ export default function({ getService, getPageObjects }) { await PageObjects.settings.clickKibanaSettings(); await PageObjects.settings.toggleAdvancedSettingCheckbox('state:storeInSessionStorage'); await PageObjects.header.clickDashboard(); - const currentUrl = await browser.getCurrentUrl(); - const urlPieces = currentUrl.match(/(.*)?_g=(.*)&_a=(.*)/); - const globalState = urlPieces[2]; - const appState = urlPieces[3]; + const [globalState, appState] = await getStateFromUrl(); // We don't have to be exact, just need to ensure it's greater than when the hashed variation is being used, // which is less than 20 characters. expect(globalState.length).to.be.greaterThan(20); diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx index bc73592501cd6..b368799e3a337 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx @@ -68,9 +68,6 @@ describe('.execute()', () => { const navigateToApp = jest.fn(); const dataPluginActions = dataPluginMock.createStartContract().actions; const savedObjectsClient = savedObjectsServiceMock.createStartContract().client; - savedObjectsClient.get = jest - .fn() - .mockReturnValue({ attributes: { from: 'now-15m', to: 'now' } }); const drilldown = new DashboardToDashboardDrilldown({ getNavigateToApp: () => Promise.resolve(navigateToApp), diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index d78959789e4a2..1404b0aa1f4dd 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -60,7 +60,6 @@ export class DashboardToDashboardDrilldown ) => { const getUrlGenerator = await this.params.getGetUrlGenerator(); const navigateToApp = await this.params.getNavigateToApp(); - const savedObjectsClient = await this.params.getSavedObjectsClient(); const { selectRangeActionGetFilters, @@ -72,16 +71,6 @@ export class DashboardToDashboardDrilldown filters: currentFilters, } = context.embeddable.getInput(); - const savedDashboard = await savedObjectsClient.get<{ timeTo: string; timeFrom: string }>( - 'dashboard', - config.dashboardId as string - ); - - const defaultTimeRange = { - to: savedDashboard.attributes.timeTo, - from: savedDashboard.attributes.timeFrom, - }; - // if useCurrentDashboardFilters enabled, then preserve all the filters (pinned and unpinned) // otherwise preserve only pinned const filters = @@ -92,7 +81,7 @@ export class DashboardToDashboardDrilldown // if useCurrentDashboardDataRange is enabled, then preserve current time range // if undefined is passed, then destination dashboard will figure out time range itself // for brush event this time range would be overwritten - let timeRange = config.useCurrentDateRange ? currentTimeRange : defaultTimeRange; + let timeRange = config.useCurrentDateRange ? currentTimeRange : undefined; if (context.data.range) { // look up by range From 514561b364044ff1a24155dc1a20ba69a3948a5e Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 7 Apr 2020 17:54:53 +0200 Subject: [PATCH 30/81] resolve conflicts --- src/legacy/core_plugins/vis_type_vislib/public/plugin.ts | 2 +- src/plugins/embeddable/public/lib/triggers/triggers.ts | 6 +++--- .../dashboard_to_dashboard_drilldown/drilldown.test.tsx | 2 +- .../dashboard_to_dashboard_drilldown/drilldown.tsx | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts b/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts index 2731fb6f5fbe6..4fbf891e15d8e 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts @@ -111,6 +111,6 @@ export class VisTypeVislibPlugin implements Plugin { public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) { setFormatService(data.fieldFormats); - setDataActions({ createFiltersFromEvent: data.actions.createFiltersFromEvent }); + setDataActions(data.actions); } } diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index 7317b0c87c0b6..87b234a63aa9a 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -25,12 +25,12 @@ export interface EmbeddableContext { } export interface EmbeddableVisTriggerContext { - embeddable: T; - timeFieldName: string; + embeddable?: T; + timeFieldName?: string; data: { e?: MouseEvent; data: unknown; - range: unknown; + range?: unknown; }; } diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx index b368799e3a337..ab88b58fe6b77 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx @@ -9,7 +9,6 @@ import { UrlGeneratorContract } from '../../../../../../../src/plugins/share/pub import { savedObjectsServiceMock } from '../../../../../../../src/core/public/mocks'; import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; import { ActionContext, Config } from './types'; -import { VisualizeEmbeddableContract } from '../../../../../../../src/legacy/core_plugins/visualizations/public/'; import { Filter, FilterStateStore, @@ -21,6 +20,7 @@ import { esFilters } from '../../../../../../../src/plugins/data/public'; // convenient to use real implementation here. import { createDirectAccessDashboardLinkGenerator } from '../../../../../../../src/plugins/dashboard/public/url_generator'; +import { VisualizeEmbeddableContract } from '../../../../../../../src/plugins/visualizations/public'; describe('.isConfigValid()', () => { const drilldown = new DashboardToDashboardDrilldown({} as any); diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index 1404b0aa1f4dd..e42d310b33fcd 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -9,7 +9,6 @@ import { CoreStart } from 'src/core/public'; import { reactToUiComponent } from '../../../../../../../src/plugins/kibana_react/public'; import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; import { DASHBOARD_APP_URL_GENERATOR } from '../../../../../../../src/plugins/dashboard/public'; -import { VisualizeEmbeddableContract } from '../../../../../../../src/legacy/core_plugins/visualizations/public'; import { PlaceContext, ActionContext, Config, CollectConfigProps } from './types'; import { CollectConfigContainer } from './collect_config'; @@ -17,6 +16,7 @@ import { DASHBOARD_TO_DASHBOARD_DRILLDOWN } from './constants'; import { DrilldownDefinition as Drilldown } from '../../../../../drilldowns/public'; import { txtGoToDashboard } from './i18n'; import { DataPublicPluginStart, esFilters } from '../../../../../../../src/plugins/data/public'; +import { VisualizeEmbeddableContract } from '../../../../../../../src/plugins/visualizations/public'; export interface Params { getSavedObjectsClient: () => Promise; @@ -69,7 +69,7 @@ export class DashboardToDashboardDrilldown timeRange: currentTimeRange, query, filters: currentFilters, - } = context.embeddable.getInput(); + } = context.embeddable!.getInput(); // if useCurrentDashboardFilters enabled, then preserve all the filters (pinned and unpinned) // otherwise preserve only pinned @@ -87,7 +87,7 @@ export class DashboardToDashboardDrilldown // look up by range const { restOfFilters, timeRangeFilter } = (await selectRangeActionGetFilters({ - timeFieldName: context.timeFieldName, + timeFieldName: context.timeFieldName!, data: context.data, })) || {}; filters.push(...(restOfFilters || [])); @@ -96,7 +96,7 @@ export class DashboardToDashboardDrilldown } } else { const { restOfFilters, timeRangeFilter } = await valueClickActionGetFilters({ - timeFieldName: context.timeFieldName, + timeFieldName: context.timeFieldName!, data: context.data, }); filters.push(...(restOfFilters || [])); From 40e396c6777227a3f1dae14ac08eedacc265a36d Mon Sep 17 00:00:00 2001 From: Matt Kime Date: Tue, 7 Apr 2020 21:14:48 -0500 Subject: [PATCH 31/81] fix async compile issue --- .../data/public/actions/value_click_action.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts index d51b604a0c392..e346b3a6f0c3e 100644 --- a/src/plugins/data/public/actions/value_click_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -88,17 +88,20 @@ export const valueClickActionGetFilters = async ( }> => { if (!(await isCompatible({ timeFieldName, data }))) { throw new IncompatibleActionError(); - } + // note - the else statement is necessary due to odd compilation behavior + // code after the throw statement can't contain await statements + } else { + const filters: Filter[] = + (await createFiltersFromEvent(data.data || [data], data.negate)) || []; - const filters: Filter[] = (await createFiltersFromEvent(data.data || [data], data.negate)) || []; + let selectedFilters: Filter[] = esFilters.mapAndFlattenFilters(filters); - let selectedFilters: Filter[] = esFilters.mapAndFlattenFilters(filters); + if (selectedFilters.length > 1) { + selectedFilters = await filterSelection(filters); + } - if (selectedFilters.length > 1) { - selectedFilters = await filterSelection(filters); + return esFilters.extractTimeFilter(timeFieldName || '', selectedFilters); } - - return esFilters.extractTimeFilter(timeFieldName || '', selectedFilters); }; // gets and applies the filters From a9b86a96b9200863a86cc9beb4286e3db5862697 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 8 Apr 2020 11:25:08 +0200 Subject: [PATCH 32/81] remove redundant test --- .../filter_manager/compare_filters.test.ts | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/src/plugins/data/common/query/filter_manager/compare_filters.test.ts b/src/plugins/data/common/query/filter_manager/compare_filters.test.ts index 3faa47a5000e0..0c3947ade8221 100644 --- a/src/plugins/data/common/query/filter_manager/compare_filters.test.ts +++ b/src/plugins/data/common/query/filter_manager/compare_filters.test.ts @@ -92,28 +92,6 @@ describe('filter manager utilities', () => { expect(compareFilters(f1, f2)).toBeTruthy(); }); - test('should compare duplicates, assuming $state: { store: FilterStateStore.APP_STATE } is default', () => { - const f1 = { - $state: { store: FilterStateStore.APP_STATE }, - ...buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index', ''), - }; - const f2 = { - ...buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index', ''), - }; - const f3 = { - $state: { store: FilterStateStore.GLOBAL_STATE }, - ...buildQueryFilter({ _type: { match: { query: 'apache', type: 'phrase' } } }, 'index', ''), - }; - - // don't take state into account at all: - expect(compareFilters(f1, f2)).toBeTruthy(); - expect(compareFilters(f2, f3)).toBeTruthy(); - - // compare with state: - expect(compareFilters(f1, f2, { state: true })).toBeTruthy(); - expect(compareFilters(f2, f3, { state: true })).toBeFalsy(); - }); - test('should compare filters array to non array', () => { const f1 = buildQueryFilter( { _type: { match: { query: 'apache', type: 'phrase' } } }, From af4a20f72e00bc2047f2ac7a7730161d699da367 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 8 Apr 2020 18:25:12 +0200 Subject: [PATCH 33/81] wip --- ...ta-public.datapublicpluginstart.actions.md | 2 +- ...ugins-data-public.datapublicpluginstart.md | 2 +- .../vislib/components/legend/legend.test.tsx | 4 +- .../vislib/components/legend/legend.tsx | 2 +- .../new_platform/new_platform.karma_mock.js | 2 +- ...> create_filters_from_brush_event.test.ts} | 18 +-- ....ts => create_filters_from_brush_event.ts} | 15 +- ...te_filters_from_value_click_event.test.ts} | 13 +- ... create_filters_from_value_click_event.ts} | 17 ++- src/plugins/data/public/actions/index.ts | 7 +- .../public/actions/select_range_action.ts | 57 +++----- .../data/public/actions/value_click_action.ts | 136 +++++++----------- src/plugins/data/public/mocks.ts | 5 +- src/plugins/data/public/plugin.ts | 22 ++- src/plugins/data/public/public.api.md | 4 +- src/plugins/data/public/types.ts | 11 +- .../public/lib/triggers/triggers.ts | 1 + .../drilldown.test.tsx | 39 ++--- .../drilldown.tsx | 36 ++--- 19 files changed, 171 insertions(+), 222 deletions(-) rename src/plugins/data/public/actions/filters/{brush_event.test.ts => create_filters_from_brush_event.test.ts} (90%) rename src/plugins/data/public/actions/filters/{brush_event.ts => create_filters_from_brush_event.ts} (83%) rename src/plugins/data/public/actions/filters/{create_filters_from_event.test.ts => create_filters_from_value_click_event.test.ts} (89%) rename src/plugins/data/public/actions/filters/{create_filters_from_event.ts => create_filters_from_value_click_event.ts} (92%) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md index 1476e6b574d8e..8098121638fb7 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md @@ -8,7 +8,7 @@ ```typescript actions: { - createFiltersFromEvent: typeof createFiltersFromEvent; + createFiltersFromValueClickEvent: typeof createFiltersFromValueClickEvent; valueClickActionGetFilters: typeof valueClickActionGetFilters; selectRangeActionGetFilters: typeof selectRangeActionGetFilters; }; diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md index 7c5e65bc1708e..79669438754af 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md @@ -14,7 +14,7 @@ export interface DataPublicPluginStart | Property | Type | Description | | --- | --- | --- | -| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromEvent: typeof createFiltersFromEvent;
valueClickActionGetFilters: typeof valueClickActionGetFilters;
selectRangeActionGetFilters: typeof selectRangeActionGetFilters;
} | | +| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromValueClickEvent: typeof createFiltersFromValueClickEvent;
valueClickActionGetFilters: typeof valueClickActionGetFilters;
selectRangeActionGetFilters: typeof selectRangeActionGetFilters;
} | | | [autocomplete](./kibana-plugin-plugins-data-public.datapublicpluginstart.autocomplete.md) | AutocompleteStart | | | [fieldFormats](./kibana-plugin-plugins-data-public.datapublicpluginstart.fieldformats.md) | FieldFormatsStart | | | [indexPatterns](./kibana-plugin-plugins-data-public.datapublicpluginstart.indexpatterns.md) | IndexPatternsContract | | diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx index c378ae7b05b37..bea7e79656075 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx @@ -36,7 +36,9 @@ jest.mock('../../../legacy_imports', () => ({ })); jest.mock('../../../services', () => ({ - getDataActions: () => ({ createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']) }), + getDataActions: () => ({ + createFiltersFromValueClickEvent: jest.fn().mockResolvedValue(['yes']), + }), })); const vis = { diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx index 2fe16bbfeb625..7436ef6506e94 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx @@ -101,7 +101,7 @@ export class VisLegend extends PureComponent { return false; } - const filters = await getDataActions().createFiltersFromEvent(item.values); + const filters = await getDataActions().createFiltersFromValueClickEvent(item.values); return Boolean(filters.length); }; diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index 25647e4a08897..5745caf27dfa1 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -348,7 +348,7 @@ export const npStart = { }, data: { actions: { - createFiltersFromEvent: Promise.resolve(['yes']), + createFiltersFromValueClickEvent: Promise.resolve(['yes']), }, autocomplete: { getProvider: sinon.fake(), diff --git a/src/plugins/data/public/actions/filters/brush_event.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_brush_event.test.ts similarity index 90% rename from src/plugins/data/public/actions/filters/brush_event.test.ts rename to src/plugins/data/public/actions/filters/create_filters_from_brush_event.test.ts index 60244354f06e4..f4c85082f2d9f 100644 --- a/src/plugins/data/public/actions/filters/brush_event.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_brush_event.test.ts @@ -19,14 +19,14 @@ import moment from 'moment'; -import { onBrushEvent, BrushEvent } from './brush_event'; +import { createFiltersFromBrushEvent, BrushEvent } from './brush_event'; import { IndexPatternsContract } from '../../../public'; import { dataPluginMock } from '../../../public/mocks'; import { setIndexPatterns } from '../../../public/services'; import { mockDataServices } from '../../../public/search/aggs/test_helpers'; -describe('brushEvent', () => { +describe('createFiltersFromBrushEvent', () => { const DAY_IN_MS = 24 * 60 * 60 * 1000; const JAN_01_2014 = 1388559600000; let baseEvent: BrushEvent; @@ -94,11 +94,11 @@ describe('brushEvent', () => { }); test('should be a function', () => { - expect(typeof onBrushEvent).toBe('function'); + expect(typeof createFiltersFromBrushEvent).toBe('function'); }); test('ignores event when data.xAxisField not provided', async () => { - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromBrushEvent(baseEvent); expect(filter).toBeUndefined(); }); @@ -119,13 +119,13 @@ describe('brushEvent', () => { test('by ignoring the event when range spans zero time', async () => { baseEvent.range = [JAN_01_2014, JAN_01_2014]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromBrushEvent(baseEvent); expect(filter).toBeUndefined(); }); test('by updating the timefilter', async () => { baseEvent.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromBrushEvent(baseEvent); expect(filter).toBeDefined(); if (filter) { @@ -154,7 +154,7 @@ describe('brushEvent', () => { const rangeBegin = JAN_01_2014; const rangeEnd = rangeBegin + DAY_IN_MS; baseEvent.range = [rangeBegin, rangeEnd]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromBrushEvent(baseEvent); expect(filter).toBeDefined(); @@ -184,13 +184,13 @@ describe('brushEvent', () => { test('by ignoring the event when range does not span at least 2 values', async () => { baseEvent.range = [1]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromBrushEvent(baseEvent); expect(filter).toBeUndefined(); }); test('by creating a new filter', async () => { baseEvent.range = [1, 2, 3, 4]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromBrushEvent(baseEvent); expect(filter).toBeDefined(); diff --git a/src/plugins/data/public/actions/filters/brush_event.ts b/src/plugins/data/public/actions/filters/create_filters_from_brush_event.ts similarity index 83% rename from src/plugins/data/public/actions/filters/brush_event.ts rename to src/plugins/data/public/actions/filters/create_filters_from_brush_event.ts index 714f005fbeb6d..cc990819caaef 100644 --- a/src/plugins/data/public/actions/filters/brush_event.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_brush_event.ts @@ -19,7 +19,7 @@ import { get, last } from 'lodash'; import moment from 'moment'; -import { esFilters, IFieldType, RangeFilterParams } from '../../../public'; +import { esFilters, Filter, IFieldType, RangeFilterParams } from '../../../public'; import { getIndexPatterns } from '../../../public/services'; import { deserializeAggConfig } from '../../search/expressions/utils'; @@ -33,18 +33,18 @@ export interface BrushEvent { range: number[]; } -export async function onBrushEvent(event: BrushEvent) { +export async function createFiltersFromBrushEvent(event: BrushEvent): Promise { const isDate = get(event.data, 'ordered.date'); const xRaw: Record = get(event.data, 'series[0].values[0].xRaw'); if (!xRaw) { - return; + return []; } const column: Record = xRaw.table.columns[xRaw.column]; if (!column || !column.meta) { - return; + return []; } const indexPattern = await getIndexPatterns().get(column.meta.indexPatternId); @@ -55,14 +55,14 @@ export async function onBrushEvent(event: BrushEvent) { const field: IFieldType = aggConfig.params.field; if (!field || event.range.length <= 1) { - return; + return []; } const min = event.range[0]; const max = last(event.range); if (min === max) { - return; + return []; } const range: RangeFilterParams = { @@ -74,5 +74,6 @@ export async function onBrushEvent(event: BrushEvent) { range.format = 'strict_date_optional_time'; } - return esFilters.buildRangeFilter(field, range, indexPattern); + const rangeFilter = esFilters.buildRangeFilter(field, range, indexPattern); + return rangeFilter ? esFilters.mapAndFlattenFilters([rangeFilter]) : []; } diff --git a/src/plugins/data/public/actions/filters/create_filters_from_event.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click_event.test.ts similarity index 89% rename from src/plugins/data/public/actions/filters/create_filters_from_event.test.ts rename to src/plugins/data/public/actions/filters/create_filters_from_value_click_event.test.ts index 1ed09002816d1..5c0d73f06c8a6 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_event.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click_event.test.ts @@ -26,7 +26,10 @@ import { import { dataPluginMock } from '../../../public/mocks'; import { setIndexPatterns } from '../../../public/services'; import { mockDataServices } from '../../../public/search/aggs/test_helpers'; -import { createFiltersFromEvent, EventData } from './create_filters_from_event'; +import { + createFiltersFromValueClickEvent, + EventData, +} from './create_filters_from_value_click_event'; const mockField = { name: 'bytes', @@ -37,7 +40,7 @@ const mockField = { format: new fieldFormats.BytesFormat({}, (() => {}) as FieldFormatsGetConfigFn), }; -describe('createFiltersFromEvent', () => { +describe('createFiltersFromValueClickEvent', () => { let dataPoints: EventData[]; beforeEach(() => { @@ -86,7 +89,7 @@ describe('createFiltersFromEvent', () => { test('ignores event when value for rows is not provided', async () => { dataPoints[0].table.rows[0]['1-1'] = null; - const filters = await createFiltersFromEvent(dataPoints); + const filters = await createFiltersFromValueClickEvent(dataPoints); expect(filters.length).toEqual(0); }); @@ -95,14 +98,14 @@ describe('createFiltersFromEvent', () => { if (dataPoints[0].table.columns[0].meta) { dataPoints[0].table.columns[0].meta.type = 'terms'; } - const filters = await createFiltersFromEvent(dataPoints); + const filters = await createFiltersFromValueClickEvent(dataPoints); expect(filters.length).toEqual(1); expect(filters[0].query.match_phrase.bytes).toEqual('2048'); }); test('handles an event when aggregations type is not terms', async () => { - const filters = await createFiltersFromEvent(dataPoints); + const filters = await createFiltersFromValueClickEvent(dataPoints); expect(filters.length).toEqual(1); diff --git a/src/plugins/data/public/actions/filters/create_filters_from_event.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click_event.ts similarity index 92% rename from src/plugins/data/public/actions/filters/create_filters_from_event.ts rename to src/plugins/data/public/actions/filters/create_filters_from_value_click_event.ts index e62945a592072..ba49f5420ac62 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_event.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click_event.ts @@ -22,6 +22,12 @@ import { deserializeAggConfig } from '../../search/expressions'; import { esFilters, Filter } from '../../../public'; import { getIndexPatterns } from '../../../public/services'; +export type ArrayOrItem = T | T[]; +export interface ClickEvent { + data: ArrayOrItem; + negate?: boolean; +} + export interface EventData { table: Pick; column: number; @@ -113,11 +119,16 @@ const createFilter = async (table: EventData['table'], columnIndex: number, rowI }; /** @public */ -export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: boolean) => { +export const createFiltersFromValueClickEvent = async ({ + data, + negate = false, +}: ClickEvent): Promise => { + data = Array.isArray(data) ? data : [data]; + const filters: Filter[] = []; await Promise.all( - dataPoints + data .filter(point => point) .map(async val => { const { table, column, row } = val; @@ -133,5 +144,5 @@ export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: b }) ); - return filters; + return esFilters.mapAndFlattenFilters(filters); }; diff --git a/src/plugins/data/public/actions/index.ts b/src/plugins/data/public/actions/index.ts index 105229e2bd81a..406370d8c876f 100644 --- a/src/plugins/data/public/actions/index.ts +++ b/src/plugins/data/public/actions/index.ts @@ -18,6 +18,7 @@ */ export { ACTION_GLOBAL_APPLY_FILTER, createFilterAction } from './apply_filter_action'; -export { createFiltersFromEvent } from './filters/create_filters_from_event'; -export { selectRangeAction, selectRangeActionGetFilters } from './select_range_action'; -export { valueClickAction, valueClickActionGetFilters } from './value_click_action'; +export { createFiltersFromValueClickEvent } from './filters/create_filters_from_value_click_event'; +export { createFiltersFromBrushEvent } from './filters/create_filters_from_brush_event'; +export { selectRangeAction } from './select_range_action'; +export { valueClickAction } from './value_click_action'; diff --git a/src/plugins/data/public/actions/select_range_action.ts b/src/plugins/data/public/actions/select_range_action.ts index 11fb287c9ae2c..f0e5072ab42bd 100644 --- a/src/plugins/data/public/actions/select_range_action.ts +++ b/src/plugins/data/public/actions/select_range_action.ts @@ -23,7 +23,7 @@ import { IncompatibleActionError, ActionByType, } from '../../../../plugins/ui_actions/public'; -import { onBrushEvent } from './filters/brush_event'; +import { createFiltersFromBrushEvent } from './filters/create_filters_from_brush_event'; import { FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_SELECT_RANGE = 'ACTION_SELECT_RANGE'; @@ -35,44 +35,12 @@ export interface SelectRangeActionContext { async function isCompatible(context: SelectRangeActionContext) { try { - return Boolean(await onBrushEvent(context.data)); + return (await createFiltersFromBrushEvent(context.data)).length > 0; } catch { return false; } } -export const selectRangeActionGetFilters = async ({ - timeFieldName, - data, -}: SelectRangeActionContext) => { - if (!(await isCompatible({ timeFieldName, data }))) { - throw new IncompatibleActionError(); - } - - const filter = await onBrushEvent(data); - - if (!filter) { - return; - } - - const selectedFilters = esFilters.mapAndFlattenFilters([filter]); - - return esFilters.extractTimeFilter(timeFieldName || '', selectedFilters); -}; - -const selectRangeActionExecute = ( - filterManager: FilterManager, - timeFilter: TimefilterContract -) => async ({ timeFieldName, data }: SelectRangeActionContext) => { - const { timeRangeFilter, restOfFilters } = - (await selectRangeActionGetFilters({ timeFieldName, data })) || {}; - - filterManager.addFilters(restOfFilters || []); - if (timeRangeFilter) { - esFilters.changeTimeFilter(timeFilter, timeRangeFilter); - } -}; - export function selectRangeAction( filterManager: FilterManager, timeFilter: TimefilterContract @@ -87,6 +55,25 @@ export function selectRangeAction( }); }, isCompatible, - execute: selectRangeActionExecute(filterManager, timeFilter), + execute: async ({ timeFieldName, data }: SelectRangeActionContext) => { + if (!(await isCompatible({ timeFieldName, data }))) { + throw new IncompatibleActionError(); + } + + const selectedFilters = await createFiltersFromBrushEvent(data); + + if (timeFieldName) { + const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( + timeFieldName, + selectedFilters + ); + filterManager.addFilters(restOfFilters); + if (timeRangeFilter) { + esFilters.changeTimeFilter(timeFilter, timeRangeFilter); + } + } else { + filterManager.addFilters(selectedFilters); + } + }, }); } diff --git a/src/plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts index e346b3a6f0c3e..8f103f14c8f83 100644 --- a/src/plugins/data/public/actions/value_click_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -18,7 +18,6 @@ */ import { i18n } from '@kbn/i18n'; -import { RangeFilter } from 'src/plugins/data/public'; import { toMountPoint } from '../../../../plugins/kibana_react/public'; import { ActionByType, @@ -27,7 +26,7 @@ import { } from '../../../../plugins/ui_actions/public'; import { getOverlays, getIndexPatterns } from '../services'; import { applyFiltersPopover } from '../ui/apply_filters'; -import { createFiltersFromEvent } from './filters/create_filters_from_event'; +import { createFiltersFromValueClickEvent } from './filters/create_filters_from_value_click_event'; import { Filter, FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_VALUE_CLICK = 'ACTION_VALUE_CLICK'; @@ -39,91 +38,13 @@ export interface ValueClickActionContext { async function isCompatible(context: ValueClickActionContext) { try { - const filters: Filter[] = - (await createFiltersFromEvent(context.data.data || [context.data], context.data.negate)) || - []; + const filters: Filter[] = await createFiltersFromValueClickEvent(context.data); return filters.length > 0; } catch { return false; } } -// this allows the user to select which filter to use -const filterSelectionFn = (filters: Filter[]): Promise => - new Promise(async resolve => { - const indexPatterns = await Promise.all( - filters.map(filter => { - return getIndexPatterns().get(filter.meta.index!); - }) - ); - - const overlay = getOverlays().openModal( - toMountPoint( - applyFiltersPopover( - filters, - indexPatterns, - () => { - overlay.close(); - resolve([]); - }, - (filterSelection: Filter[]) => { - overlay.close(); - resolve(filterSelection); - } - ) - ), - { - 'data-test-subj': 'selectFilterOverlay', - } - ); - }); - -// given a ValueClickActionContext, returns timeRangeFilter and Filters -export const valueClickActionGetFilters = async ( - { timeFieldName, data }: ValueClickActionContext, - filterSelection: (filters: Filter[]) => Promise = async (filters: Filter[]) => filters -): Promise<{ - timeRangeFilter?: RangeFilter; - restOfFilters: Filter[]; -}> => { - if (!(await isCompatible({ timeFieldName, data }))) { - throw new IncompatibleActionError(); - // note - the else statement is necessary due to odd compilation behavior - // code after the throw statement can't contain await statements - } else { - const filters: Filter[] = - (await createFiltersFromEvent(data.data || [data], data.negate)) || []; - - let selectedFilters: Filter[] = esFilters.mapAndFlattenFilters(filters); - - if (selectedFilters.length > 1) { - selectedFilters = await filterSelection(filters); - } - - return esFilters.extractTimeFilter(timeFieldName || '', selectedFilters); - } -}; - -// gets and applies the filters -export const valueClickActionExecute = ( - filterManager: FilterManager, - timeFilter: TimefilterContract, - filterSelection: (filters: Filter[]) => Promise = async (filters: Filter[]) => filters -) => async ({ timeFieldName, data }: ValueClickActionContext) => { - const { timeRangeFilter, restOfFilters } = await valueClickActionGetFilters( - { - timeFieldName, - data, - }, - filterSelection - ); - - filterManager.addFilters(restOfFilters); - if (timeRangeFilter) { - esFilters.changeTimeFilter(timeFilter, timeRangeFilter); - } -}; - export function valueClickAction( filterManager: FilterManager, timeFilter: TimefilterContract @@ -138,6 +59,57 @@ export function valueClickAction( }); }, isCompatible, - execute: valueClickActionExecute(filterManager, timeFilter, filterSelectionFn), + execute: async ({ timeFieldName, data }: ValueClickActionContext) => { + if (!(await isCompatible({ timeFieldName, data }))) { + throw new IncompatibleActionError(); + } + + let selectedFilters = await createFiltersFromValueClickEvent(data); + + if (selectedFilters.length > 1) { + const indexPatterns = await Promise.all( + selectedFilters.map(filter => { + return getIndexPatterns().get(filter.meta.index!); + }) + ); + + const filterSelectionPromise: Promise = new Promise(resolve => { + const overlay = getOverlays().openModal( + toMountPoint( + applyFiltersPopover( + selectedFilters, + indexPatterns, + () => { + overlay.close(); + resolve([]); + }, + (filterSelection: Filter[]) => { + overlay.close(); + resolve(filterSelection); + } + ) + ), + { + 'data-test-subj': 'selectFilterOverlay', + } + ); + }); + + selectedFilters = await filterSelectionPromise; + } + + if (timeFieldName) { + const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( + timeFieldName, + selectedFilters + ); + filterManager.addFilters(restOfFilters); + if (timeRangeFilter) { + esFilters.changeTimeFilter(timeFilter, timeRangeFilter); + } + } else { + filterManager.addFilters(selectedFilters); + } + }, }); } diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 830a236b433de..3d40ef81f2a19 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -45,9 +45,8 @@ const createStartContract = (): Start => { const queryStartMock = queryServiceMock.createStartContract(); return { actions: { - createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']), - selectRangeActionGetFilters: jest.fn(), - valueClickActionGetFilters: jest.fn(), + createFiltersFromValueClickEvent: jest.fn().mockResolvedValue(['yes']), + createFiltersFromBrushEvent: jest.fn().mockResolvedValue([]), }, autocomplete: autocompleteMock, search: searchStartMock, diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index b0ea231db8e6e..ec3503519ec0a 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -18,13 +18,13 @@ */ import { - PluginInitializerContext, CoreSetup, CoreStart, - Plugin, PackageInfo, + Plugin, + PluginInitializerContext, } from 'src/core/public'; -import { Storage, IStorageWrapper } from '../../kibana_utils/public'; +import { IStorageWrapper, Storage } from '../../kibana_utils/public'; import { DataPublicPluginSetup, DataPublicPluginStart, @@ -51,26 +51,25 @@ import { import { createSearchBar } from './ui/search_bar/create_search_bar'; import { esaggs } from './search/expressions'; import { + APPLY_FILTER_TRIGGER, SELECT_RANGE_TRIGGER, VALUE_CLICK_TRIGGER, - APPLY_FILTER_TRIGGER, } from '../../ui_actions/public'; import { ACTION_GLOBAL_APPLY_FILTER, createFilterAction, - createFiltersFromEvent, - selectRangeActionGetFilters, - valueClickActionGetFilters, + createFiltersFromValueClickEvent, + createFiltersFromBrushEvent, } from './actions'; import { ApplyGlobalFilterActionContext } from './actions/apply_filter_action'; import { + ACTION_SELECT_RANGE, selectRangeAction, SelectRangeActionContext, - ACTION_SELECT_RANGE, } from './actions/select_range_action'; import { - valueClickAction, ACTION_VALUE_CLICK, + valueClickAction, ValueClickActionContext, } from './actions/value_click_action'; @@ -162,9 +161,8 @@ export class DataPublicPlugin implements Plugin = (context: ISearc // src/plugins/data/public/index.ts:414:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:56:5 - (ae-forgotten-export) The symbol "createFiltersFromEvent" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:56:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickEvent" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:57:5 - (ae-forgotten-export) The symbol "valueClickActionGetFilters" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:58:5 - (ae-forgotten-export) The symbol "selectRangeActionGetFilters" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:66:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 887f5c4ec706e..8b4d3801ea136 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -24,11 +24,7 @@ import { ExpressionsSetup } from 'src/plugins/expressions/public'; import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public'; import { AutocompleteSetup, AutocompleteStart } from './autocomplete'; import { FieldFormatsSetup, FieldFormatsStart } from './field_formats'; -import { - createFiltersFromEvent, - valueClickActionGetFilters, - selectRangeActionGetFilters, -} from './actions'; +import { createFiltersFromBrushEvent, createFiltersFromValueClickEvent } from './actions'; import { ISearchSetup, ISearchStart } from './search'; import { QuerySetup, QueryStart } from './query'; import { IndexPatternSelectProps } from './ui/index_pattern_select'; @@ -53,9 +49,8 @@ export interface DataPublicPluginSetup { export interface DataPublicPluginStart { actions: { - createFiltersFromEvent: typeof createFiltersFromEvent; - valueClickActionGetFilters: typeof valueClickActionGetFilters; - selectRangeActionGetFilters: typeof selectRangeActionGetFilters; + createFiltersFromValueClickEvent: typeof createFiltersFromValueClickEvent; + createFiltersFromBrushEvent: typeof createFiltersFromBrushEvent; }; autocomplete: AutocompleteStart; indexPatterns: IndexPatternsContract; diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index 87b234a63aa9a..4291b8f23ae5a 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -31,6 +31,7 @@ export interface EmbeddableVisTriggerContext { async function setupTestBed( config: Partial, embeddableInput: { filters?: Filter[]; timeRange?: TimeRange; query?: Query }, - filtersFromEvent: { restOfFilters?: Filter[]; timeRangeFilter?: RangeFilter }, + filtersFromEvent: Filter[], useRangeEvent = false ) { const navigateToApp = jest.fn(); @@ -82,21 +82,11 @@ describe('.execute()', () => { getSavedObjectsClient: () => Promise.resolve(savedObjectsClient), }); const selectRangeFiltersSpy = jest - .spyOn(dataPluginActions, 'selectRangeActionGetFilters') - .mockImplementationOnce(() => - Promise.resolve({ - restOfFilters: filtersFromEvent.restOfFilters || [], - timeRangeFilter: filtersFromEvent.timeRangeFilter, - }) - ); + .spyOn(dataPluginActions, 'createFiltersFromBrushEvent') + .mockImplementationOnce(() => Promise.resolve(filtersFromEvent)); const valueClickFiltersSpy = jest - .spyOn(dataPluginActions, 'valueClickActionGetFilters') - .mockImplementationOnce(() => - Promise.resolve({ - restOfFilters: filtersFromEvent.restOfFilters || [], - timeRangeFilter: filtersFromEvent.timeRangeFilter, - }) - ); + .spyOn(dataPluginActions, 'createFiltersFromValueClickEvent') + .mockImplementationOnce(() => Promise.resolve(filtersFromEvent)); await drilldown.execute( { @@ -109,6 +99,7 @@ describe('.execute()', () => { data: { range: useRangeEvent ? {} : undefined, }, + timeFieldName: 'order_date', embeddable: { getInput: () => ({ filters: [], @@ -143,7 +134,7 @@ describe('.execute()', () => { dashboardId: testDashboardId, }, {}, - {}, + [], false ); @@ -158,7 +149,7 @@ describe('.execute()', () => { { query: { query: queryString, language: queryLanguage }, }, - {}, + [], true ); @@ -178,9 +169,7 @@ describe('.execute()', () => { { filters: [getFilter(false, existingAppFilterKey), getFilter(true, existingGlobalFilterKey)], }, - { - restOfFilters: [getFilter(false, newAppliedFilterKey)], - }, + [getFilter(false, newAppliedFilterKey)], false ); @@ -201,9 +190,7 @@ describe('.execute()', () => { { filters: [getFilter(false, existingAppFilterKey), getFilter(true, existingGlobalFilterKey)], }, - { - restOfFilters: [getFilter(false, newAppliedFilterKey)], - }, + [getFilter(false, newAppliedFilterKey)], false ); @@ -223,7 +210,7 @@ describe('.execute()', () => { to: 'now', }, }, - {}, + [], false ); @@ -241,7 +228,7 @@ describe('.execute()', () => { to: 'now', }, }, - {}, + [], false ); @@ -259,7 +246,7 @@ describe('.execute()', () => { to: 'now', }, }, - { timeRangeFilter: getMockTimeRangeFilter() }, + [getMockTimeRangeFilter()], true ); diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index e42d310b33fcd..bdb3986aa3f4f 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -62,8 +62,8 @@ export class DashboardToDashboardDrilldown const navigateToApp = await this.params.getNavigateToApp(); const { - selectRangeActionGetFilters, - valueClickActionGetFilters, + createFiltersFromValueClickEvent, + createFiltersFromBrushEvent, } = await this.params.getDataPluginActions(); const { timeRange: currentTimeRange, @@ -73,7 +73,7 @@ export class DashboardToDashboardDrilldown // if useCurrentDashboardFilters enabled, then preserve all the filters (pinned and unpinned) // otherwise preserve only pinned - const filters = + const existingFilters = (config.useCurrentFilters ? currentFilters : currentFilters?.filter(f => esFilters.isFilterPinned(f))) ?? []; @@ -82,24 +82,16 @@ export class DashboardToDashboardDrilldown // if undefined is passed, then destination dashboard will figure out time range itself // for brush event this time range would be overwritten let timeRange = config.useCurrentDateRange ? currentTimeRange : undefined; - - if (context.data.range) { - // look up by range - const { restOfFilters, timeRangeFilter } = - (await selectRangeActionGetFilters({ - timeFieldName: context.timeFieldName!, - data: context.data, - })) || {}; - filters.push(...(restOfFilters || [])); - if (timeRangeFilter) { - timeRange = esFilters.convertRangeFilterToTimeRangeString(timeRangeFilter); - } - } else { - const { restOfFilters, timeRangeFilter } = await valueClickActionGetFilters({ - timeFieldName: context.timeFieldName!, - data: context.data, - }); - filters.push(...(restOfFilters || [])); + let filtersFromEvent = context.data.range + ? await createFiltersFromBrushEvent(context.data as any) + : await createFiltersFromValueClickEvent(context.data as any); + + if (context.timeFieldName) { + const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( + context.timeFieldName, + filtersFromEvent + ); + filtersFromEvent = restOfFilters; if (timeRangeFilter) { timeRange = esFilters.convertRangeFilterToTimeRangeString(timeRangeFilter); } @@ -109,7 +101,7 @@ export class DashboardToDashboardDrilldown dashboardId: config.dashboardId, query, timeRange, - filters, + filters: [...existingFilters, ...filtersFromEvent], }); const dashboardHash = dashboardPath.split('#')[1]; From 2c070b8dc91229c6999672aec0316ac3f998d5ee Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 9 Apr 2020 12:43:49 +0200 Subject: [PATCH 34/81] wip --- .../actions/filters/create_filters_from_brush_event.test.ts | 2 +- .../filters/create_filters_from_value_click_event.test.ts | 2 +- src/plugins/ui_actions/public/util/configurable.ts | 2 +- .../drilldowns/actions/flyout_edit_drilldown/menu_item.tsx | 2 +- .../connected_flyout_manage_drilldowns.tsx | 2 +- .../components/connected_flyout_manage_drilldowns/test_data.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/data/public/actions/filters/create_filters_from_brush_event.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_brush_event.test.ts index f4c85082f2d9f..0ed6cd240df0a 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_brush_event.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_brush_event.test.ts @@ -26,7 +26,7 @@ import { dataPluginMock } from '../../../public/mocks'; import { setIndexPatterns } from '../../../public/services'; import { mockDataServices } from '../../../public/search/aggs/test_helpers'; -describe('createFiltersFromBrushEvent', () => { +describe.skip('createFiltersFromBrushEvent', () => { const DAY_IN_MS = 24 * 60 * 60 * 1000; const JAN_01_2014 = 1388559600000; let baseEvent: BrushEvent; diff --git a/src/plugins/data/public/actions/filters/create_filters_from_value_click_event.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click_event.test.ts index 5c0d73f06c8a6..1331c6f022fe5 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_value_click_event.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click_event.test.ts @@ -40,7 +40,7 @@ const mockField = { format: new fieldFormats.BytesFormat({}, (() => {}) as FieldFormatsGetConfigFn), }; -describe('createFiltersFromValueClickEvent', () => { +describe.skip('createFiltersFromValueClickEvent', () => { let dataPoints: EventData[]; beforeEach(() => { diff --git a/src/plugins/ui_actions/public/util/configurable.ts b/src/plugins/ui_actions/public/util/configurable.ts index d3a527a2183b1..0a5a703abd0c1 100644 --- a/src/plugins/ui_actions/public/util/configurable.ts +++ b/src/plugins/ui_actions/public/util/configurable.ts @@ -17,7 +17,7 @@ * under the License. */ -import { UiComponent } from 'src/plugins/kibana_utils/common'; +import { UiComponent } from 'src/plugins/kibana_utils/public'; /** * Represents something that can be configured by user using UI. diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_edit_drilldown/menu_item.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_edit_drilldown/menu_item.tsx index 4f99fca511b07..a35eab2dff4e7 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_edit_drilldown/menu_item.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_edit_drilldown/menu_item.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiNotificationBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { EmbeddableContext } from '../../../../../../../../src/plugins/embeddable/public'; import { txtDisplayName } from './i18n'; -import { useContainerState } from '../../../../../../../../src/plugins/kibana_utils/common'; +import { useContainerState } from '../../../../../../../../src/plugins/kibana_utils/public'; export const MenuItem: React.FC<{ context: EmbeddableContext }> = ({ context }) => { if (!context.embeddable.dynamicActions) diff --git a/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/connected_flyout_manage_drilldowns.tsx b/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/connected_flyout_manage_drilldowns.tsx index f22ccc2f26f02..4e94f95d4a062 100644 --- a/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/connected_flyout_manage_drilldowns.tsx +++ b/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/connected_flyout_manage_drilldowns.tsx @@ -22,7 +22,7 @@ import { SELECT_RANGE_TRIGGER, TriggerContextMapping, } from '../../../../../../src/plugins/ui_actions/public'; -import { useContainerState } from '../../../../../../src/plugins/kibana_utils/common'; +import { useContainerState } from '../../../../../../src/plugins/kibana_utils/public'; import { DrilldownListItem } from '../list_manage_drilldowns'; import { toastDrilldownCreated, diff --git a/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/test_data.ts b/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/test_data.ts index b8deaa8b842bc..8a67abdaed3f0 100644 --- a/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/test_data.ts +++ b/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/test_data.ts @@ -11,7 +11,7 @@ import { UiActionsSerializedAction, TriggerContextMapping, } from '../../../../../../src/plugins/ui_actions/public'; -import { createStateContainer } from '../../../../../../src/plugins/kibana_utils/common'; +import { createStateContainer } from '../../../../../../src/plugins/kibana_utils/public'; class MockDynamicActionManager implements PublicMethodsOf { public readonly state = createStateContainer({ From 520b3b0ca3bcfecccee2564e8ac68e7c0ceee47f Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 9 Apr 2020 12:56:37 +0200 Subject: [PATCH 35/81] fix --- .../drilldowns/actions/flyout_edit_drilldown/menu_item.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_edit_drilldown/menu_item.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_edit_drilldown/menu_item.test.tsx index be693fadf9282..79486c4fdebd8 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_edit_drilldown/menu_item.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_edit_drilldown/menu_item.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { render, cleanup, act } from '@testing-library/react/pure'; import { MenuItem } from './menu_item'; -import { createStateContainer } from '../../../../../../../../src/plugins/kibana_utils/common'; +import { createStateContainer } from '../../../../../../../../src/plugins/kibana_utils/public'; import { DynamicActionManager } from '../../../../../../../../src/plugins/ui_actions/public'; import { IEmbeddable } from '../../../../../../../../src/plugins/embeddable/public/lib/embeddables'; import '@testing-library/jest-dom'; From 5ef56b80ee886f71ac5555aaf0b2cba434844217 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 9 Apr 2020 13:08:16 +0200 Subject: [PATCH 36/81] temp skip tests --- .../create_filters_from_brush_event.test.ts | 204 ------------------ ...ate_filters_from_value_click_event.test.ts | 119 ---------- 2 files changed, 323 deletions(-) delete mode 100644 src/plugins/data/public/actions/filters/create_filters_from_brush_event.test.ts delete mode 100644 src/plugins/data/public/actions/filters/create_filters_from_value_click_event.test.ts diff --git a/src/plugins/data/public/actions/filters/create_filters_from_brush_event.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_brush_event.test.ts deleted file mode 100644 index 0ed6cd240df0a..0000000000000 --- a/src/plugins/data/public/actions/filters/create_filters_from_brush_event.test.ts +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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 moment from 'moment'; - -import { createFiltersFromBrushEvent, BrushEvent } from './brush_event'; - -import { IndexPatternsContract } from '../../../public'; -import { dataPluginMock } from '../../../public/mocks'; -import { setIndexPatterns } from '../../../public/services'; -import { mockDataServices } from '../../../public/search/aggs/test_helpers'; - -describe.skip('createFiltersFromBrushEvent', () => { - const DAY_IN_MS = 24 * 60 * 60 * 1000; - const JAN_01_2014 = 1388559600000; - let baseEvent: BrushEvent; - - const aggConfigs = [ - { - params: { - field: {}, - }, - getIndexPattern: () => ({ - timeFieldName: 'time', - fields: { - getByName: () => undefined, - filter: () => [], - }, - }), - }, - ]; - - beforeEach(() => { - mockDataServices(); - setIndexPatterns(({ - ...dataPluginMock.createStartContract().indexPatterns, - get: async () => ({ - id: 'indexPatternId', - timeFieldName: 'time', - fields: { - getByName: () => undefined, - filter: () => [], - }, - }), - } as unknown) as IndexPatternsContract); - - baseEvent = { - data: { - ordered: { - date: false, - }, - series: [ - { - values: [ - { - xRaw: { - column: 0, - table: { - columns: [ - { - id: '1', - meta: { - type: 'histogram', - indexPatternId: 'indexPatternId', - aggConfigParams: aggConfigs[0].params, - }, - }, - ], - }, - }, - }, - ], - }, - ], - }, - range: [], - }; - }); - - test('should be a function', () => { - expect(typeof createFiltersFromBrushEvent).toBe('function'); - }); - - test('ignores event when data.xAxisField not provided', async () => { - const filter = await createFiltersFromBrushEvent(baseEvent); - expect(filter).toBeUndefined(); - }); - - describe('handles an event when the x-axis field is a date field', () => { - describe('date field is index pattern timefield', () => { - beforeEach(() => { - aggConfigs[0].params.field = { - name: 'time', - type: 'date', - }; - baseEvent.data.ordered = { date: true }; - }); - - afterAll(() => { - baseEvent.range = []; - baseEvent.data.ordered = { date: false }; - }); - - test('by ignoring the event when range spans zero time', async () => { - baseEvent.range = [JAN_01_2014, JAN_01_2014]; - const filter = await createFiltersFromBrushEvent(baseEvent); - expect(filter).toBeUndefined(); - }); - - test('by updating the timefilter', async () => { - baseEvent.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS]; - const filter = await createFiltersFromBrushEvent(baseEvent); - expect(filter).toBeDefined(); - - if (filter) { - expect(filter.range.time.gte).toBe(new Date(JAN_01_2014).toISOString()); - // Set to a baseline timezone for comparison. - expect(filter.range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString()); - } - }); - }); - - describe('date field is not index pattern timefield', () => { - beforeEach(() => { - aggConfigs[0].params.field = { - name: 'anotherTimeField', - type: 'date', - }; - baseEvent.data.ordered = { date: true }; - }); - - afterAll(() => { - baseEvent.range = []; - baseEvent.data.ordered = { date: false }; - }); - - test('creates a new range filter', async () => { - const rangeBegin = JAN_01_2014; - const rangeEnd = rangeBegin + DAY_IN_MS; - baseEvent.range = [rangeBegin, rangeEnd]; - const filter = await createFiltersFromBrushEvent(baseEvent); - - expect(filter).toBeDefined(); - - if (filter) { - expect(filter.range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString()); - expect(filter.range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString()); - expect(filter.range.anotherTimeField).toHaveProperty( - 'format', - 'strict_date_optional_time' - ); - } - }); - }); - }); - - describe('handles an event when the x-axis field is a number', () => { - beforeAll(() => { - aggConfigs[0].params.field = { - name: 'numberField', - type: 'number', - }; - }); - - afterAll(() => { - baseEvent.range = []; - }); - - test('by ignoring the event when range does not span at least 2 values', async () => { - baseEvent.range = [1]; - const filter = await createFiltersFromBrushEvent(baseEvent); - expect(filter).toBeUndefined(); - }); - - test('by creating a new filter', async () => { - baseEvent.range = [1, 2, 3, 4]; - const filter = await createFiltersFromBrushEvent(baseEvent); - - expect(filter).toBeDefined(); - - if (filter) { - expect(filter.range.numberField.gte).toBe(1); - expect(filter.range.numberField.lt).toBe(4); - expect(filter.range.numberField).not.toHaveProperty('format'); - } - }); - }); -}); diff --git a/src/plugins/data/public/actions/filters/create_filters_from_value_click_event.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click_event.test.ts deleted file mode 100644 index 1331c6f022fe5..0000000000000 --- a/src/plugins/data/public/actions/filters/create_filters_from_value_click_event.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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 { - fieldFormats, - FieldFormatsGetConfigFn, - esFilters, - IndexPatternsContract, -} from '../../../public'; -import { dataPluginMock } from '../../../public/mocks'; -import { setIndexPatterns } from '../../../public/services'; -import { mockDataServices } from '../../../public/search/aggs/test_helpers'; -import { - createFiltersFromValueClickEvent, - EventData, -} from './create_filters_from_value_click_event'; - -const mockField = { - name: 'bytes', - indexPattern: { - id: 'logstash-*', - }, - filterable: true, - format: new fieldFormats.BytesFormat({}, (() => {}) as FieldFormatsGetConfigFn), -}; - -describe.skip('createFiltersFromValueClickEvent', () => { - let dataPoints: EventData[]; - - beforeEach(() => { - dataPoints = [ - { - table: { - columns: [ - { - name: 'test', - id: '1-1', - meta: { - type: 'histogram', - indexPatternId: 'logstash-*', - aggConfigParams: { - field: 'bytes', - interval: 30, - otherBucket: true, - }, - }, - }, - ], - rows: [ - { - '1-1': '2048', - }, - ], - }, - column: 0, - row: 0, - value: 'test', - }, - ]; - - mockDataServices(); - setIndexPatterns(({ - ...dataPluginMock.createStartContract().indexPatterns, - get: async () => ({ - id: 'logstash-*', - fields: { - getByName: () => mockField, - filter: () => [mockField], - }, - }), - } as unknown) as IndexPatternsContract); - }); - - test('ignores event when value for rows is not provided', async () => { - dataPoints[0].table.rows[0]['1-1'] = null; - const filters = await createFiltersFromValueClickEvent(dataPoints); - - expect(filters.length).toEqual(0); - }); - - test('handles an event when aggregations type is a terms', async () => { - if (dataPoints[0].table.columns[0].meta) { - dataPoints[0].table.columns[0].meta.type = 'terms'; - } - const filters = await createFiltersFromValueClickEvent(dataPoints); - - expect(filters.length).toEqual(1); - expect(filters[0].query.match_phrase.bytes).toEqual('2048'); - }); - - test('handles an event when aggregations type is not terms', async () => { - const filters = await createFiltersFromValueClickEvent(dataPoints); - - expect(filters.length).toEqual(1); - - const [rangeFilter] = filters; - - if (esFilters.isRangeFilter(rangeFilter)) { - expect(rangeFilter.range.bytes.gte).toEqual(2048); - expect(rangeFilter.range.bytes.lt).toEqual(2078); - } - }); -}); From 07bee638d70671ac14566ea689ae834973241f08 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 9 Apr 2020 13:18:10 +0200 Subject: [PATCH 37/81] fix --- .../vis_type_vislib/public/vislib/components/legend/legend.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx index 7436ef6506e94..d2d09234e7774 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx @@ -101,7 +101,7 @@ export class VisLegend extends PureComponent { return false; } - const filters = await getDataActions().createFiltersFromValueClickEvent(item.values); + const filters = await getDataActions().createFiltersFromValueClickEvent({ data: item.values }); return Boolean(filters.length); }; From a14439e3355a7f5b6e71b775a2d2bf57b08f1e3b Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 9 Apr 2020 14:35:19 +0200 Subject: [PATCH 38/81] handle missing dashboard edge case --- .../dashboard_drilldown_config.tsx | 5 ++++- .../collect_config.tsx | 20 ++++++++++++++++--- .../dashboard_to_dashboard_drilldown/i18n.ts | 9 +++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx index 386664da4f625..ac74f4718cc2b 100644 --- a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx @@ -22,6 +22,7 @@ export interface DashboardDrilldownConfigProps { onKeepRangeToggle?: () => void; onSearchChange: (searchString: string) => void; isLoading: boolean; + error?: string | null; } export const DashboardDrilldownConfig: React.FC = ({ @@ -34,12 +35,13 @@ export const DashboardDrilldownConfig: React.FC = onKeepRangeToggle, onSearchChange, isLoading, + error, }) => { const selectedTitle = dashboards.find(item => item.value === activeDashboardId)?.label || ''; return ( <> - + async selectedOptions={ @@ -52,6 +54,7 @@ export const DashboardDrilldownConfig: React.FC = singleSelection={{ asPlainText: true }} fullWidth data-test-subj={'dashboardDrilldownSelectDashboard'} + isInvalid={!!error} /> {!!onCurrentFiltersToggle && ( diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx index 572bc1c04b2ad..94ca10f62a757 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx @@ -10,6 +10,7 @@ import { debounce, findIndex } from 'lodash'; import { CollectConfigProps } from './types'; import { DashboardDrilldownConfig } from '../../../components/dashboard_drilldown_config'; import { SimpleSavedObject } from '../../../../../../../src/core/public'; +import { txtDestinationDashboardNotFound } from './i18n'; const mergeDashboards = ( dashboards: Array>, @@ -36,7 +37,7 @@ interface CollectConfigContainerState { searchString?: string; isLoading: boolean; selectedDashboard?: EuiComboBoxOptionOption; - delay: boolean; + error: string | null; } export class CollectConfigContainer extends React.Component< @@ -49,7 +50,7 @@ export class CollectConfigContainer extends React.Component< isLoading: false, searchString: undefined, selectedDashboard: undefined, - delay: false, + error: null, }; constructor(props: CollectConfigProps) { @@ -74,6 +75,15 @@ export class CollectConfigContainer extends React.Component< .get<{ title: string }>('dashboard', config.dashboardId) .then(dashboard => { if (!this.isMounted) return; + if (dashboard.error?.statusCode === 404) { + this.setState({ + error: txtDestinationDashboardNotFound(config.dashboardId), + }); + this.props.onConfig({ ...config, dashboardId: undefined }); + return; + } + if (dashboard.error) return; + this.setState({ selectedDashboard: dashboardSavedObjectToMenuItem(dashboard) }); }); } @@ -106,7 +116,7 @@ export class CollectConfigContainer extends React.Component< render() { const { config, onConfig } = this.props; - const { dashboards, selectedDashboard, isLoading } = this.state; + const { dashboards, selectedDashboard, isLoading, error } = this.state; return ( { onConfig({ ...config, dashboardId }); + if (this.state.error) { + this.setState({ error: null }); + } }} onSearchChange={this.debouncedLoadDashboards} onCurrentFiltersToggle={() => diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/i18n.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/i18n.ts index 98b746bafd24a..0fbb53b464e14 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/i18n.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/i18n.ts @@ -9,3 +9,12 @@ import { i18n } from '@kbn/i18n'; export const txtGoToDashboard = i18n.translate('xpack.dashboard.drilldown.goToDashboard', { defaultMessage: 'Go to Dashboard', }); + +export const txtDestinationDashboardNotFound = (dashboardId?: string) => + i18n.translate('xpack.dashboard.drilldown.errorDestinationDashboardIsMissing', { + defaultMessage: + "Destination dashboard ('{dashboardId}') no longer exists. Choose another dashboard.", + values: { + dashboardId, + }, + }); From af1ab76519b40f15df9d68ae6224cf44870bf3b0 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 9 Apr 2020 14:54:47 +0200 Subject: [PATCH 39/81] fix api --- ...ugins-data-public.datapublicpluginstart.actions.md | 3 +-- ...lugin-plugins-data-public.datapublicpluginstart.md | 2 +- src/plugins/data/public/public.api.md | 11 ++++------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md index 8098121638fb7..b0a86d539863c 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md @@ -9,7 +9,6 @@ ```typescript actions: { createFiltersFromValueClickEvent: typeof createFiltersFromValueClickEvent; - valueClickActionGetFilters: typeof valueClickActionGetFilters; - selectRangeActionGetFilters: typeof selectRangeActionGetFilters; + createFiltersFromBrushEvent: typeof createFiltersFromBrushEvent; }; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md index 79669438754af..2f115775eb1e6 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md @@ -14,7 +14,7 @@ export interface DataPublicPluginStart | Property | Type | Description | | --- | --- | --- | -| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromValueClickEvent: typeof createFiltersFromValueClickEvent;
valueClickActionGetFilters: typeof valueClickActionGetFilters;
selectRangeActionGetFilters: typeof selectRangeActionGetFilters;
} | | +| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromValueClickEvent: typeof createFiltersFromValueClickEvent;
createFiltersFromBrushEvent: typeof createFiltersFromBrushEvent;
} | | | [autocomplete](./kibana-plugin-plugins-data-public.datapublicpluginstart.autocomplete.md) | AutocompleteStart | | | [fieldFormats](./kibana-plugin-plugins-data-public.datapublicpluginstart.fieldformats.md) | FieldFormatsStart | | | [indexPatterns](./kibana-plugin-plugins-data-public.datapublicpluginstart.indexpatterns.md) | IndexPatternsContract | | diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index fe0ead65342c8..edaf4e89e301f 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -40,7 +40,6 @@ import { Plugin as Plugin_2 } from 'src/core/public'; import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/public'; import { PopoverAnchorPosition } from '@elastic/eui'; import { PublicUiSettingsParams } from 'src/core/server/types'; -import { RangeFilter as RangeFilter_2 } from 'src/plugins/data/public'; import React from 'react'; import * as React_2 from 'react'; import { Required } from '@kbn/utility-types'; @@ -246,8 +245,7 @@ export interface DataPublicPluginStart { // (undocumented) actions: { createFiltersFromValueClickEvent: typeof createFiltersFromValueClickEvent; - valueClickActionGetFilters: typeof valueClickActionGetFilters; - selectRangeActionGetFilters: typeof selectRangeActionGetFilters; + createFiltersFromBrushEvent: typeof createFiltersFromBrushEvent; }; // Warning: (ae-forgotten-export) The symbol "AutocompleteStart" needs to be exported by the entry point index.d.ts // @@ -1903,10 +1901,9 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/public/index.ts:414:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:56:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickEvent" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:57:5 - (ae-forgotten-export) The symbol "valueClickActionGetFilters" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:58:5 - (ae-forgotten-export) The symbol "selectRangeActionGetFilters" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:66:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickEvent" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:53:5 - (ae-forgotten-export) The symbol "createFiltersFromBrushEvent" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:61:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) From baf61baa3af0745720139d56fdd5635a76be3c34 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Wed, 8 Apr 2020 09:03:51 -0700 Subject: [PATCH 40/81] refactor action filter creation utils --- .../vis_type_vislib/public/plugin.ts | 4 +- .../vislib/components/legend/legend.test.tsx | 4 +- .../vislib/components/legend/legend.tsx | 2 +- .../new_platform/new_platform.karma_mock.js | 2 +- ... create_filters_from_range_select.test.ts} | 79 ++++++++----------- ...ts => create_filters_from_range_select.ts} | 34 +++----- ...> create_filters_from_value_click.test.ts} | 10 +-- ....ts => create_filters_from_value_click.ts} | 11 ++- src/plugins/data/public/actions/index.ts | 2 +- .../public/actions/select_range_action.ts | 17 ++-- .../data/public/actions/value_click_action.ts | 18 ++--- src/plugins/data/public/mocks.ts | 2 +- src/plugins/data/public/plugin.ts | 8 +- src/plugins/data/public/types.ts | 4 +- .../public/lib/triggers/triggers.ts | 5 +- 15 files changed, 96 insertions(+), 106 deletions(-) rename src/plugins/data/public/actions/filters/{brush_event.test.ts => create_filters_from_range_select.test.ts} (70%) rename src/plugins/data/public/actions/filters/{brush_event.ts => create_filters_from_range_select.ts} (75%) rename src/plugins/data/public/actions/filters/{create_filters_from_event.test.ts => create_filters_from_value_click.test.ts} (88%) rename src/plugins/data/public/actions/filters/{create_filters_from_event.ts => create_filters_from_value_click.ts} (94%) diff --git a/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts b/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts index 2731fb6f5fbe6..0c771fb0f977b 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts @@ -111,6 +111,8 @@ export class VisTypeVislibPlugin implements Plugin { public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) { setFormatService(data.fieldFormats); - setDataActions({ createFiltersFromEvent: data.actions.createFiltersFromEvent }); + setDataActions({ + createFiltersFromValueClickAction: data.actions.createFiltersFromValueClickAction, + }); } } diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx index c378ae7b05b37..6bf66c2bdd788 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx @@ -36,7 +36,9 @@ jest.mock('../../../legacy_imports', () => ({ })); jest.mock('../../../services', () => ({ - getDataActions: () => ({ createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']) }), + getDataActions: () => ({ + createFiltersFromValueClickAction: jest.fn().mockResolvedValue(['yes']), + }), })); const vis = { diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx index 2fe16bbfeb625..7eb25e3930718 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx @@ -101,7 +101,7 @@ export class VisLegend extends PureComponent { return false; } - const filters = await getDataActions().createFiltersFromEvent(item.values); + const filters = await getDataActions().createFiltersFromValueClickAction({ data: item.values }); return Boolean(filters.length); }; diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index 33a7fdad065b4..5097062f64a61 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -375,7 +375,7 @@ export const npStart = { }, data: { actions: { - createFiltersFromEvent: Promise.resolve(['yes']), + createFiltersFromValueClickAction: Promise.resolve(['yes']), }, autocomplete: { getProvider: sinon.fake(), diff --git a/src/plugins/data/public/actions/filters/brush_event.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts similarity index 70% rename from src/plugins/data/public/actions/filters/brush_event.test.ts rename to src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts index 60244354f06e4..b0b9ac0669ed2 100644 --- a/src/plugins/data/public/actions/filters/brush_event.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts @@ -19,7 +19,10 @@ import moment from 'moment'; -import { onBrushEvent, BrushEvent } from './brush_event'; +import { + createFiltersFromRangeSelectAction, + RangeSelectEvent, +} from './create_filters_from_range_select'; import { IndexPatternsContract } from '../../../public'; import { dataPluginMock } from '../../../public/mocks'; @@ -29,7 +32,7 @@ import { mockDataServices } from '../../../public/search/aggs/test_helpers'; describe('brushEvent', () => { const DAY_IN_MS = 24 * 60 * 60 * 1000; const JAN_01_2014 = 1388559600000; - let baseEvent: BrushEvent; + let baseEvent: RangeSelectEvent; const aggConfigs = [ { @@ -61,44 +64,32 @@ describe('brushEvent', () => { } as unknown) as IndexPatternsContract); baseEvent = { - data: { - ordered: { - date: false, - }, - series: [ + column: 0, + table: { + type: 'kibana_datatable', + columns: [ { - values: [ - { - xRaw: { - column: 0, - table: { - columns: [ - { - id: '1', - meta: { - type: 'histogram', - indexPatternId: 'indexPatternId', - aggConfigParams: aggConfigs[0].params, - }, - }, - ], - }, - }, - }, - ], + id: '1', + name: '1', + meta: { + type: 'histogram', + indexPatternId: 'indexPatternId', + aggConfigParams: aggConfigs[0].params, + }, }, ], + rows: [], }, range: [], }; }); test('should be a function', () => { - expect(typeof onBrushEvent).toBe('function'); + expect(typeof createFiltersFromRangeSelectAction).toBe('function'); }); test('ignores event when data.xAxisField not provided', async () => { - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromRangeSelectAction(baseEvent); expect(filter).toBeUndefined(); }); @@ -119,19 +110,19 @@ describe('brushEvent', () => { test('by ignoring the event when range spans zero time', async () => { baseEvent.range = [JAN_01_2014, JAN_01_2014]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromRangeSelectAction(baseEvent); expect(filter).toBeUndefined(); }); test('by updating the timefilter', async () => { baseEvent.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromRangeSelectAction(baseEvent); expect(filter).toBeDefined(); - if (filter) { - expect(filter.range.time.gte).toBe(new Date(JAN_01_2014).toISOString()); + if (filter.length) { + expect(filter[0].range.time.gte).toBe(new Date(JAN_01_2014).toISOString()); // Set to a baseline timezone for comparison. - expect(filter.range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString()); + expect(filter[0].range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString()); } }); }); @@ -154,14 +145,14 @@ describe('brushEvent', () => { const rangeBegin = JAN_01_2014; const rangeEnd = rangeBegin + DAY_IN_MS; baseEvent.range = [rangeBegin, rangeEnd]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromRangeSelectAction(baseEvent); expect(filter).toBeDefined(); - if (filter) { - expect(filter.range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString()); - expect(filter.range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString()); - expect(filter.range.anotherTimeField).toHaveProperty( + if (filter.length) { + expect(filter[0].range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString()); + expect(filter[0].range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString()); + expect(filter[0].range.anotherTimeField).toHaveProperty( 'format', 'strict_date_optional_time' ); @@ -184,20 +175,20 @@ describe('brushEvent', () => { test('by ignoring the event when range does not span at least 2 values', async () => { baseEvent.range = [1]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromRangeSelectAction(baseEvent); expect(filter).toBeUndefined(); }); test('by creating a new filter', async () => { baseEvent.range = [1, 2, 3, 4]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromRangeSelectAction(baseEvent); expect(filter).toBeDefined(); - if (filter) { - expect(filter.range.numberField.gte).toBe(1); - expect(filter.range.numberField.lt).toBe(4); - expect(filter.range.numberField).not.toHaveProperty('format'); + if (filter.length) { + expect(filter[0].range.numberField.gte).toBe(1); + expect(filter[0].range.numberField.lt).toBe(4); + expect(filter[0].range.numberField).not.toHaveProperty('format'); } }); }); diff --git a/src/plugins/data/public/actions/filters/brush_event.ts b/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts similarity index 75% rename from src/plugins/data/public/actions/filters/brush_event.ts rename to src/plugins/data/public/actions/filters/create_filters_from_range_select.ts index 714f005fbeb6d..3bf924dd30eab 100644 --- a/src/plugins/data/public/actions/filters/brush_event.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts @@ -17,34 +17,24 @@ * under the License. */ -import { get, last } from 'lodash'; +import { last } from 'lodash'; import moment from 'moment'; import { esFilters, IFieldType, RangeFilterParams } from '../../../public'; import { getIndexPatterns } from '../../../public/services'; import { deserializeAggConfig } from '../../search/expressions/utils'; +import { KibanaDatatable } from '../../../../expressions'; -export interface BrushEvent { - data: { - ordered: { - date: boolean; - }; - series: Array>; - }; +export interface RangeSelectEvent { + table: KibanaDatatable; + column: number; range: number[]; } -export async function onBrushEvent(event: BrushEvent) { - const isDate = get(event.data, 'ordered.date'); - const xRaw: Record = get(event.data, 'series[0].values[0].xRaw'); - - if (!xRaw) { - return; - } - - const column: Record = xRaw.table.columns[xRaw.column]; +export async function createFiltersFromRangeSelectAction(event: RangeSelectEvent) { + const column: Record = event.table.columns[event.column]; if (!column || !column.meta) { - return; + return []; } const indexPattern = await getIndexPatterns().get(column.meta.indexPatternId); @@ -55,16 +45,18 @@ export async function onBrushEvent(event: BrushEvent) { const field: IFieldType = aggConfig.params.field; if (!field || event.range.length <= 1) { - return; + return []; } const min = event.range[0]; const max = last(event.range); if (min === max) { - return; + return []; } + const isDate = field.type === 'date'; + const range: RangeFilterParams = { gte: isDate ? moment(min).toISOString() : min, lt: isDate ? moment(max).toISOString() : max, @@ -74,5 +66,5 @@ export async function onBrushEvent(event: BrushEvent) { range.format = 'strict_date_optional_time'; } - return esFilters.buildRangeFilter(field, range, indexPattern); + return esFilters.mapAndFlattenFilters([esFilters.buildRangeFilter(field, range, indexPattern)]); } diff --git a/src/plugins/data/public/actions/filters/create_filters_from_event.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts similarity index 88% rename from src/plugins/data/public/actions/filters/create_filters_from_event.test.ts rename to src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts index 1ed09002816d1..84c78a36e8e19 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_event.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts @@ -26,7 +26,7 @@ import { import { dataPluginMock } from '../../../public/mocks'; import { setIndexPatterns } from '../../../public/services'; import { mockDataServices } from '../../../public/search/aggs/test_helpers'; -import { createFiltersFromEvent, EventData } from './create_filters_from_event'; +import { createFiltersFromValueClickAction, EventData } from './create_filters_from_value_click'; const mockField = { name: 'bytes', @@ -37,7 +37,7 @@ const mockField = { format: new fieldFormats.BytesFormat({}, (() => {}) as FieldFormatsGetConfigFn), }; -describe('createFiltersFromEvent', () => { +describe('createFiltersFromValueClick', () => { let dataPoints: EventData[]; beforeEach(() => { @@ -86,7 +86,7 @@ describe('createFiltersFromEvent', () => { test('ignores event when value for rows is not provided', async () => { dataPoints[0].table.rows[0]['1-1'] = null; - const filters = await createFiltersFromEvent(dataPoints); + const filters = await createFiltersFromValueClickAction({ data: dataPoints }); expect(filters.length).toEqual(0); }); @@ -95,14 +95,14 @@ describe('createFiltersFromEvent', () => { if (dataPoints[0].table.columns[0].meta) { dataPoints[0].table.columns[0].meta.type = 'terms'; } - const filters = await createFiltersFromEvent(dataPoints); + const filters = await createFiltersFromValueClickAction({ data: dataPoints }); expect(filters.length).toEqual(1); expect(filters[0].query.match_phrase.bytes).toEqual('2048'); }); test('handles an event when aggregations type is not terms', async () => { - const filters = await createFiltersFromEvent(dataPoints); + const filters = await createFiltersFromValueClickAction({ data: dataPoints }); expect(filters.length).toEqual(1); diff --git a/src/plugins/data/public/actions/filters/create_filters_from_event.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts similarity index 94% rename from src/plugins/data/public/actions/filters/create_filters_from_event.ts rename to src/plugins/data/public/actions/filters/create_filters_from_value_click.ts index e62945a592072..1b4ea14c80ae4 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_event.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts @@ -29,6 +29,11 @@ export interface EventData { value: any; } +export interface ValueClickEvent { + data: EventData[]; + negate?: boolean; +} + /** * For terms aggregations on `__other__` buckets, this assembles a list of applicable filter * terms based on a specific cell in the tabified data. @@ -113,11 +118,11 @@ const createFilter = async (table: EventData['table'], columnIndex: number, rowI }; /** @public */ -export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: boolean) => { +export const createFiltersFromValueClickAction = async ({ data, negate }: ValueClickEvent) => { const filters: Filter[] = []; await Promise.all( - dataPoints + data .filter(point => point) .map(async val => { const { table, column, row } = val; @@ -133,5 +138,5 @@ export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: b }) ); - return filters; + return esFilters.mapAndFlattenFilters(filters); }; diff --git a/src/plugins/data/public/actions/index.ts b/src/plugins/data/public/actions/index.ts index cdb84ff13f25e..d9ea6fab047e1 100644 --- a/src/plugins/data/public/actions/index.ts +++ b/src/plugins/data/public/actions/index.ts @@ -18,6 +18,6 @@ */ export { ACTION_GLOBAL_APPLY_FILTER, createFilterAction } from './apply_filter_action'; -export { createFiltersFromEvent } from './filters/create_filters_from_event'; +export { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click'; export { selectRangeAction } from './select_range_action'; export { valueClickAction } from './value_click_action'; diff --git a/src/plugins/data/public/actions/select_range_action.ts b/src/plugins/data/public/actions/select_range_action.ts index 6e1f16a09e803..29a0a3123028b 100644 --- a/src/plugins/data/public/actions/select_range_action.ts +++ b/src/plugins/data/public/actions/select_range_action.ts @@ -23,19 +23,22 @@ import { IncompatibleActionError, ActionByType, } from '../../../../plugins/ui_actions/public'; -import { onBrushEvent } from './filters/brush_event'; +import { + createFiltersFromRangeSelectAction, + RangeSelectEvent, +} from './filters/create_filters_from_range_select'; import { FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_SELECT_RANGE = 'ACTION_SELECT_RANGE'; export interface SelectRangeActionContext { - data: any; + data: RangeSelectEvent; timeFieldName: string; } async function isCompatible(context: SelectRangeActionContext) { try { - return Boolean(await onBrushEvent(context.data)); + return Boolean(await createFiltersFromRangeSelectAction(context.data)); } catch { return false; } @@ -59,13 +62,7 @@ export function selectRangeAction( throw new IncompatibleActionError(); } - const filter = await onBrushEvent(data); - - if (!filter) { - return; - } - - const selectedFilters = esFilters.mapAndFlattenFilters([filter]); + const selectedFilters = await createFiltersFromRangeSelectAction(data); if (timeFieldName) { const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( diff --git a/src/plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts index 01c32e27da07d..ce35b9aaa2820 100644 --- a/src/plugins/data/public/actions/value_click_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -26,21 +26,22 @@ import { } from '../../../../plugins/ui_actions/public'; import { getOverlays, getIndexPatterns } from '../services'; import { applyFiltersPopover } from '../ui/apply_filters'; -import { createFiltersFromEvent } from './filters/create_filters_from_event'; +import { + createFiltersFromValueClickAction, + ValueClickEvent, +} from './filters/create_filters_from_value_click'; import { Filter, FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_VALUE_CLICK = 'ACTION_VALUE_CLICK'; export interface ValueClickActionContext { - data: any; + data: ValueClickEvent; timeFieldName: string; } async function isCompatible(context: ValueClickActionContext) { try { - const filters: Filter[] = - (await createFiltersFromEvent(context.data.data || [context.data], context.data.negate)) || - []; + const filters: Filter[] = await createFiltersFromValueClickAction(context.data); return filters.length > 0; } catch { return false; @@ -65,12 +66,11 @@ export function valueClickAction( throw new IncompatibleActionError(); } - const filters: Filter[] = - (await createFiltersFromEvent(data.data || [data], data.negate)) || []; + const filters: Filter[] = await createFiltersFromValueClickAction(data); - let selectedFilters: Filter[] = esFilters.mapAndFlattenFilters(filters); + let selectedFilters = filters; - if (selectedFilters.length > 1) { + if (filters.length > 1) { const indexPatterns = await Promise.all( filters.map(filter => { return getIndexPatterns().get(filter.meta.index!); diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 2d43cae79ac98..0f708cc589d83 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -45,7 +45,7 @@ const createStartContract = (): Start => { const queryStartMock = queryServiceMock.createStartContract(); return { actions: { - createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']), + createFiltersFromValueClickAction: jest.fn().mockResolvedValue(['yes']), }, autocomplete: autocompleteMock, search: searchStartMock, diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 2ebe377b3b32f..f860960c7f5a7 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -58,7 +58,11 @@ import { VALUE_CLICK_TRIGGER, APPLY_FILTER_TRIGGER, } from '../../ui_actions/public'; -import { ACTION_GLOBAL_APPLY_FILTER, createFilterAction, createFiltersFromEvent } from './actions'; +import { + ACTION_GLOBAL_APPLY_FILTER, + createFilterAction, + createFiltersFromValueClickAction, +} from './actions'; import { ApplyGlobalFilterActionContext } from './actions/apply_filter_action'; import { selectRangeAction, @@ -162,7 +166,7 @@ export class DataPublicPlugin implements Plugin Date: Mon, 13 Apr 2020 23:48:43 -0700 Subject: [PATCH 41/81] updating --- .../create_filters_from_range_select.test.ts | 59 +++++++++---------- src/plugins/data/public/actions/index.ts | 1 + src/plugins/data/public/plugin.ts | 2 + .../visualizations/public/expressions/vis.ts | 5 +- 4 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts index b0b9ac0669ed2..0d53256772bd5 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts @@ -24,7 +24,7 @@ import { RangeSelectEvent, } from './create_filters_from_range_select'; -import { IndexPatternsContract } from '../../../public'; +import { IndexPatternsContract, RangeFilter } from '../../../public'; import { dataPluginMock } from '../../../public/mocks'; import { setIndexPatterns } from '../../../public/services'; import { mockDataServices } from '../../../public/search/aggs/test_helpers'; @@ -34,18 +34,21 @@ describe('brushEvent', () => { const JAN_01_2014 = 1388559600000; let baseEvent: RangeSelectEvent; + const indexPattern = { + id: 'indexPatternId', + timeFieldName: 'time', + fields: { + getByName: () => undefined, + filter: () => [], + }, + }; + const aggConfigs = [ { params: { field: {}, }, - getIndexPattern: () => ({ - timeFieldName: 'time', - fields: { - getByName: () => undefined, - filter: () => [], - }, - }), + getIndexPattern: () => indexPattern, }, ]; @@ -53,14 +56,7 @@ describe('brushEvent', () => { mockDataServices(); setIndexPatterns(({ ...dataPluginMock.createStartContract().indexPatterns, - get: async () => ({ - id: 'indexPatternId', - timeFieldName: 'time', - fields: { - getByName: () => undefined, - filter: () => [], - }, - }), + get: async () => indexPattern, } as unknown) as IndexPatternsContract); baseEvent = { @@ -90,7 +86,7 @@ describe('brushEvent', () => { test('ignores event when data.xAxisField not provided', async () => { const filter = await createFiltersFromRangeSelectAction(baseEvent); - expect(filter).toBeUndefined(); + expect(filter).toEqual([]); }); describe('handles an event when the x-axis field is a date field', () => { @@ -100,18 +96,17 @@ describe('brushEvent', () => { name: 'time', type: 'date', }; - baseEvent.data.ordered = { date: true }; }); afterAll(() => { baseEvent.range = []; - baseEvent.data.ordered = { date: false }; + aggConfigs[0].params.field = {}; }); test('by ignoring the event when range spans zero time', async () => { baseEvent.range = [JAN_01_2014, JAN_01_2014]; const filter = await createFiltersFromRangeSelectAction(baseEvent); - expect(filter).toBeUndefined(); + expect(filter).toEqual([]); }); test('by updating the timefilter', async () => { @@ -120,9 +115,10 @@ describe('brushEvent', () => { expect(filter).toBeDefined(); if (filter.length) { - expect(filter[0].range.time.gte).toBe(new Date(JAN_01_2014).toISOString()); + const rangeFilter = filter[0] as RangeFilter; + expect(rangeFilter.range.time.gte).toBe(new Date(JAN_01_2014).toISOString()); // Set to a baseline timezone for comparison. - expect(filter[0].range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString()); + expect(rangeFilter.range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString()); } }); }); @@ -133,12 +129,11 @@ describe('brushEvent', () => { name: 'anotherTimeField', type: 'date', }; - baseEvent.data.ordered = { date: true }; }); afterAll(() => { baseEvent.range = []; - baseEvent.data.ordered = { date: false }; + aggConfigs[0].params.field = {}; }); test('creates a new range filter', async () => { @@ -150,9 +145,10 @@ describe('brushEvent', () => { expect(filter).toBeDefined(); if (filter.length) { - expect(filter[0].range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString()); - expect(filter[0].range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString()); - expect(filter[0].range.anotherTimeField).toHaveProperty( + const rangeFilter = filter[0] as RangeFilter; + expect(rangeFilter.range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString()); + expect(rangeFilter.range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString()); + expect(rangeFilter.range.anotherTimeField).toHaveProperty( 'format', 'strict_date_optional_time' ); @@ -176,7 +172,7 @@ describe('brushEvent', () => { test('by ignoring the event when range does not span at least 2 values', async () => { baseEvent.range = [1]; const filter = await createFiltersFromRangeSelectAction(baseEvent); - expect(filter).toBeUndefined(); + expect(filter).toEqual([]); }); test('by creating a new filter', async () => { @@ -186,9 +182,10 @@ describe('brushEvent', () => { expect(filter).toBeDefined(); if (filter.length) { - expect(filter[0].range.numberField.gte).toBe(1); - expect(filter[0].range.numberField.lt).toBe(4); - expect(filter[0].range.numberField).not.toHaveProperty('format'); + const rangeFilter = filter[0] as RangeFilter; + expect(rangeFilter.range.numberField.gte).toBe(1); + expect(rangeFilter.range.numberField.lt).toBe(4); + expect(rangeFilter.range.numberField).not.toHaveProperty('format'); } }); }); diff --git a/src/plugins/data/public/actions/index.ts b/src/plugins/data/public/actions/index.ts index d9ea6fab047e1..ef9014aafe82d 100644 --- a/src/plugins/data/public/actions/index.ts +++ b/src/plugins/data/public/actions/index.ts @@ -19,5 +19,6 @@ export { ACTION_GLOBAL_APPLY_FILTER, createFilterAction } from './apply_filter_action'; export { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click'; +export { createFiltersFromRangeSelectAction } from './filters/create_filters_from_range_select'; export { selectRangeAction } from './select_range_action'; export { valueClickAction } from './value_click_action'; diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index f860960c7f5a7..a9e6669dd4eac 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -62,6 +62,7 @@ import { ACTION_GLOBAL_APPLY_FILTER, createFilterAction, createFiltersFromValueClickAction, + createFiltersFromRangeSelectAction, } from './actions'; import { ApplyGlobalFilterActionContext } from './actions/apply_filter_action'; import { @@ -167,6 +168,7 @@ export class DataPublicPlugin implements Plugin { if (!this.eventsSubject) return; - this.eventsSubject.next({ name: 'filterBucket', data }); + this.eventsSubject.next({ + name: 'filterBucket', + data: data.data ? data : { negate: false, data: [data] }, + }); }, brush: (data: any) => { if (!this.eventsSubject) return; From 66c9906d2852078530b1c5e37774ed22652059d3 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Tue, 14 Apr 2020 01:36:49 -0700 Subject: [PATCH 42/81] updating docs --- ...gin-plugins-data-public.datapublicpluginstart.actions.md | 2 +- ...bana-plugin-plugins-data-public.datapublicpluginstart.md | 2 +- .../kibana-plugin-plugins-data-public.fieldformats.md | 2 +- .../kibana-plugin-plugins-data-server.fieldformats.md | 2 +- src/plugins/data/public/public.api.md | 6 +++--- src/plugins/data/server/server.api.md | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md index 3e966caa30799..66404d7747343 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md @@ -8,6 +8,6 @@ ```typescript actions: { - createFiltersFromEvent: typeof createFiltersFromEvent; + createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction; }; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md index a623e91388fd6..8522c626c59a1 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md @@ -14,7 +14,7 @@ export interface DataPublicPluginStart | Property | Type | Description | | --- | --- | --- | -| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromEvent: typeof createFiltersFromEvent;
} | | +| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;
} | | | [autocomplete](./kibana-plugin-plugins-data-public.datapublicpluginstart.autocomplete.md) | AutocompleteStart | | | [fieldFormats](./kibana-plugin-plugins-data-public.datapublicpluginstart.fieldformats.md) | FieldFormatsStart | | | [indexPatterns](./kibana-plugin-plugins-data-public.datapublicpluginstart.indexpatterns.md) | IndexPatternsContract | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md index 244633c3c4c9e..d39871b99f744 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md @@ -10,7 +10,7 @@ fieldFormats: { FieldFormat: typeof FieldFormat; FieldFormatsRegistry: typeof FieldFormatsRegistry; - serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serialize: (agg: import("./search").AggConfig) => import("../../expressions").SerializedFieldFormat; DEFAULT_CONVERTER_COLOR: { range: string; regex: string; diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md index 2b986aee508e2..11f18a195d271 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md @@ -10,7 +10,7 @@ fieldFormats: { FieldFormatsRegistry: typeof FieldFormatsRegistry; FieldFormat: typeof FieldFormat; - serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions").SerializedFieldFormat; BoolFormat: typeof BoolFormat; BytesFormat: typeof BytesFormat; ColorFormat: typeof ColorFormat; diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index cef82b27b1b5b..098548948d73b 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -248,7 +248,7 @@ export interface DataPublicPluginSetup { export interface DataPublicPluginStart { // (undocumented) actions: { - createFiltersFromEvent: typeof createFiltersFromEvent; + createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction; }; // Warning: (ae-forgotten-export) The symbol "AutocompleteStart" needs to be exported by the entry point index.d.ts // @@ -484,7 +484,7 @@ export type FieldFormatId = FIELD_FORMAT_IDS | string; export const fieldFormats: { FieldFormat: typeof FieldFormat; FieldFormatsRegistry: typeof FieldFormatsRegistry; - serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serialize: (agg: import("./search").AggConfig) => import("../../expressions").SerializedFieldFormat; DEFAULT_CONVERTER_COLOR: { range: string; regex: string; @@ -1906,7 +1906,7 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/public/index.ts:413:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromEvent" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:60:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index c41023eab6d20..f8a9a7792c492 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -283,7 +283,7 @@ export interface FieldFormatConfig { export const fieldFormats: { FieldFormatsRegistry: typeof FieldFormatsRegistry; FieldFormat: typeof FieldFormat; - serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions").SerializedFieldFormat; BoolFormat: typeof BoolFormat; BytesFormat: typeof BytesFormat; ColorFormat: typeof ColorFormat; From 451f2a8e3c6c973df51eb048e33584bd05624479 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 14 Apr 2020 13:44:05 +0200 Subject: [PATCH 43/81] improve --- .../public/components/README.md | 5 - .../collect_config_container.tsx} | 124 +++++++++++------- .../dashboard_drilldown_config.story.tsx | 2 +- .../dashboard_drilldown_config.tsx | 0 .../dashboard_drilldown_config/i18n.ts | 0 .../dashboard_drilldown_config/index.ts | 0 .../components/i18n.ts | 16 +++ .../components/index.ts | 2 +- .../drilldown.tsx | 23 +++- .../dashboard_to_dashboard_drilldown/i18n.ts | 9 -- .../dashboard_to_dashboard_drilldown/types.ts | 17 +-- 11 files changed, 109 insertions(+), 89 deletions(-) delete mode 100644 x-pack/plugins/dashboard_enhanced/public/components/README.md rename x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/{collect_config.tsx => components/collect_config_container.tsx} (53%) rename x-pack/plugins/dashboard_enhanced/public/{ => services/drilldowns/dashboard_to_dashboard_drilldown}/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx (96%) rename x-pack/plugins/dashboard_enhanced/public/{ => services/drilldowns/dashboard_to_dashboard_drilldown}/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx (100%) rename x-pack/plugins/dashboard_enhanced/public/{ => services/drilldowns/dashboard_to_dashboard_drilldown}/components/dashboard_drilldown_config/i18n.ts (100%) rename x-pack/plugins/dashboard_enhanced/public/{ => services/drilldowns/dashboard_to_dashboard_drilldown}/components/dashboard_drilldown_config/index.ts (100%) create mode 100644 x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/i18n.ts rename x-pack/plugins/dashboard_enhanced/public/{ => services/drilldowns/dashboard_to_dashboard_drilldown}/components/index.ts (77%) diff --git a/x-pack/plugins/dashboard_enhanced/public/components/README.md b/x-pack/plugins/dashboard_enhanced/public/components/README.md deleted file mode 100644 index 8081f8a2451cf..0000000000000 --- a/x-pack/plugins/dashboard_enhanced/public/components/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Presentation React components - -Here we keep reusable *presentation* (aka *dumb*) React components—these -components should not be connected to state and ideally should not know anything -about Kibana. diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx similarity index 53% rename from x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx rename to x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx index 94ca10f62a757..978bf6d8935d4 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/collect_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx @@ -7,10 +7,14 @@ import React from 'react'; import { EuiComboBoxOptionOption } from '@elastic/eui'; import { debounce, findIndex } from 'lodash'; -import { CollectConfigProps } from './types'; -import { DashboardDrilldownConfig } from '../../../components/dashboard_drilldown_config'; -import { SimpleSavedObject } from '../../../../../../../src/core/public'; +import { CoreStart, SimpleSavedObject } from '../../../../../../../../src/core/public'; +import { DashboardDrilldownConfig } from './dashboard_drilldown_config'; import { txtDestinationDashboardNotFound } from './i18n'; +import { UiActionsCollectConfigProps } from '../../../../../../../../src/plugins/ui_actions/public'; +import { SharePluginStart } from '../../../../../../../../src/plugins/share/public'; +import { DrilldownFactoryContext } from '../../../../../../drilldowns/public'; +import { Config } from '../types'; +import { IEmbeddable } from '../../../../../../../../src/plugins/embeddable/public'; const mergeDashboards = ( dashboards: Array>, @@ -32,6 +36,17 @@ const dashboardSavedObjectToMenuItem = ( label: savedObject.attributes.title, }); +interface CollectConfigProps extends UiActionsCollectConfigProps { + deps: { + getSavedObjectsClient: () => Promise; + getNavigateToApp: () => Promise; + getGetUrlGenerator: () => Promise; + }; + context: DrilldownFactoryContext<{ + embeddable: IEmbeddable; + }>; +} + interface CollectConfigContainerState { dashboards: Array>; searchString?: string; @@ -67,53 +82,6 @@ export class CollectConfigContainer extends React.Component< this.isMounted = false; } - loadSelectedDashboard() { - const { config } = this.props; - this.props.deps.getSavedObjectsClient().then(savedObjectsClient => { - if (config.dashboardId) { - savedObjectsClient - .get<{ title: string }>('dashboard', config.dashboardId) - .then(dashboard => { - if (!this.isMounted) return; - if (dashboard.error?.statusCode === 404) { - this.setState({ - error: txtDestinationDashboardNotFound(config.dashboardId), - }); - this.props.onConfig({ ...config, dashboardId: undefined }); - return; - } - if (dashboard.error) return; - - this.setState({ selectedDashboard: dashboardSavedObjectToMenuItem(dashboard) }); - }); - } - }); - } - - private readonly debouncedLoadDashboards: (searchString?: string) => void; - loadDashboards(searchString?: string) { - const currentDashboardId = this.props.context.placeContext.embeddable?.parent?.id; - this.setState({ searchString, isLoading: true }); - this.props.deps.getSavedObjectsClient().then(savedObjectsClient => { - savedObjectsClient - .find<{ title: string }>({ - type: 'dashboard', - search: searchString ? `${searchString}*` : undefined, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', - perPage: 100, - }) - .then(({ savedObjects }) => { - if (!this.isMounted) return; - if (searchString !== this.state.searchString) return; - const dashboardList = savedObjects - .map(dashboardSavedObjectToMenuItem) - .filter(({ value }) => !currentDashboardId || value !== currentDashboardId); - this.setState({ dashboards: dashboardList, isLoading: false }); - }); - }); - } - render() { const { config, onConfig } = this.props; const { dashboards, selectedDashboard, isLoading, error } = this.state; @@ -148,4 +116,60 @@ export class CollectConfigContainer extends React.Component< /> ); } + + private async loadSelectedDashboard() { + const { config } = this.props; + if (!config.dashboardId) return; + const savedObjectsClient = await this.props.deps.getSavedObjectsClient(); + const savedObject = await savedObjectsClient.get<{ title: string }>( + 'dashboard', + config.dashboardId + ); + + if (!this.isMounted) return; // bailout if response is no longer needed + + // handle case when destination dashboard is no longer exist + if (savedObject.error?.statusCode === 404) { + this.setState({ + error: txtDestinationDashboardNotFound(config.dashboardId), + }); + this.props.onConfig({ ...config, dashboardId: undefined }); + return; + } + + // any other error + if (savedObject.error) { + this.setState({ + error: savedObject.error.message, + }); + this.props.onConfig({ ...config, dashboardId: undefined }); + return; + } + + this.setState({ selectedDashboard: dashboardSavedObjectToMenuItem(savedObject) }); + } + + private readonly debouncedLoadDashboards: (searchString?: string) => void; + private async loadDashboards(searchString?: string) { + const currentDashboardId = this.props.context.placeContext.embeddable?.parent?.id; + this.setState({ searchString, isLoading: true }); + const savedObjectsClient = await this.props.deps.getSavedObjectsClient(); + const { savedObjects } = await savedObjectsClient.find<{ title: string }>({ + type: 'dashboard', + search: searchString ? `${searchString}*` : undefined, + searchFields: ['title^3', 'description'], + defaultSearchOperator: 'AND', + perPage: 100, + }); + + // bail out if this response is no longer needed + if (!this.isMounted) return; + if (searchString !== this.state.searchString) return; + + const dashboardList = savedObjects + .map(dashboardSavedObjectToMenuItem) + .filter(({ value }) => !currentDashboardId || value !== currentDashboardId); + + this.setState({ dashboards: dashboardList, isLoading: false }); + } } diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx similarity index 96% rename from x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx rename to x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx index 0978af654e9c4..15c0cd0c782de 100644 --- a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx @@ -8,7 +8,7 @@ import * as React from 'react'; import { storiesOf } from '@storybook/react'; -import { DashboardDrilldownConfig } from '.'; +import { DashboardDrilldownConfig } from './dashboard_drilldown_config'; export const dashboards = [ { value: 'dashboard1', label: 'Dashboard 1' }, diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx similarity index 100% rename from x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx rename to x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/i18n.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/i18n.ts similarity index 100% rename from x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/i18n.ts rename to x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/i18n.ts diff --git a/x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/index.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/index.ts similarity index 100% rename from x-pack/plugins/dashboard_enhanced/public/components/dashboard_drilldown_config/index.ts rename to x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/index.ts diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/i18n.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/i18n.ts new file mode 100644 index 0000000000000..6f6f7412f6b53 --- /dev/null +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/i18n.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const txtDestinationDashboardNotFound = (dashboardId?: string) => + i18n.translate('xpack.dashboard.drilldown.errorDestinationDashboardIsMissing', { + defaultMessage: + "Destination dashboard ('{dashboardId}') no longer exists. Choose another dashboard.", + values: { + dashboardId, + }, + }); diff --git a/x-pack/plugins/dashboard_enhanced/public/components/index.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/index.ts similarity index 77% rename from x-pack/plugins/dashboard_enhanced/public/components/index.ts rename to x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/index.ts index b9a64a3cc17e6..c34290528d914 100644 --- a/x-pack/plugins/dashboard_enhanced/public/components/index.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './dashboard_drilldown_config'; +export { CollectConfigContainer } from './collect_config_container'; diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index bdb3986aa3f4f..e0b27d27576dc 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -9,9 +9,8 @@ import { CoreStart } from 'src/core/public'; import { reactToUiComponent } from '../../../../../../../src/plugins/kibana_react/public'; import { SharePluginStart } from '../../../../../../../src/plugins/share/public'; import { DASHBOARD_APP_URL_GENERATOR } from '../../../../../../../src/plugins/dashboard/public'; -import { PlaceContext, ActionContext, Config, CollectConfigProps } from './types'; - -import { CollectConfigContainer } from './collect_config'; +import { PlaceContext, ActionContext, Config } from './types'; +import { CollectConfigContainer } from './components'; import { DASHBOARD_TO_DASHBOARD_DRILLDOWN } from './constants'; import { DrilldownDefinition as Drilldown } from '../../../../../drilldowns/public'; import { txtGoToDashboard } from './i18n'; @@ -37,7 +36,7 @@ export class DashboardToDashboardDrilldown public readonly euiIcon = 'dashboardApp'; - private readonly ReactCollectConfig: React.FC = props => ( + private readonly ReactCollectConfig: React.FC = props => ( ); @@ -82,9 +81,19 @@ export class DashboardToDashboardDrilldown // if undefined is passed, then destination dashboard will figure out time range itself // for brush event this time range would be overwritten let timeRange = config.useCurrentDateRange ? currentTimeRange : undefined; - let filtersFromEvent = context.data.range - ? await createFiltersFromBrushEvent(context.data as any) - : await createFiltersFromValueClickEvent(context.data as any); + let filtersFromEvent = await (async () => { + // TODO: not sure what would be the best way to handle types here + // context.data is `unknown` and comes from `EmbeddableVisTriggerContext` + try { + return context.data.range + ? await createFiltersFromBrushEvent(context.data as any) + : await createFiltersFromValueClickEvent(context.data as any); + } catch (e) { + // eslint-disable-next-line no-console + console.warn('DashboardToDashboard drilldown: unable to extract filters from event', e); + return []; + } + })(); if (context.timeFieldName) { const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/i18n.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/i18n.ts index 0fbb53b464e14..98b746bafd24a 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/i18n.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/i18n.ts @@ -9,12 +9,3 @@ import { i18n } from '@kbn/i18n'; export const txtGoToDashboard = i18n.translate('xpack.dashboard.drilldown.goToDashboard', { defaultMessage: 'Go to Dashboard', }); - -export const txtDestinationDashboardNotFound = (dashboardId?: string) => - i18n.translate('xpack.dashboard.drilldown.errorDestinationDashboardIsMissing', { - defaultMessage: - "Destination dashboard ('{dashboardId}') no longer exists. Choose another dashboard.", - values: { - dashboardId, - }, - }); diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts index 39d6507e277d8..6c5e66e3dfed4 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts @@ -4,15 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CoreStart } from 'src/core/public'; -import { SharePluginStart } from 'src/plugins/share/public'; -import { DrilldownFactoryContext } from '../../../../../drilldowns/public'; import { - EmbeddableVisTriggerContext, EmbeddableContext, + EmbeddableVisTriggerContext, IEmbeddable, } from '../../../../../../../src/plugins/embeddable/public'; -import { UiActionsCollectConfigProps } from '../../../../../../../src/plugins/ui_actions/public'; export type PlaceContext = EmbeddableContext; export type ActionContext = EmbeddableVisTriggerContext; @@ -22,14 +18,3 @@ export interface Config { useCurrentFilters: boolean; useCurrentDateRange: boolean; } - -export interface CollectConfigProps extends UiActionsCollectConfigProps { - deps: { - getSavedObjectsClient: () => Promise; - getNavigateToApp: () => Promise; - getGetUrlGenerator: () => Promise; - }; - context: DrilldownFactoryContext<{ - embeddable: IEmbeddable; - }>; -} From 4cd3c23b0bf09c3faf9901b8d54f1bb8c8e19af0 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 14 Apr 2020 14:21:28 +0200 Subject: [PATCH 44/81] fix storybook --- x-pack/plugins/dashboard_enhanced/scripts/storybook.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/dashboard_enhanced/scripts/storybook.js b/x-pack/plugins/dashboard_enhanced/scripts/storybook.js index f2cbe4135f4cb..5d95c56c31e3b 100644 --- a/x-pack/plugins/dashboard_enhanced/scripts/storybook.js +++ b/x-pack/plugins/dashboard_enhanced/scripts/storybook.js @@ -9,5 +9,5 @@ import { join } from 'path'; // eslint-disable-next-line require('@kbn/storybook').runStorybookCli({ name: 'dashboard_enhanced', - storyGlobs: [join(__dirname, '..', 'public', 'components', '**', '*.story.tsx')], + storyGlobs: [join(__dirname, '..', 'public', '**', '*.story.tsx')], }); From 08597a1a8e00a4d18226b3c3a06856bc1d514474 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 16 Apr 2020 12:22:12 +0200 Subject: [PATCH 45/81] post merge fixes --- test/functional/page_objects/dashboard_page.ts | 4 ++-- .../drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/functional/page_objects/dashboard_page.ts b/test/functional/page_objects/dashboard_page.ts index 914372e9001ef..224adb295b2b2 100644 --- a/test/functional/page_objects/dashboard_page.ts +++ b/test/functional/page_objects/dashboard_page.ts @@ -515,8 +515,8 @@ export function DashboardPageProvider({ getService, getPageObjects }: FtrProvide log.debug('getPanelDrilldownCount'); const panel = (await this.getDashboardPanels())[panelIndex]; try { - const count = await panel.findByCssSelector( - '[data-test-subj="embeddablePanelDrilldownCount"]' + const count = await panel.findByTestSubject( + 'embeddablePanelNotification-ACTION_PANEL_NOTIFICATIONS' ); return Number.parseInt(await count.getVisibleText(), 10); } catch (e) { diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index e0b27d27576dc..72586bf0fa93b 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -44,8 +44,8 @@ export class DashboardToDashboardDrilldown public readonly createConfig = () => ({ dashboardId: '', - useCurrentFilters: false, - useCurrentDateRange: false, + useCurrentFilters: true, + useCurrentDateRange: true, }); public readonly isConfigValid = (config: Config): config is Config => { From bc6d22fd84f4c2afd8779e0fa5f2fa7a763adba2 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 16 Apr 2020 13:01:41 +0200 Subject: [PATCH 46/81] fix payload emitted in brush event --- .../public/vislib/lib/handler.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/lib/handler.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/lib/handler.js index ecf67ee3e017c..f33ce0395af1f 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/lib/handler.js +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/lib/handler.js @@ -83,10 +83,21 @@ export class Handler { // memoize so that the same function is returned every time, // allowing us to remove/re-add the same function - this.getProxyHandler = _.memoize(function(event) { + this.getProxyHandler = _.memoize(function(eventType) { const self = this; - return function(e) { - self.vis.emit(event, e); + return function(eventPayload) { + switch (eventType) { + case 'brush': + const xRaw = _.get(eventPayload.data, 'series[0].values[0].xRaw'); + if (!xRaw) return; // not sure if this is possible? + return self.vis.emit(eventType, { + table: xRaw.table, + range: eventPayload.range, + column: xRaw.column, + }); + case 'click': + return self.vis.emit(eventType, eventPayload); + } }; }); From ede5e98d34876d029f4a52e1db94079eab64f9bc Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 16 Apr 2020 13:29:52 +0200 Subject: [PATCH 47/81] properly export createRange action --- ...lugin-plugins-data-public.datapublicpluginstart.actions.md | 1 + ...kibana-plugin-plugins-data-public.datapublicpluginstart.md | 2 +- src/legacy/core_plugins/vis_type_vislib/public/plugin.ts | 4 +--- src/legacy/ui/public/new_platform/new_platform.karma_mock.js | 1 + src/plugins/data/public/mocks.ts | 1 + src/plugins/data/public/public.api.md | 4 +++- src/plugins/data/public/types.ts | 3 ++- 7 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md index 66404d7747343..25ce6eaa688f8 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md @@ -9,5 +9,6 @@ ```typescript actions: { createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction; + createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction; }; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md index 8522c626c59a1..4f43f10ce089e 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md @@ -14,7 +14,7 @@ export interface DataPublicPluginStart | Property | Type | Description | | --- | --- | --- | -| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;
} | | +| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;
createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction;
} | | | [autocomplete](./kibana-plugin-plugins-data-public.datapublicpluginstart.autocomplete.md) | AutocompleteStart | | | [fieldFormats](./kibana-plugin-plugins-data-public.datapublicpluginstart.fieldformats.md) | FieldFormatsStart | | | [indexPatterns](./kibana-plugin-plugins-data-public.datapublicpluginstart.indexpatterns.md) | IndexPatternsContract | | diff --git a/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts b/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts index 0c771fb0f977b..4fbf891e15d8e 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts @@ -111,8 +111,6 @@ export class VisTypeVislibPlugin implements Plugin { public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) { setFormatService(data.fieldFormats); - setDataActions({ - createFiltersFromValueClickAction: data.actions.createFiltersFromValueClickAction, - }); + setDataActions(data.actions); } } diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index 5097062f64a61..336f0624f5bde 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -376,6 +376,7 @@ export const npStart = { data: { actions: { createFiltersFromValueClickAction: Promise.resolve(['yes']), + createFiltersFromRangeSelectAction: sinon.fake(), }, autocomplete: { getProvider: sinon.fake(), diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 0f708cc589d83..1f604b9eb6baa 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -46,6 +46,7 @@ const createStartContract = (): Start => { return { actions: { createFiltersFromValueClickAction: jest.fn().mockResolvedValue(['yes']), + createFiltersFromRangeSelectAction: jest.fn(), }, autocomplete: autocompleteMock, search: searchStartMock, diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 098548948d73b..345963a068c9e 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -249,6 +249,7 @@ export interface DataPublicPluginStart { // (undocumented) actions: { createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction; + createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction; }; // Warning: (ae-forgotten-export) The symbol "AutocompleteStart" needs to be exported by the entry point index.d.ts // @@ -1907,7 +1908,8 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:60:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:53:5 - (ae-forgotten-export) The symbol "createFiltersFromRangeSelectAction" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:61:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index e572e8015aa2e..5414de16be310 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -24,7 +24,7 @@ import { ExpressionsSetup } from 'src/plugins/expressions/public'; import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public'; import { AutocompleteSetup, AutocompleteStart } from './autocomplete'; import { FieldFormatsSetup, FieldFormatsStart } from './field_formats'; -import { createFiltersFromValueClickAction } from './actions'; +import { createFiltersFromRangeSelectAction, createFiltersFromValueClickAction } from './actions'; import { ISearchSetup, ISearchStart } from './search'; import { QuerySetup, QueryStart } from './query'; import { IndexPatternSelectProps } from './ui/index_pattern_select'; @@ -50,6 +50,7 @@ export interface DataPublicPluginSetup { export interface DataPublicPluginStart { actions: { createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction; + createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction; }; autocomplete: AutocompleteStart; indexPatterns: IndexPatternsContract; From c2aed7a744f6fedd0cd22550a0c6744180fbbc08 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 16 Apr 2020 14:28:03 +0200 Subject: [PATCH 48/81] improve tests --- .../apps/dashboard/drilldowns/dashboard_drilldowns.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts b/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts index 1121921c7d315..0396ec9bc8b79 100644 --- a/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts +++ b/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts @@ -136,15 +136,15 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { { location: areaChart, offset: { - x: 150, - y: 100, + x: -100, + y: 0, }, }, { location: areaChart, offset: { - x: 200, - y: 100, + x: 100, + y: 0, }, } ); From 84f653b7de20f9b686b1a8be86044b674128753a Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 16 Apr 2020 15:48:17 +0200 Subject: [PATCH 49/81] add test --- .../dashboard_to_dashboard_drilldown/drilldown.test.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx index 48a483589c416..2dc7075e57e9f 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx @@ -51,6 +51,13 @@ test('config component exist', () => { expect(drilldown.CollectConfig).toEqual(expect.any(Function)); }); +test('initial config: switches are ON', () => { + const drilldown = new DashboardToDashboardDrilldown({} as any); + const { useCurrentDateRange, useCurrentFilters } = drilldown.createConfig(); + expect(useCurrentDateRange).toBe(true); + expect(useCurrentFilters).toBe(true); +}); + describe('.execute()', () => { /** * A convenience test setup helper From ba458c7dd33a8442948b02ca27663e5fa25186eb Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 16 Apr 2020 16:40:32 +0200 Subject: [PATCH 50/81] post merge fixes --- src/plugins/data/public/plugin.ts | 9 +- src/plugins/data/public/public.api.md | 98 ++++++++++--------- .../public/lib/triggers/triggers.ts | 13 ++- .../drilldown.test.tsx | 4 +- .../drilldown.tsx | 14 +-- 5 files changed, 75 insertions(+), 63 deletions(-) diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index ccf94171235fe..336edfb993c57 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -122,12 +122,12 @@ export class DataPublicPlugin implements Plugin boolean; changeTimeFilter: typeof changeTimeFilter; + convertRangeFilterToTimeRangeString: typeof convertRangeFilterToTimeRangeString; mapAndFlattenFilters: (filters: import("../common").Filter[]) => import("../common").Filter[]; extractTimeFilter: typeof extractTimeFilter; }; @@ -1857,54 +1858,55 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/common/es_query/filters/match_all_filter.ts:28:3 - (ae-forgotten-export) The symbol "MatchAllFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrase_filter.ts:33:3 - (ae-forgotten-export) The symbol "PhraseFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrases_filter.ts:31:3 - (ae-forgotten-export) The symbol "PhrasesFilterMeta" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "FilterLabel" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "generateFilters" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:391:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:410:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:413:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FilterLabel" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "generateFilters" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "convertRangeFilterToTimeRangeString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:385:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:385:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:385:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:385:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:391:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:393:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:403:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:404:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:407:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:415:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index 50bfa270a51a2..68ef66db539e6 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -24,8 +24,8 @@ export interface EmbeddableContext { embeddable: IEmbeddable; } -export interface EmbeddableVisTriggerContext { - embeddable?: IEmbeddable; +export interface EmbeddableVisTriggerContext { + embeddable?: T; timeFieldName?: string; data: unknown; } @@ -41,5 +41,12 @@ export const PANEL_BADGE_TRIGGER = 'PANEL_BADGE_TRIGGER'; export const panelBadgeTrigger: Trigger<'PANEL_BADGE_TRIGGER'> = { id: PANEL_BADGE_TRIGGER, title: 'Panel badges', - description: 'Actions appear in title bar when an embeddable loads in a panel', + description: 'Actions appear in title bar when an embeddable loads in a panel.', +}; + +export const PANEL_NOTIFICATION_TRIGGER = 'PANEL_NOTIFICATION_TRIGGER'; +export const panelNotificationTrigger: Trigger<'PANEL_NOTIFICATION_TRIGGER'> = { + id: PANEL_NOTIFICATION_TRIGGER, + title: 'Panel notifications', + description: 'Actions appear in top-right corner of a panel.', }; diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx index 2dc7075e57e9f..6d951c6f0c44a 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx @@ -89,10 +89,10 @@ describe('.execute()', () => { getSavedObjectsClient: () => Promise.resolve(savedObjectsClient), }); const selectRangeFiltersSpy = jest - .spyOn(dataPluginActions, 'createFiltersFromBrushEvent') + .spyOn(dataPluginActions, 'createFiltersFromRangeSelectAction') .mockImplementationOnce(() => Promise.resolve(filtersFromEvent)); const valueClickFiltersSpy = jest - .spyOn(dataPluginActions, 'createFiltersFromValueClickEvent') + .spyOn(dataPluginActions, 'createFiltersFromValueClickAction') .mockImplementationOnce(() => Promise.resolve(filtersFromEvent)); await drilldown.execute( diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index 72586bf0fa93b..75fea624c10a3 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -61,8 +61,8 @@ export class DashboardToDashboardDrilldown const navigateToApp = await this.params.getNavigateToApp(); const { - createFiltersFromValueClickEvent, - createFiltersFromBrushEvent, + createFiltersFromRangeSelectAction, + createFiltersFromValueClickAction, } = await this.params.getDataPluginActions(); const { timeRange: currentTimeRange, @@ -85,12 +85,12 @@ export class DashboardToDashboardDrilldown // TODO: not sure what would be the best way to handle types here // context.data is `unknown` and comes from `EmbeddableVisTriggerContext` try { - return context.data.range - ? await createFiltersFromBrushEvent(context.data as any) - : await createFiltersFromValueClickEvent(context.data as any); + return (context.data as any).range + ? await createFiltersFromValueClickAction(context.data as any) + : await createFiltersFromRangeSelectAction(context.data as any); } catch (e) { // eslint-disable-next-line no-console - console.warn('DashboardToDashboard drilldown: unable to extract filters from event', e); + console.warn("DashboardToDashboard drilldown: can't extract filters from event", e); return []; } })(); @@ -108,7 +108,7 @@ export class DashboardToDashboardDrilldown const dashboardPath = await getUrlGenerator(DASHBOARD_APP_URL_GENERATOR).createUrl({ dashboardId: config.dashboardId, - query, + query: config.useCurrentFilters ? query : undefined, timeRange, filters: [...existingFilters, ...filtersFromEvent], }); From 8a00d6504da6d7fe46f95fcf9739e71f76aad540 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 16 Apr 2020 16:47:46 +0200 Subject: [PATCH 51/81] improve --- .../dashboard_drilldown_config.test.tsx | 10 ++++++++++ .../connected_flyout_manage_drilldowns/i18n.ts | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.test.tsx diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.test.tsx new file mode 100644 index 0000000000000..df072ad693f69 --- /dev/null +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.test.tsx @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// Need to wait for https://github.com/elastic/eui/pull/3173/ +// to unit test this component +// basic interaction is covered in end-to-end tests +test.skip(''); diff --git a/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/i18n.ts b/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/i18n.ts index 9fa366445ebae..31384860786ef 100644 --- a/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/i18n.ts +++ b/x-pack/plugins/drilldowns/public/components/connected_flyout_manage_drilldowns/i18n.ts @@ -15,7 +15,7 @@ export const toastDrilldownCreated = { ), text: (drilldownName: string) => i18n.translate('xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownCreatedText', { - defaultMessage: 'You created "{drilldownName}", save dashboard to test.', + defaultMessage: 'You created "{drilldownName}". Save dashboard before testing.', values: { drilldownName, }, @@ -31,7 +31,7 @@ export const toastDrilldownEdited = { ), text: (drilldownName: string) => i18n.translate('xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownEditedText', { - defaultMessage: 'You edited "{drilldownName}", save dashboard to test.', + defaultMessage: 'You edited "{drilldownName}". Save dashboard before testing.', values: { drilldownName, }, @@ -48,7 +48,7 @@ export const toastDrilldownDeleted = { text: i18n.translate( 'xpack.drilldowns.components.flyoutDrilldownWizard.toast.drilldownDeletedText', { - defaultMessage: 'You deleted a drilldown', + defaultMessage: 'You deleted a drilldown.', } ), }; From 73a15665468dfeda034d02a9e7aef044a7dc46af Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 16 Apr 2020 16:58:04 +0200 Subject: [PATCH 52/81] fix --- .../drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index 75fea624c10a3..eab9114708047 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -86,8 +86,8 @@ export class DashboardToDashboardDrilldown // context.data is `unknown` and comes from `EmbeddableVisTriggerContext` try { return (context.data as any).range - ? await createFiltersFromValueClickAction(context.data as any) - : await createFiltersFromRangeSelectAction(context.data as any); + ? await createFiltersFromRangeSelectAction(context.data as any) + : await createFiltersFromValueClickAction(context.data as any); } catch (e) { // eslint-disable-next-line no-console console.warn("DashboardToDashboard drilldown: can't extract filters from event", e); From 952d6cd01e12f4cb1e4599274ab1e96dde3aa627 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 16 Apr 2020 17:02:24 +0200 Subject: [PATCH 53/81] improve --- .../drilldown.test.tsx | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx index 6d951c6f0c44a..8135f4c34f70f 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx @@ -148,16 +148,34 @@ describe('.execute()', () => { expect(navigatedPath).toEqual(expect.stringContaining(`dashboard/${testDashboardId}`)); }); - test('navigates with query', async () => { + test('query is removed with query if filters are disabled', async () => { const queryString = 'querystring'; const queryLanguage = 'kuery'; const { navigatedPath } = await setupTestBed( - {}, + { + useCurrentFilters: false, + }, { query: { query: queryString, language: queryLanguage }, }, - [], - true + [] + ); + + expect(navigatedPath).toEqual(expect.not.stringContaining(queryString)); + expect(navigatedPath).toEqual(expect.not.stringContaining(queryLanguage)); + }); + + test('navigates with query if filters are enabled', async () => { + const queryString = 'querystring'; + const queryLanguage = 'kuery'; + const { navigatedPath } = await setupTestBed( + { + useCurrentFilters: true, + }, + { + query: { query: queryString, language: queryLanguage }, + }, + [] ); expect(navigatedPath).toEqual(expect.stringContaining(queryString)); From d686351c7aa39e93a35b0a31fdf0c474f4785310 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 17 Apr 2020 09:28:07 +0200 Subject: [PATCH 54/81] fix build --- .../dashboard_drilldown_config.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.test.tsx index df072ad693f69..edeb7de48d9ac 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.test.tsx @@ -7,4 +7,4 @@ // Need to wait for https://github.com/elastic/eui/pull/3173/ // to unit test this component // basic interaction is covered in end-to-end tests -test.skip(''); +test.todo(''); From cac9633a9d804ea0ccddf23fe525029853961d74 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 17 Apr 2020 11:16:02 +0200 Subject: [PATCH 55/81] wip getHref support --- .../drilldown.tsx | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index eab9114708047..bd3e90090d124 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -26,7 +26,9 @@ export interface Params { export class DashboardToDashboardDrilldown implements Drilldown> { - constructor(protected readonly params: Params) {} + constructor(protected readonly params: Params) { + this.getDestinationUrl = this.getDestinationUrl.bind(this); + } public readonly id = DASHBOARD_TO_DASHBOARD_DRILLDOWN; @@ -53,12 +55,30 @@ export class DashboardToDashboardDrilldown return true; }; + public readonly getHref = async ( + config: Config, + context: ActionContext + ): Promise => { + return await this.getDestinationUrl(config, context); + }; + public readonly execute = async ( config: Config, context: ActionContext ) => { - const getUrlGenerator = await this.params.getGetUrlGenerator(); const navigateToApp = await this.params.getNavigateToApp(); + const dashboardPath = await this.getDestinationUrl(config, context); + const dashboardHash = dashboardPath.split('#')[1]; + await navigateToApp('kibana', { + path: `#${dashboardHash}`, + }); + }; + + private async getDestinationUrl( + config: Config, + context: ActionContext + ): Promise { + const getUrlGenerator = await this.params.getGetUrlGenerator(); const { createFiltersFromRangeSelectAction, @@ -106,17 +126,11 @@ export class DashboardToDashboardDrilldown } } - const dashboardPath = await getUrlGenerator(DASHBOARD_APP_URL_GENERATOR).createUrl({ + return getUrlGenerator(DASHBOARD_APP_URL_GENERATOR).createUrl({ dashboardId: config.dashboardId, query: config.useCurrentFilters ? query : undefined, timeRange, filters: [...existingFilters, ...filtersFromEvent], }); - - const dashboardHash = dashboardPath.split('#')[1]; - - await navigateToApp('kibana', { - path: `#${dashboardHash}`, - }); - }; + } } From b4837a3d16fea535c5aa4208c96cdbdf7c3b465c Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 17 Apr 2020 13:09:40 +0200 Subject: [PATCH 56/81] implement getHref() --- .../functional/page_objects/dashboard_page.ts | 13 +- .../dashboard_drilldowns_services.ts | 5 +- .../components/collect_config_container.tsx | 3 - .../drilldown.test.tsx | 123 ++++++++++-------- .../drilldown.tsx | 17 ++- .../drilldowns/dashboard_drilldowns.ts | 10 ++ .../services/dashboard/drilldowns_manage.ts | 4 +- .../dashboard/panel_drilldown_actions.ts | 14 +- 8 files changed, 117 insertions(+), 72 deletions(-) diff --git a/test/functional/page_objects/dashboard_page.ts b/test/functional/page_objects/dashboard_page.ts index 224adb295b2b2..ef19d24391fe3 100644 --- a/test/functional/page_objects/dashboard_page.ts +++ b/test/functional/page_objects/dashboard_page.ts @@ -104,16 +104,21 @@ export function DashboardPageProvider({ getService, getPageObjects }: FtrProvide public async getDashboardIdFromCurrentUrl() { const currentUrl = await browser.getCurrentUrl(); - const urlSubstring = 'kibana#/dashboard/'; - const startOfIdIndex = currentUrl.indexOf(urlSubstring) + urlSubstring.length; - const endIndex = currentUrl.indexOf('?'); - const id = currentUrl.substring(startOfIdIndex, endIndex < 0 ? currentUrl.length : endIndex); + const id = this.getDashboardIdFromUrl(currentUrl); log.debug(`Dashboard id extracted from ${currentUrl} is ${id}`); return id; } + public getDashboardIdFromUrl(url: string) { + const urlSubstring = 'kibana#/dashboard/'; + const startOfIdIndex = url.indexOf(urlSubstring) + urlSubstring.length; + const endIndex = url.indexOf('?'); + const id = url.substring(startOfIdIndex, endIndex < 0 ? url.length : endIndex); + return id; + } + /** * Returns true if already on the dashboard landing page (that page doesn't have a link to itself). * @returns {Promise} diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts index d807eb433b14e..2ed06796d9beb 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts @@ -44,8 +44,7 @@ export class DashboardDrilldownsService { const drilldowns = async () => (await core.getStartServices())[1].drilldowns; const getSavedObjectsClient = async () => (await core.getStartServices())[0].savedObjects.client; - const getNavigateToApp = async () => - (await core.getStartServices())[0].application.navigateToApp; + const getApplicationService = async () => (await core.getStartServices())[0].application; const getGetUrlGenerator = async () => (await core.getStartServices())[1].share.urlGenerators.getUrlGenerator; @@ -61,7 +60,7 @@ export class DashboardDrilldownsService { const dashboardToDashboardDrilldown = new DashboardToDashboardDrilldown({ getSavedObjectsClient, getGetUrlGenerator, - getNavigateToApp, + getApplicationService, getDataPluginActions, }); plugins.drilldowns.registerDrilldown(dashboardToDashboardDrilldown); diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx index 978bf6d8935d4..72544163e9e6a 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx @@ -11,7 +11,6 @@ import { CoreStart, SimpleSavedObject } from '../../../../../../../../src/core/p import { DashboardDrilldownConfig } from './dashboard_drilldown_config'; import { txtDestinationDashboardNotFound } from './i18n'; import { UiActionsCollectConfigProps } from '../../../../../../../../src/plugins/ui_actions/public'; -import { SharePluginStart } from '../../../../../../../../src/plugins/share/public'; import { DrilldownFactoryContext } from '../../../../../../drilldowns/public'; import { Config } from '../types'; import { IEmbeddable } from '../../../../../../../../src/plugins/embeddable/public'; @@ -39,8 +38,6 @@ const dashboardSavedObjectToMenuItem = ( interface CollectConfigProps extends UiActionsCollectConfigProps { deps: { getSavedObjectsClient: () => Promise; - getNavigateToApp: () => Promise; - getGetUrlGenerator: () => Promise; }; context: DrilldownFactoryContext<{ embeddable: IEmbeddable; diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx index 8135f4c34f70f..561eb5145e95d 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx @@ -58,7 +58,12 @@ test('initial config: switches are ON', () => { expect(useCurrentFilters).toBe(true); }); -describe('.execute()', () => { +test('getHref is defined', () => { + const drilldown = new DashboardToDashboardDrilldown({} as any); + expect(drilldown.getHref).toBeDefined(); +}); + +describe('.execute() & getHref', () => { /** * A convenience test setup helper * Beware: `dataPluginMock.createStartContract().actions` and extracting filters from event is mocked! @@ -73,11 +78,16 @@ describe('.execute()', () => { useRangeEvent = false ) { const navigateToApp = jest.fn(); + const getUrlForApp = jest.fn((app, opt) => `${app}/${opt.path}`); const dataPluginActions = dataPluginMock.createStartContract().actions; const savedObjectsClient = savedObjectsServiceMock.createStartContract().client; const drilldown = new DashboardToDashboardDrilldown({ - getNavigateToApp: () => Promise.resolve(navigateToApp), + getApplicationService: () => + Promise.resolve({ + navigateToApp, + getUrlForApp, + }), getGetUrlGenerator: () => Promise.resolve( () => @@ -90,33 +100,34 @@ describe('.execute()', () => { }); const selectRangeFiltersSpy = jest .spyOn(dataPluginActions, 'createFiltersFromRangeSelectAction') - .mockImplementationOnce(() => Promise.resolve(filtersFromEvent)); + .mockImplementation(() => Promise.resolve(filtersFromEvent)); const valueClickFiltersSpy = jest .spyOn(dataPluginActions, 'createFiltersFromValueClickAction') - .mockImplementationOnce(() => Promise.resolve(filtersFromEvent)); + .mockImplementation(() => Promise.resolve(filtersFromEvent)); - await drilldown.execute( - { - dashboardId: 'id', - useCurrentFilters: false, - useCurrentDateRange: false, - ...config, + const completeConfig: Config = { + dashboardId: 'id', + useCurrentFilters: false, + useCurrentDateRange: false, + ...config, + }; + + const context = ({ + data: { + range: useRangeEvent ? {} : undefined, }, - ({ - data: { - range: useRangeEvent ? {} : undefined, - }, - timeFieldName: 'order_date', - embeddable: { - getInput: () => ({ - filters: [], - timeRange: { from: 'now-15m', to: 'now' }, - query: { query: 'test', language: 'kuery' }, - ...embeddableInput, - }), - }, - } as unknown) as ActionContext - ); + timeFieldName: 'order_date', + embeddable: { + getInput: () => ({ + filters: [], + timeRange: { from: 'now-15m', to: 'now' }, + query: { query: 'test', language: 'kuery' }, + ...embeddableInput, + }), + }, + } as unknown) as ActionContext; + + await drilldown.execute(completeConfig, context); if (useRangeEvent) { expect(selectRangeFiltersSpy).toBeCalledTimes(1); @@ -129,14 +140,19 @@ describe('.execute()', () => { expect(navigateToApp).toBeCalledTimes(1); expect(navigateToApp.mock.calls[0][0]).toBe('kibana'); + const executeNavigatedPath = navigateToApp.mock.calls[0][1]?.path; + const href = await drilldown.getHref(completeConfig, context); + + expect(href.includes(executeNavigatedPath)).toBe(true); + return { - navigatedPath: navigateToApp.mock.calls[0][1]?.path, + href, }; } test('navigates to correct dashboard', async () => { const testDashboardId = 'dashboardId'; - const { navigatedPath } = await setupTestBed( + const { href } = await setupTestBed( { dashboardId: testDashboardId, }, @@ -145,13 +161,13 @@ describe('.execute()', () => { false ); - expect(navigatedPath).toEqual(expect.stringContaining(`dashboard/${testDashboardId}`)); + expect(href).toEqual(expect.stringContaining(`dashboard/${testDashboardId}`)); }); test('query is removed with query if filters are disabled', async () => { const queryString = 'querystring'; const queryLanguage = 'kuery'; - const { navigatedPath } = await setupTestBed( + const { href } = await setupTestBed( { useCurrentFilters: false, }, @@ -161,14 +177,14 @@ describe('.execute()', () => { [] ); - expect(navigatedPath).toEqual(expect.not.stringContaining(queryString)); - expect(navigatedPath).toEqual(expect.not.stringContaining(queryLanguage)); + expect(href).toEqual(expect.not.stringContaining(queryString)); + expect(href).toEqual(expect.not.stringContaining(queryLanguage)); }); test('navigates with query if filters are enabled', async () => { const queryString = 'querystring'; const queryLanguage = 'kuery'; - const { navigatedPath } = await setupTestBed( + const { href } = await setupTestBed( { useCurrentFilters: true, }, @@ -178,8 +194,8 @@ describe('.execute()', () => { [] ); - expect(navigatedPath).toEqual(expect.stringContaining(queryString)); - expect(navigatedPath).toEqual(expect.stringContaining(queryLanguage)); + expect(href).toEqual(expect.stringContaining(queryString)); + expect(href).toEqual(expect.stringContaining(queryLanguage)); }); test('when user chooses to keep current filters, current filters are set on destination dashboard', async () => { @@ -187,20 +203,19 @@ describe('.execute()', () => { const existingGlobalFilterKey = 'existingGlobalFilter'; const newAppliedFilterKey = 'newAppliedFilter'; - const { navigatedPath } = await setupTestBed( + const { href } = await setupTestBed( { useCurrentFilters: true, }, { filters: [getFilter(false, existingAppFilterKey), getFilter(true, existingGlobalFilterKey)], }, - [getFilter(false, newAppliedFilterKey)], - false + [getFilter(false, newAppliedFilterKey)] ); - expect(navigatedPath).toEqual(expect.stringContaining(existingAppFilterKey)); - expect(navigatedPath).toEqual(expect.stringContaining(existingGlobalFilterKey)); - expect(navigatedPath).toEqual(expect.stringContaining(newAppliedFilterKey)); + expect(href).toEqual(expect.stringContaining(existingAppFilterKey)); + expect(href).toEqual(expect.stringContaining(existingGlobalFilterKey)); + expect(href).toEqual(expect.stringContaining(newAppliedFilterKey)); }); test('when user chooses to remove current filters, current app filters are remove on destination dashboard', async () => { @@ -208,24 +223,23 @@ describe('.execute()', () => { const existingGlobalFilterKey = 'existingGlobalFilter'; const newAppliedFilterKey = 'newAppliedFilter'; - const { navigatedPath } = await setupTestBed( + const { href } = await setupTestBed( { useCurrentFilters: false, }, { filters: [getFilter(false, existingAppFilterKey), getFilter(true, existingGlobalFilterKey)], }, - [getFilter(false, newAppliedFilterKey)], - false + [getFilter(false, newAppliedFilterKey)] ); - expect(navigatedPath).not.toEqual(expect.stringContaining(existingAppFilterKey)); - expect(navigatedPath).toEqual(expect.stringContaining(existingGlobalFilterKey)); - expect(navigatedPath).toEqual(expect.stringContaining(newAppliedFilterKey)); + expect(href).not.toEqual(expect.stringContaining(existingAppFilterKey)); + expect(href).toEqual(expect.stringContaining(existingGlobalFilterKey)); + expect(href).toEqual(expect.stringContaining(newAppliedFilterKey)); }); test('when user chooses to keep current time range, current time range is passed in url', async () => { - const { navigatedPath } = await setupTestBed( + const { href } = await setupTestBed( { useCurrentDateRange: true, }, @@ -235,15 +249,14 @@ describe('.execute()', () => { to: 'now', }, }, - [], - false + [] ); - expect(navigatedPath).toEqual(expect.stringContaining('now-300m')); + expect(href).toEqual(expect.stringContaining('now-300m')); }); test('when user chooses to not keep current time range, no current time range is passed in url', async () => { - const { navigatedPath } = await setupTestBed( + const { href } = await setupTestBed( { useCurrentDateRange: false, }, @@ -257,11 +270,11 @@ describe('.execute()', () => { false ); - expect(navigatedPath).not.toEqual(expect.stringContaining('now-300m')); + expect(href).not.toEqual(expect.stringContaining('now-300m')); }); test('if range filter contains date, then it is passed as time', async () => { - const { navigatedPath } = await setupTestBed( + const { href } = await setupTestBed( { useCurrentDateRange: true, }, @@ -275,8 +288,8 @@ describe('.execute()', () => { true ); - expect(navigatedPath).not.toEqual(expect.stringContaining('now-300m')); - expect(navigatedPath).toEqual(expect.stringContaining('2020-03-23')); + expect(href).not.toEqual(expect.stringContaining('now-300m')); + expect(href).toEqual(expect.stringContaining('2020-03-23')); }); }); diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index bd3e90090d124..afb78d8f0cf29 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -19,7 +19,9 @@ import { VisualizeEmbeddableContract } from '../../../../../../../src/plugins/vi export interface Params { getSavedObjectsClient: () => Promise; - getNavigateToApp: () => Promise; + getApplicationService: () => Promise< + Pick + >; getGetUrlGenerator: () => Promise; getDataPluginActions: () => Promise; } @@ -59,15 +61,24 @@ export class DashboardToDashboardDrilldown config: Config, context: ActionContext ): Promise => { - return await this.getDestinationUrl(config, context); + const { getUrlForApp } = await this.params.getApplicationService(); + const dashboardPath = await this.getDestinationUrl(config, context); + // note: extracting hash and using 'kibana' as appId will be redundant, + // when dashboard move to np urls. (urlGenerator generates np url, which is not supported yet) + const dashboardHash = dashboardPath.split('#')[1]; + return getUrlForApp('kibana', { + path: `#${dashboardHash}`, + }); }; public readonly execute = async ( config: Config, context: ActionContext ) => { - const navigateToApp = await this.params.getNavigateToApp(); + const { navigateToApp } = await this.params.getApplicationService(); const dashboardPath = await this.getDestinationUrl(config, context); + // note: extracting hash and using 'kibana' as appId will be redundant, + // when dashboard move to np urls. (urlGenerator generates np url, which is not supported yet) const dashboardHash = dashboardPath.split('#')[1]; await navigateToApp('kibana', { path: `#${dashboardHash}`, diff --git a/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts b/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts index 0396ec9bc8b79..1a90d5d1fe52a 100644 --- a/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts +++ b/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts @@ -68,9 +68,18 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { // trigger drilldown action by clicking on a pie and picking drilldown action by it's name await pieChart.filterOnPieSlice('40,000'); await dashboardDrilldownPanelActions.expectMultipleActionsMenuOpened(); + + const href = await dashboardDrilldownPanelActions.getActionHrefByText( + DRILLDOWN_TO_AREA_CHART_NAME + ); + expect(typeof href).to.be('string'); // checking that action has a href + const dashboardIdFromHref = PageObjects.dashboard.getDashboardIdFromUrl(href); + await navigateWithinDashboard(async () => { await dashboardDrilldownPanelActions.clickActionByText(DRILLDOWN_TO_AREA_CHART_NAME); }); + // checking that href is at least pointing to the same dashboard that we are navigated to by regular click + expect(dashboardIdFromHref).to.be(await PageObjects.dashboard.getDashboardIdFromCurrentUrl()); // check that we drilled-down with filter from pie chart expect(await filterBar.getFilterCount()).to.be(1); @@ -80,6 +89,7 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { // brush area chart and drilldown back to pie chat dashboard await brushAreaChart(); await dashboardDrilldownPanelActions.expectMultipleActionsMenuOpened(); + await navigateWithinDashboard(async () => { await dashboardDrilldownPanelActions.clickActionByText(DRILLDOWN_TO_PIE_CHART_NAME); }); diff --git a/x-pack/test/functional/services/dashboard/drilldowns_manage.ts b/x-pack/test/functional/services/dashboard/drilldowns_manage.ts index 4d1b856b7c38a..a8711e9230adb 100644 --- a/x-pack/test/functional/services/dashboard/drilldowns_manage.ts +++ b/x-pack/test/functional/services/dashboard/drilldowns_manage.ts @@ -77,9 +77,7 @@ export function DashboardDrilldownsManageProvider({ getService }: FtrProviderCon const drilldowns = await testSubjects.findAll('listManageDrilldownsItem'); for (const drilldown of drilldowns) { - const nameColumn = await drilldown.findByCssSelector( - '[data-test-subj="drilldownListItemName"]' - ); + const nameColumn = await drilldown.findByTestSubject('drilldownListItemName'); const name = await nameColumn.getVisibleText(); if (titles.includes(name)) { const checkbox = await drilldown.findByTagName('input'); diff --git a/x-pack/test/functional/services/dashboard/panel_drilldown_actions.ts b/x-pack/test/functional/services/dashboard/panel_drilldown_actions.ts index 52f7540f9f2f7..febcbdcc9273e 100644 --- a/x-pack/test/functional/services/dashboard/panel_drilldown_actions.ts +++ b/x-pack/test/functional/services/dashboard/panel_drilldown_actions.ts @@ -5,6 +5,7 @@ */ import { FtrProviderContext } from '../../ftr_provider_context'; +import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; const CREATE_DRILLDOWN_DATA_TEST_SUBJ = 'embeddablePanelAction-OPEN_FLYOUT_ADD_DRILLDOWN'; const MANAGE_DRILLDOWNS_DATA_TEST_SUBJ = 'embeddablePanelAction-OPEN_FLYOUT_EDIT_DRILLDOWN'; @@ -53,12 +54,23 @@ export function DashboardDrilldownPanelActionsProvider({ getService }: FtrProvid async clickActionByText(text: string) { log.debug(`clickActionByText: "${text}"`); + (await this.getActionWebElementByText(text)).click(); + } + + async getActionHrefByText(text: string) { + log.debug(`getActionHref: "${text}"`); + const item = await this.getActionWebElementByText(text); + return item.getAttribute('href'); + } + + async getActionWebElementByText(text: string): Promise { + log.debug(`getActionWebElement: "${text}"`); const menu = await testSubjects.find('multipleActionsContextMenu'); const items = await menu.findAllByCssSelector('[data-test-subj*="embeddablePanelAction-"]'); for (const item of items) { const currentText = await item.getVisibleText(); if (currentText === text) { - return await item.click(); + return item; } } From 08250629d6a7f0d729fd901a3ef2da50a61920c7 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 17 Apr 2020 14:08:35 +0200 Subject: [PATCH 57/81] give proper name to a story --- .../dashboard_drilldown_config.story.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx index 15c0cd0c782de..f3a966a73509c 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.story.tsx @@ -36,7 +36,10 @@ const InteractiveDemo: React.FC = () => { ); }; -storiesOf('components/DashboardDrilldownConfig', module) +storiesOf( + 'services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config', + module +) .add('default', () => ( Date: Fri, 17 Apr 2020 14:11:29 +0200 Subject: [PATCH 58/81] use sync start services --- src/plugins/kibana_utils/public/index.ts | 1 + .../flyout_create_drilldown.test.tsx | 4 +-- .../flyout_create_drilldown.tsx | 8 +++--- .../flyout_edit_drilldown.test.tsx | 4 +-- .../flyout_edit_drilldown.tsx | 8 +++--- .../dashboard_drilldowns_services.ts | 19 +++++++------ .../drilldown.test.tsx | 28 ++++++++----------- .../drilldown.tsx | 10 +++---- 8 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts index 2f139050e994a..a1ef075d89d86 100644 --- a/src/plugins/kibana_utils/public/index.ts +++ b/src/plugins/kibana_utils/public/index.ts @@ -76,6 +76,7 @@ export { } from './state_sync'; export { removeQueryParam, redirectWhenMissing, ensureDefaultIndexPattern } from './history'; export { applyDiff } from './state_management/utils/diff_object'; +export { createStartServicesGetter } from './core/create_start_service_getter'; /** dummy plugin, we just want kibanaUtils to have its own bundle */ export function plugin() { diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.test.tsx index dcdefba04d882..83bbad9ae6b21 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.test.tsx @@ -20,8 +20,8 @@ const drilldowns = drilldownsPluginMock.createStartContract(); const uiActions = uiActionsPluginMock.createStartContract(); const actionParams: OpenFlyoutAddDrilldownParams = { - drilldowns: () => Promise.resolve(drilldowns), - overlays: () => Promise.resolve(overlays), + drilldowns: () => drilldowns, + overlays: () => overlays, }; test('should create', () => { diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx index 8aa0611519b16..da4d683043290 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx @@ -16,8 +16,8 @@ import { EmbeddableContext } from '../../../../../../../../src/plugins/embeddabl export const OPEN_FLYOUT_ADD_DRILLDOWN = 'OPEN_FLYOUT_ADD_DRILLDOWN'; export interface OpenFlyoutAddDrilldownParams { - overlays: () => Promise; - drilldowns: () => Promise; + overlays: () => CoreStart['overlays']; + drilldowns: () => DrilldownsStart; } export class FlyoutCreateDrilldownAction implements ActionByType { @@ -50,8 +50,8 @@ export class FlyoutCreateDrilldownAction implements ActionByType Promise.resolve(drilldowns), - overlays: () => Promise.resolve(overlays), + drilldowns: () => drilldowns, + overlays: () => overlays, }; test('should create', () => { diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_edit_drilldown/flyout_edit_drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_edit_drilldown/flyout_edit_drilldown.tsx index 860a3a65e42ff..98ed801b4b614 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_edit_drilldown/flyout_edit_drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_edit_drilldown/flyout_edit_drilldown.tsx @@ -20,8 +20,8 @@ import { isEnhancedEmbeddable } from '../../../../../../embeddable_enhanced/publ export const OPEN_FLYOUT_EDIT_DRILLDOWN = 'OPEN_FLYOUT_EDIT_DRILLDOWN'; export interface FlyoutEditDrilldownParams { - overlays: () => Promise; - drilldowns: () => Promise; + overlays: () => CoreStart['overlays']; + drilldowns: () => DrilldownsStart; } export class FlyoutEditDrilldownAction implements ActionByType { @@ -48,8 +48,8 @@ export class FlyoutEditDrilldownAction implements ActionByType, plugins: SetupDependencies) { - const overlays = async () => (await core.getStartServices())[0].overlays; - const drilldowns = async () => (await core.getStartServices())[1].drilldowns; - const getSavedObjectsClient = async () => - (await core.getStartServices())[0].savedObjects.client; - const getApplicationService = async () => (await core.getStartServices())[0].application; + const getStartServices = createStartServicesGetter( + core.getStartServices + ); - const getGetUrlGenerator = async () => - (await core.getStartServices())[1].share.urlGenerators.getUrlGenerator; - - const getDataPluginActions = async () => (await core.getStartServices())[1].data.actions; + const overlays = () => getStartServices().core.overlays; + const drilldowns = () => getStartServices().plugins.drilldowns; + const getSavedObjectsClient = () => getStartServices().core.savedObjects.client; + const getApplicationService = () => getStartServices().core.application; + const getGetUrlGenerator = () => getStartServices().plugins.share.urlGenerators.getUrlGenerator; + const getDataPluginActions = () => getStartServices().plugins.data.actions; const actionFlyoutCreateDrilldown = new FlyoutCreateDrilldownAction({ overlays, drilldowns }); plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, actionFlyoutCreateDrilldown); diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx index 561eb5145e95d..247b33f72ab4a 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx @@ -83,27 +83,23 @@ describe('.execute() & getHref', () => { const savedObjectsClient = savedObjectsServiceMock.createStartContract().client; const drilldown = new DashboardToDashboardDrilldown({ - getApplicationService: () => - Promise.resolve({ - navigateToApp, - getUrlForApp, - }), - getGetUrlGenerator: () => - Promise.resolve( - () => - createDirectAccessDashboardLinkGenerator(() => - Promise.resolve({ appBasePath: 'test', useHashedUrl: false }) - ) as UrlGeneratorContract - ), - getDataPluginActions: () => Promise.resolve(dataPluginActions), - getSavedObjectsClient: () => Promise.resolve(savedObjectsClient), + getApplicationService: () => ({ + navigateToApp, + getUrlForApp, + }), + getGetUrlGenerator: () => () => + createDirectAccessDashboardLinkGenerator(() => + Promise.resolve({ appBasePath: 'test', useHashedUrl: false }) + ) as UrlGeneratorContract, + getDataPluginActions: () => dataPluginActions, + getSavedObjectsClient: () => savedObjectsClient, }); const selectRangeFiltersSpy = jest .spyOn(dataPluginActions, 'createFiltersFromRangeSelectAction') - .mockImplementation(() => Promise.resolve(filtersFromEvent)); + .mockImplementation(() => filtersFromEvent); const valueClickFiltersSpy = jest .spyOn(dataPluginActions, 'createFiltersFromValueClickAction') - .mockImplementation(() => Promise.resolve(filtersFromEvent)); + .mockImplementation(() => filtersFromEvent); const completeConfig: Config = { dashboardId: 'id', diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index afb78d8f0cf29..2bae9cc35865b 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -18,12 +18,10 @@ import { DataPublicPluginStart, esFilters } from '../../../../../../../src/plugi import { VisualizeEmbeddableContract } from '../../../../../../../src/plugins/visualizations/public'; export interface Params { - getSavedObjectsClient: () => Promise; - getApplicationService: () => Promise< - Pick - >; - getGetUrlGenerator: () => Promise; - getDataPluginActions: () => Promise; + getSavedObjectsClient: () => CoreStart['savedObjects']['client']; + getApplicationService: () => Pick; + getGetUrlGenerator: () => SharePluginStart['urlGenerators']['getUrlGenerator']; + getDataPluginActions: () => DataPublicPluginStart['actions']; } export class DashboardToDashboardDrilldown From 7010b18db5c6923c97e3e8444fbcf1fb2578e623 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 17 Apr 2020 14:14:53 +0200 Subject: [PATCH 59/81] update text --- .../components/dashboard_drilldown_config/i18n.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/i18n.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/i18n.ts index 6f2c29693fcb0..5bd6b3b262e20 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/i18n.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/i18n.ts @@ -16,13 +16,13 @@ export const txtChooseDestinationDashboard = i18n.translate( export const txtUseCurrentFilters = i18n.translate( 'xpack.dashboard.components.DashboardDrilldownConfig.useCurrentFilters', { - defaultMessage: "Use current dashboard's filters", + defaultMessage: "Use origin dashboard's filters and query", } ); export const txtUseCurrentDateRange = i18n.translate( 'xpack.dashboard.components.DashboardDrilldownConfig.useCurrentDateRange', { - defaultMessage: "Use current dashboard's date range", + defaultMessage: "Use origin dashboard's date range", } ); From ed71dc5179cfd3ea6779b196448500e56c1b56ef Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 17 Apr 2020 14:21:50 +0200 Subject: [PATCH 60/81] fix types --- .../dashboard_to_dashboard_drilldown/drilldown.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx index 247b33f72ab4a..e0276ec33d097 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx @@ -96,10 +96,10 @@ describe('.execute() & getHref', () => { }); const selectRangeFiltersSpy = jest .spyOn(dataPluginActions, 'createFiltersFromRangeSelectAction') - .mockImplementation(() => filtersFromEvent); + .mockImplementation(() => Promise.resolve(filtersFromEvent)); const valueClickFiltersSpy = jest .spyOn(dataPluginActions, 'createFiltersFromValueClickAction') - .mockImplementation(() => filtersFromEvent); + .mockImplementation(() => Promise.resolve(filtersFromEvent)); const completeConfig: Config = { dashboardId: 'id', From 6ca0d9300ed23873127557237f05377cef31d42d Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 17 Apr 2020 14:55:37 +0200 Subject: [PATCH 61/81] fix ts --- .../components/collect_config_container.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx index 72544163e9e6a..7c36536e8ef3e 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx @@ -37,7 +37,7 @@ const dashboardSavedObjectToMenuItem = ( interface CollectConfigProps extends UiActionsCollectConfigProps { deps: { - getSavedObjectsClient: () => Promise; + getSavedObjectsClient: () => CoreStart['savedObjects']['client']; }; context: DrilldownFactoryContext<{ embeddable: IEmbeddable; @@ -117,7 +117,7 @@ export class CollectConfigContainer extends React.Component< private async loadSelectedDashboard() { const { config } = this.props; if (!config.dashboardId) return; - const savedObjectsClient = await this.props.deps.getSavedObjectsClient(); + const savedObjectsClient = this.props.deps.getSavedObjectsClient(); const savedObject = await savedObjectsClient.get<{ title: string }>( 'dashboard', config.dashboardId @@ -150,7 +150,7 @@ export class CollectConfigContainer extends React.Component< private async loadDashboards(searchString?: string) { const currentDashboardId = this.props.context.placeContext.embeddable?.parent?.id; this.setState({ searchString, isLoading: true }); - const savedObjectsClient = await this.props.deps.getSavedObjectsClient(); + const savedObjectsClient = this.props.deps.getSavedObjectsClient(); const { savedObjects } = await savedObjectsClient.find<{ title: string }>({ type: 'dashboard', search: searchString ? `${searchString}*` : undefined, From 1ac52d047bcae6977899cd5bda3c5c93d5e8e0c3 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 21 Apr 2020 11:51:53 +0200 Subject: [PATCH 62/81] fix docs --- src/plugins/data/public/public.api.md | 108 +++++++++++++------------- 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 427c4f7864554..6c225a6e6f1dc 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -248,7 +248,8 @@ export interface DataPublicPluginSetup { export interface DataPublicPluginStart { // (undocumented) actions: { - createFiltersFromEvent: typeof createFiltersFromEvent; + createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction; + createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction; }; // Warning: (ae-forgotten-export) The symbol "AutocompleteStart" needs to be exported by the entry point index.d.ts // @@ -393,6 +394,7 @@ export const esFilters: { generateFilters: typeof generateFilters; onlyDisabledFiltersChanged: (newFilters?: import("../common").Filter[] | undefined, oldFilters?: import("../common").Filter[] | undefined) => boolean; changeTimeFilter: typeof changeTimeFilter; + convertRangeFilterToTimeRangeString: typeof convertRangeFilterToTimeRangeString; mapAndFlattenFilters: (filters: import("../common").Filter[]) => import("../common").Filter[]; extractTimeFilter: typeof extractTimeFilter; }; @@ -484,7 +486,7 @@ export type FieldFormatId = FIELD_FORMAT_IDS | string; export const fieldFormats: { FieldFormat: typeof FieldFormat; FieldFormatsRegistry: typeof FieldFormatsRegistry; - serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serialize: (agg: import("./search").AggConfig) => import("../../expressions").SerializedFieldFormat; DEFAULT_CONVERTER_COLOR: { range: string; regex: string; @@ -1841,58 +1843,60 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/common/es_query/filters/match_all_filter.ts:28:3 - (ae-forgotten-export) The symbol "MatchAllFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrase_filter.ts:33:3 - (ae-forgotten-export) The symbol "PhraseFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrases_filter.ts:31:3 - (ae-forgotten-export) The symbol "PhrasesFilterMeta" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "FilterLabel" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "generateFilters" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:382:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:382:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:382:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:382:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:387:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:399:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:404:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FilterLabel" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "generateFilters" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "convertRangeFilterToTimeRangeString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:392:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:403:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:407:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:410:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:414:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromEvent" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:60:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:53:5 - (ae-forgotten-export) The symbol "createFiltersFromRangeSelectAction" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:61:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) From bb7f7d3e3a11659ca87a1d4e00c2c57326dadaa7 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 21 Apr 2020 12:02:36 +0200 Subject: [PATCH 63/81] move clone below drilldowns (near replace) --- .../dashboard/public/application/actions/clone_panel_action.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx index 4d15e7e899fa8..869646a653ee4 100644 --- a/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx +++ b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx @@ -39,7 +39,7 @@ export interface ClonePanelActionContext { export class ClonePanelAction implements ActionByType { public readonly type = ACTION_CLONE_PANEL; public readonly id = ACTION_CLONE_PANEL; - public order = 11; + public order = 4; constructor(private core: CoreStart) {} From 8c4e836e0939453850fe9ad4f3a0c921bcb2740a Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 21 Apr 2020 12:04:03 +0200 Subject: [PATCH 64/81] remove redundant comments --- .../components/collect_config_container.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx index 7c36536e8ef3e..1d6cb9aaa0feb 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/collect_config_container.tsx @@ -123,7 +123,7 @@ export class CollectConfigContainer extends React.Component< config.dashboardId ); - if (!this.isMounted) return; // bailout if response is no longer needed + if (!this.isMounted) return; // handle case when destination dashboard is no longer exist if (savedObject.error?.statusCode === 404) { @@ -134,7 +134,6 @@ export class CollectConfigContainer extends React.Component< return; } - // any other error if (savedObject.error) { this.setState({ error: savedObject.error.message, From 73eadb0a3f2a367a5f51fb9a706c094a16c39d29 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Wed, 8 Apr 2020 09:03:51 -0700 Subject: [PATCH 65/81] refactor action filter creation utils --- .../vis_type_vislib/public/plugin.ts | 4 +- .../vislib/components/legend/legend.test.tsx | 4 +- .../vislib/components/legend/legend.tsx | 2 +- .../new_platform/new_platform.karma_mock.js | 2 +- ... create_filters_from_range_select.test.ts} | 79 ++++++++----------- ...ts => create_filters_from_range_select.ts} | 34 +++----- ...> create_filters_from_value_click.test.ts} | 10 +-- ....ts => create_filters_from_value_click.ts} | 11 ++- src/plugins/data/public/actions/index.ts | 2 +- .../public/actions/select_range_action.ts | 17 ++-- .../data/public/actions/value_click_action.ts | 18 ++--- src/plugins/data/public/mocks.ts | 2 +- src/plugins/data/public/plugin.ts | 8 +- src/plugins/data/public/types.ts | 4 +- .../public/lib/triggers/triggers.ts | 5 +- 15 files changed, 96 insertions(+), 106 deletions(-) rename src/plugins/data/public/actions/filters/{brush_event.test.ts => create_filters_from_range_select.test.ts} (70%) rename src/plugins/data/public/actions/filters/{brush_event.ts => create_filters_from_range_select.ts} (75%) rename src/plugins/data/public/actions/filters/{create_filters_from_event.test.ts => create_filters_from_value_click.test.ts} (88%) rename src/plugins/data/public/actions/filters/{create_filters_from_event.ts => create_filters_from_value_click.ts} (94%) diff --git a/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts b/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts index ef3f664252856..f7cf090b43afc 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts @@ -108,6 +108,8 @@ export class VisTypeVislibPlugin implements Plugin { public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) { setFormatService(data.fieldFormats); - setDataActions({ createFiltersFromEvent: data.actions.createFiltersFromEvent }); + setDataActions({ + createFiltersFromValueClickAction: data.actions.createFiltersFromValueClickAction, + }); } } diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx index c378ae7b05b37..6bf66c2bdd788 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx @@ -36,7 +36,9 @@ jest.mock('../../../legacy_imports', () => ({ })); jest.mock('../../../services', () => ({ - getDataActions: () => ({ createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']) }), + getDataActions: () => ({ + createFiltersFromValueClickAction: jest.fn().mockResolvedValue(['yes']), + }), })); const vis = { diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx index 2fe16bbfeb625..7eb25e3930718 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx @@ -101,7 +101,7 @@ export class VisLegend extends PureComponent { return false; } - const filters = await getDataActions().createFiltersFromEvent(item.values); + const filters = await getDataActions().createFiltersFromValueClickAction({ data: item.values }); return Boolean(filters.length); }; diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index f14f26613ef01..414265e7e0dea 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -377,7 +377,7 @@ export const npStart = { }, data: { actions: { - createFiltersFromEvent: Promise.resolve(['yes']), + createFiltersFromValueClickAction: Promise.resolve(['yes']), }, autocomplete: { getProvider: sinon.fake(), diff --git a/src/plugins/data/public/actions/filters/brush_event.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts similarity index 70% rename from src/plugins/data/public/actions/filters/brush_event.test.ts rename to src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts index 60244354f06e4..b0b9ac0669ed2 100644 --- a/src/plugins/data/public/actions/filters/brush_event.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts @@ -19,7 +19,10 @@ import moment from 'moment'; -import { onBrushEvent, BrushEvent } from './brush_event'; +import { + createFiltersFromRangeSelectAction, + RangeSelectEvent, +} from './create_filters_from_range_select'; import { IndexPatternsContract } from '../../../public'; import { dataPluginMock } from '../../../public/mocks'; @@ -29,7 +32,7 @@ import { mockDataServices } from '../../../public/search/aggs/test_helpers'; describe('brushEvent', () => { const DAY_IN_MS = 24 * 60 * 60 * 1000; const JAN_01_2014 = 1388559600000; - let baseEvent: BrushEvent; + let baseEvent: RangeSelectEvent; const aggConfigs = [ { @@ -61,44 +64,32 @@ describe('brushEvent', () => { } as unknown) as IndexPatternsContract); baseEvent = { - data: { - ordered: { - date: false, - }, - series: [ + column: 0, + table: { + type: 'kibana_datatable', + columns: [ { - values: [ - { - xRaw: { - column: 0, - table: { - columns: [ - { - id: '1', - meta: { - type: 'histogram', - indexPatternId: 'indexPatternId', - aggConfigParams: aggConfigs[0].params, - }, - }, - ], - }, - }, - }, - ], + id: '1', + name: '1', + meta: { + type: 'histogram', + indexPatternId: 'indexPatternId', + aggConfigParams: aggConfigs[0].params, + }, }, ], + rows: [], }, range: [], }; }); test('should be a function', () => { - expect(typeof onBrushEvent).toBe('function'); + expect(typeof createFiltersFromRangeSelectAction).toBe('function'); }); test('ignores event when data.xAxisField not provided', async () => { - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromRangeSelectAction(baseEvent); expect(filter).toBeUndefined(); }); @@ -119,19 +110,19 @@ describe('brushEvent', () => { test('by ignoring the event when range spans zero time', async () => { baseEvent.range = [JAN_01_2014, JAN_01_2014]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromRangeSelectAction(baseEvent); expect(filter).toBeUndefined(); }); test('by updating the timefilter', async () => { baseEvent.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromRangeSelectAction(baseEvent); expect(filter).toBeDefined(); - if (filter) { - expect(filter.range.time.gte).toBe(new Date(JAN_01_2014).toISOString()); + if (filter.length) { + expect(filter[0].range.time.gte).toBe(new Date(JAN_01_2014).toISOString()); // Set to a baseline timezone for comparison. - expect(filter.range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString()); + expect(filter[0].range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString()); } }); }); @@ -154,14 +145,14 @@ describe('brushEvent', () => { const rangeBegin = JAN_01_2014; const rangeEnd = rangeBegin + DAY_IN_MS; baseEvent.range = [rangeBegin, rangeEnd]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromRangeSelectAction(baseEvent); expect(filter).toBeDefined(); - if (filter) { - expect(filter.range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString()); - expect(filter.range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString()); - expect(filter.range.anotherTimeField).toHaveProperty( + if (filter.length) { + expect(filter[0].range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString()); + expect(filter[0].range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString()); + expect(filter[0].range.anotherTimeField).toHaveProperty( 'format', 'strict_date_optional_time' ); @@ -184,20 +175,20 @@ describe('brushEvent', () => { test('by ignoring the event when range does not span at least 2 values', async () => { baseEvent.range = [1]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromRangeSelectAction(baseEvent); expect(filter).toBeUndefined(); }); test('by creating a new filter', async () => { baseEvent.range = [1, 2, 3, 4]; - const filter = await onBrushEvent(baseEvent); + const filter = await createFiltersFromRangeSelectAction(baseEvent); expect(filter).toBeDefined(); - if (filter) { - expect(filter.range.numberField.gte).toBe(1); - expect(filter.range.numberField.lt).toBe(4); - expect(filter.range.numberField).not.toHaveProperty('format'); + if (filter.length) { + expect(filter[0].range.numberField.gte).toBe(1); + expect(filter[0].range.numberField.lt).toBe(4); + expect(filter[0].range.numberField).not.toHaveProperty('format'); } }); }); diff --git a/src/plugins/data/public/actions/filters/brush_event.ts b/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts similarity index 75% rename from src/plugins/data/public/actions/filters/brush_event.ts rename to src/plugins/data/public/actions/filters/create_filters_from_range_select.ts index 714f005fbeb6d..3bf924dd30eab 100644 --- a/src/plugins/data/public/actions/filters/brush_event.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts @@ -17,34 +17,24 @@ * under the License. */ -import { get, last } from 'lodash'; +import { last } from 'lodash'; import moment from 'moment'; import { esFilters, IFieldType, RangeFilterParams } from '../../../public'; import { getIndexPatterns } from '../../../public/services'; import { deserializeAggConfig } from '../../search/expressions/utils'; +import { KibanaDatatable } from '../../../../expressions'; -export interface BrushEvent { - data: { - ordered: { - date: boolean; - }; - series: Array>; - }; +export interface RangeSelectEvent { + table: KibanaDatatable; + column: number; range: number[]; } -export async function onBrushEvent(event: BrushEvent) { - const isDate = get(event.data, 'ordered.date'); - const xRaw: Record = get(event.data, 'series[0].values[0].xRaw'); - - if (!xRaw) { - return; - } - - const column: Record = xRaw.table.columns[xRaw.column]; +export async function createFiltersFromRangeSelectAction(event: RangeSelectEvent) { + const column: Record = event.table.columns[event.column]; if (!column || !column.meta) { - return; + return []; } const indexPattern = await getIndexPatterns().get(column.meta.indexPatternId); @@ -55,16 +45,18 @@ export async function onBrushEvent(event: BrushEvent) { const field: IFieldType = aggConfig.params.field; if (!field || event.range.length <= 1) { - return; + return []; } const min = event.range[0]; const max = last(event.range); if (min === max) { - return; + return []; } + const isDate = field.type === 'date'; + const range: RangeFilterParams = { gte: isDate ? moment(min).toISOString() : min, lt: isDate ? moment(max).toISOString() : max, @@ -74,5 +66,5 @@ export async function onBrushEvent(event: BrushEvent) { range.format = 'strict_date_optional_time'; } - return esFilters.buildRangeFilter(field, range, indexPattern); + return esFilters.mapAndFlattenFilters([esFilters.buildRangeFilter(field, range, indexPattern)]); } diff --git a/src/plugins/data/public/actions/filters/create_filters_from_event.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts similarity index 88% rename from src/plugins/data/public/actions/filters/create_filters_from_event.test.ts rename to src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts index 1ed09002816d1..84c78a36e8e19 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_event.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts @@ -26,7 +26,7 @@ import { import { dataPluginMock } from '../../../public/mocks'; import { setIndexPatterns } from '../../../public/services'; import { mockDataServices } from '../../../public/search/aggs/test_helpers'; -import { createFiltersFromEvent, EventData } from './create_filters_from_event'; +import { createFiltersFromValueClickAction, EventData } from './create_filters_from_value_click'; const mockField = { name: 'bytes', @@ -37,7 +37,7 @@ const mockField = { format: new fieldFormats.BytesFormat({}, (() => {}) as FieldFormatsGetConfigFn), }; -describe('createFiltersFromEvent', () => { +describe('createFiltersFromValueClick', () => { let dataPoints: EventData[]; beforeEach(() => { @@ -86,7 +86,7 @@ describe('createFiltersFromEvent', () => { test('ignores event when value for rows is not provided', async () => { dataPoints[0].table.rows[0]['1-1'] = null; - const filters = await createFiltersFromEvent(dataPoints); + const filters = await createFiltersFromValueClickAction({ data: dataPoints }); expect(filters.length).toEqual(0); }); @@ -95,14 +95,14 @@ describe('createFiltersFromEvent', () => { if (dataPoints[0].table.columns[0].meta) { dataPoints[0].table.columns[0].meta.type = 'terms'; } - const filters = await createFiltersFromEvent(dataPoints); + const filters = await createFiltersFromValueClickAction({ data: dataPoints }); expect(filters.length).toEqual(1); expect(filters[0].query.match_phrase.bytes).toEqual('2048'); }); test('handles an event when aggregations type is not terms', async () => { - const filters = await createFiltersFromEvent(dataPoints); + const filters = await createFiltersFromValueClickAction({ data: dataPoints }); expect(filters.length).toEqual(1); diff --git a/src/plugins/data/public/actions/filters/create_filters_from_event.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts similarity index 94% rename from src/plugins/data/public/actions/filters/create_filters_from_event.ts rename to src/plugins/data/public/actions/filters/create_filters_from_value_click.ts index e62945a592072..1b4ea14c80ae4 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_event.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts @@ -29,6 +29,11 @@ export interface EventData { value: any; } +export interface ValueClickEvent { + data: EventData[]; + negate?: boolean; +} + /** * For terms aggregations on `__other__` buckets, this assembles a list of applicable filter * terms based on a specific cell in the tabified data. @@ -113,11 +118,11 @@ const createFilter = async (table: EventData['table'], columnIndex: number, rowI }; /** @public */ -export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: boolean) => { +export const createFiltersFromValueClickAction = async ({ data, negate }: ValueClickEvent) => { const filters: Filter[] = []; await Promise.all( - dataPoints + data .filter(point => point) .map(async val => { const { table, column, row } = val; @@ -133,5 +138,5 @@ export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: b }) ); - return filters; + return esFilters.mapAndFlattenFilters(filters); }; diff --git a/src/plugins/data/public/actions/index.ts b/src/plugins/data/public/actions/index.ts index cdb84ff13f25e..d9ea6fab047e1 100644 --- a/src/plugins/data/public/actions/index.ts +++ b/src/plugins/data/public/actions/index.ts @@ -18,6 +18,6 @@ */ export { ACTION_GLOBAL_APPLY_FILTER, createFilterAction } from './apply_filter_action'; -export { createFiltersFromEvent } from './filters/create_filters_from_event'; +export { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click'; export { selectRangeAction } from './select_range_action'; export { valueClickAction } from './value_click_action'; diff --git a/src/plugins/data/public/actions/select_range_action.ts b/src/plugins/data/public/actions/select_range_action.ts index 6e1f16a09e803..29a0a3123028b 100644 --- a/src/plugins/data/public/actions/select_range_action.ts +++ b/src/plugins/data/public/actions/select_range_action.ts @@ -23,19 +23,22 @@ import { IncompatibleActionError, ActionByType, } from '../../../../plugins/ui_actions/public'; -import { onBrushEvent } from './filters/brush_event'; +import { + createFiltersFromRangeSelectAction, + RangeSelectEvent, +} from './filters/create_filters_from_range_select'; import { FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_SELECT_RANGE = 'ACTION_SELECT_RANGE'; export interface SelectRangeActionContext { - data: any; + data: RangeSelectEvent; timeFieldName: string; } async function isCompatible(context: SelectRangeActionContext) { try { - return Boolean(await onBrushEvent(context.data)); + return Boolean(await createFiltersFromRangeSelectAction(context.data)); } catch { return false; } @@ -59,13 +62,7 @@ export function selectRangeAction( throw new IncompatibleActionError(); } - const filter = await onBrushEvent(data); - - if (!filter) { - return; - } - - const selectedFilters = esFilters.mapAndFlattenFilters([filter]); + const selectedFilters = await createFiltersFromRangeSelectAction(data); if (timeFieldName) { const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( diff --git a/src/plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts index 01c32e27da07d..ce35b9aaa2820 100644 --- a/src/plugins/data/public/actions/value_click_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -26,21 +26,22 @@ import { } from '../../../../plugins/ui_actions/public'; import { getOverlays, getIndexPatterns } from '../services'; import { applyFiltersPopover } from '../ui/apply_filters'; -import { createFiltersFromEvent } from './filters/create_filters_from_event'; +import { + createFiltersFromValueClickAction, + ValueClickEvent, +} from './filters/create_filters_from_value_click'; import { Filter, FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_VALUE_CLICK = 'ACTION_VALUE_CLICK'; export interface ValueClickActionContext { - data: any; + data: ValueClickEvent; timeFieldName: string; } async function isCompatible(context: ValueClickActionContext) { try { - const filters: Filter[] = - (await createFiltersFromEvent(context.data.data || [context.data], context.data.negate)) || - []; + const filters: Filter[] = await createFiltersFromValueClickAction(context.data); return filters.length > 0; } catch { return false; @@ -65,12 +66,11 @@ export function valueClickAction( throw new IncompatibleActionError(); } - const filters: Filter[] = - (await createFiltersFromEvent(data.data || [data], data.negate)) || []; + const filters: Filter[] = await createFiltersFromValueClickAction(data); - let selectedFilters: Filter[] = esFilters.mapAndFlattenFilters(filters); + let selectedFilters = filters; - if (selectedFilters.length > 1) { + if (filters.length > 1) { const indexPatterns = await Promise.all( filters.map(filter => { return getIndexPatterns().get(filter.meta.index!); diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 2d43cae79ac98..0f708cc589d83 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -45,7 +45,7 @@ const createStartContract = (): Start => { const queryStartMock = queryServiceMock.createStartContract(); return { actions: { - createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']), + createFiltersFromValueClickAction: jest.fn().mockResolvedValue(['yes']), }, autocomplete: autocompleteMock, search: searchStartMock, diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 1723545b32522..2e8720a280c71 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -58,7 +58,11 @@ import { VALUE_CLICK_TRIGGER, APPLY_FILTER_TRIGGER, } from '../../ui_actions/public'; -import { ACTION_GLOBAL_APPLY_FILTER, createFilterAction, createFiltersFromEvent } from './actions'; +import { + ACTION_GLOBAL_APPLY_FILTER, + createFilterAction, + createFiltersFromValueClickAction, +} from './actions'; import { ApplyGlobalFilterActionContext } from './actions/apply_filter_action'; import { selectRangeAction, @@ -162,7 +166,7 @@ export class DataPublicPlugin implements Plugin Date: Mon, 13 Apr 2020 23:48:43 -0700 Subject: [PATCH 66/81] updating --- .../create_filters_from_range_select.test.ts | 59 +++++++++---------- src/plugins/data/public/actions/index.ts | 1 + src/plugins/data/public/plugin.ts | 2 + .../visualizations/public/expressions/vis.ts | 5 +- 4 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts index b0b9ac0669ed2..0d53256772bd5 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts @@ -24,7 +24,7 @@ import { RangeSelectEvent, } from './create_filters_from_range_select'; -import { IndexPatternsContract } from '../../../public'; +import { IndexPatternsContract, RangeFilter } from '../../../public'; import { dataPluginMock } from '../../../public/mocks'; import { setIndexPatterns } from '../../../public/services'; import { mockDataServices } from '../../../public/search/aggs/test_helpers'; @@ -34,18 +34,21 @@ describe('brushEvent', () => { const JAN_01_2014 = 1388559600000; let baseEvent: RangeSelectEvent; + const indexPattern = { + id: 'indexPatternId', + timeFieldName: 'time', + fields: { + getByName: () => undefined, + filter: () => [], + }, + }; + const aggConfigs = [ { params: { field: {}, }, - getIndexPattern: () => ({ - timeFieldName: 'time', - fields: { - getByName: () => undefined, - filter: () => [], - }, - }), + getIndexPattern: () => indexPattern, }, ]; @@ -53,14 +56,7 @@ describe('brushEvent', () => { mockDataServices(); setIndexPatterns(({ ...dataPluginMock.createStartContract().indexPatterns, - get: async () => ({ - id: 'indexPatternId', - timeFieldName: 'time', - fields: { - getByName: () => undefined, - filter: () => [], - }, - }), + get: async () => indexPattern, } as unknown) as IndexPatternsContract); baseEvent = { @@ -90,7 +86,7 @@ describe('brushEvent', () => { test('ignores event when data.xAxisField not provided', async () => { const filter = await createFiltersFromRangeSelectAction(baseEvent); - expect(filter).toBeUndefined(); + expect(filter).toEqual([]); }); describe('handles an event when the x-axis field is a date field', () => { @@ -100,18 +96,17 @@ describe('brushEvent', () => { name: 'time', type: 'date', }; - baseEvent.data.ordered = { date: true }; }); afterAll(() => { baseEvent.range = []; - baseEvent.data.ordered = { date: false }; + aggConfigs[0].params.field = {}; }); test('by ignoring the event when range spans zero time', async () => { baseEvent.range = [JAN_01_2014, JAN_01_2014]; const filter = await createFiltersFromRangeSelectAction(baseEvent); - expect(filter).toBeUndefined(); + expect(filter).toEqual([]); }); test('by updating the timefilter', async () => { @@ -120,9 +115,10 @@ describe('brushEvent', () => { expect(filter).toBeDefined(); if (filter.length) { - expect(filter[0].range.time.gte).toBe(new Date(JAN_01_2014).toISOString()); + const rangeFilter = filter[0] as RangeFilter; + expect(rangeFilter.range.time.gte).toBe(new Date(JAN_01_2014).toISOString()); // Set to a baseline timezone for comparison. - expect(filter[0].range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString()); + expect(rangeFilter.range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString()); } }); }); @@ -133,12 +129,11 @@ describe('brushEvent', () => { name: 'anotherTimeField', type: 'date', }; - baseEvent.data.ordered = { date: true }; }); afterAll(() => { baseEvent.range = []; - baseEvent.data.ordered = { date: false }; + aggConfigs[0].params.field = {}; }); test('creates a new range filter', async () => { @@ -150,9 +145,10 @@ describe('brushEvent', () => { expect(filter).toBeDefined(); if (filter.length) { - expect(filter[0].range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString()); - expect(filter[0].range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString()); - expect(filter[0].range.anotherTimeField).toHaveProperty( + const rangeFilter = filter[0] as RangeFilter; + expect(rangeFilter.range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString()); + expect(rangeFilter.range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString()); + expect(rangeFilter.range.anotherTimeField).toHaveProperty( 'format', 'strict_date_optional_time' ); @@ -176,7 +172,7 @@ describe('brushEvent', () => { test('by ignoring the event when range does not span at least 2 values', async () => { baseEvent.range = [1]; const filter = await createFiltersFromRangeSelectAction(baseEvent); - expect(filter).toBeUndefined(); + expect(filter).toEqual([]); }); test('by creating a new filter', async () => { @@ -186,9 +182,10 @@ describe('brushEvent', () => { expect(filter).toBeDefined(); if (filter.length) { - expect(filter[0].range.numberField.gte).toBe(1); - expect(filter[0].range.numberField.lt).toBe(4); - expect(filter[0].range.numberField).not.toHaveProperty('format'); + const rangeFilter = filter[0] as RangeFilter; + expect(rangeFilter.range.numberField.gte).toBe(1); + expect(rangeFilter.range.numberField.lt).toBe(4); + expect(rangeFilter.range.numberField).not.toHaveProperty('format'); } }); }); diff --git a/src/plugins/data/public/actions/index.ts b/src/plugins/data/public/actions/index.ts index d9ea6fab047e1..ef9014aafe82d 100644 --- a/src/plugins/data/public/actions/index.ts +++ b/src/plugins/data/public/actions/index.ts @@ -19,5 +19,6 @@ export { ACTION_GLOBAL_APPLY_FILTER, createFilterAction } from './apply_filter_action'; export { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click'; +export { createFiltersFromRangeSelectAction } from './filters/create_filters_from_range_select'; export { selectRangeAction } from './select_range_action'; export { valueClickAction } from './value_click_action'; diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 2e8720a280c71..ccf94171235fe 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -62,6 +62,7 @@ import { ACTION_GLOBAL_APPLY_FILTER, createFilterAction, createFiltersFromValueClickAction, + createFiltersFromRangeSelectAction, } from './actions'; import { ApplyGlobalFilterActionContext } from './actions/apply_filter_action'; import { @@ -167,6 +168,7 @@ export class DataPublicPlugin implements Plugin { if (!this.eventsSubject) return; - this.eventsSubject.next({ name: 'filterBucket', data }); + this.eventsSubject.next({ + name: 'filterBucket', + data: data.data ? data : { negate: false, data: [data] }, + }); }, brush: (data: any) => { if (!this.eventsSubject) return; From 974527f91c665371a5d01c03daf454686894a6f3 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Tue, 14 Apr 2020 01:36:49 -0700 Subject: [PATCH 67/81] updating docs --- ...gin-plugins-data-public.datapublicpluginstart.actions.md | 2 +- ...bana-plugin-plugins-data-public.datapublicpluginstart.md | 2 +- .../kibana-plugin-plugins-data-public.fieldformats.md | 2 +- .../kibana-plugin-plugins-data-server.fieldformats.md | 2 +- src/plugins/data/public/public.api.md | 6 +++--- src/plugins/data/server/server.api.md | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md index 3e966caa30799..66404d7747343 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md @@ -8,6 +8,6 @@ ```typescript actions: { - createFiltersFromEvent: typeof createFiltersFromEvent; + createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction; }; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md index a623e91388fd6..8522c626c59a1 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md @@ -14,7 +14,7 @@ export interface DataPublicPluginStart | Property | Type | Description | | --- | --- | --- | -| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromEvent: typeof createFiltersFromEvent;
} | | +| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;
} | | | [autocomplete](./kibana-plugin-plugins-data-public.datapublicpluginstart.autocomplete.md) | AutocompleteStart | | | [fieldFormats](./kibana-plugin-plugins-data-public.datapublicpluginstart.fieldformats.md) | FieldFormatsStart | | | [indexPatterns](./kibana-plugin-plugins-data-public.datapublicpluginstart.indexpatterns.md) | IndexPatternsContract | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md index 244633c3c4c9e..d39871b99f744 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md @@ -10,7 +10,7 @@ fieldFormats: { FieldFormat: typeof FieldFormat; FieldFormatsRegistry: typeof FieldFormatsRegistry; - serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serialize: (agg: import("./search").AggConfig) => import("../../expressions").SerializedFieldFormat; DEFAULT_CONVERTER_COLOR: { range: string; regex: string; diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md index 2b986aee508e2..11f18a195d271 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md @@ -10,7 +10,7 @@ fieldFormats: { FieldFormatsRegistry: typeof FieldFormatsRegistry; FieldFormat: typeof FieldFormat; - serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions").SerializedFieldFormat; BoolFormat: typeof BoolFormat; BytesFormat: typeof BytesFormat; ColorFormat: typeof ColorFormat; diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 427c4f7864554..bd18e901ed66b 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -248,7 +248,7 @@ export interface DataPublicPluginSetup { export interface DataPublicPluginStart { // (undocumented) actions: { - createFiltersFromEvent: typeof createFiltersFromEvent; + createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction; }; // Warning: (ae-forgotten-export) The symbol "AutocompleteStart" needs to be exported by the entry point index.d.ts // @@ -484,7 +484,7 @@ export type FieldFormatId = FIELD_FORMAT_IDS | string; export const fieldFormats: { FieldFormat: typeof FieldFormat; FieldFormatsRegistry: typeof FieldFormatsRegistry; - serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serialize: (agg: import("./search").AggConfig) => import("../../expressions").SerializedFieldFormat; DEFAULT_CONVERTER_COLOR: { range: string; regex: string; @@ -1891,7 +1891,7 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromEvent" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:60:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index c41023eab6d20..f8a9a7792c492 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -283,7 +283,7 @@ export interface FieldFormatConfig { export const fieldFormats: { FieldFormatsRegistry: typeof FieldFormatsRegistry; FieldFormat: typeof FieldFormat; - serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions").SerializedFieldFormat; BoolFormat: typeof BoolFormat; BytesFormat: typeof BytesFormat; ColorFormat: typeof ColorFormat; From f1f46663033186727b5917dc13a48bdc3a775e5a Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 16 Apr 2020 13:01:41 +0200 Subject: [PATCH 68/81] fix payload emitted in brush event --- .../public/vislib/lib/handler.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/lib/handler.js b/src/legacy/core_plugins/vis_type_vislib/public/vislib/lib/handler.js index ecf67ee3e017c..f33ce0395af1f 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/lib/handler.js +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/lib/handler.js @@ -83,10 +83,21 @@ export class Handler { // memoize so that the same function is returned every time, // allowing us to remove/re-add the same function - this.getProxyHandler = _.memoize(function(event) { + this.getProxyHandler = _.memoize(function(eventType) { const self = this; - return function(e) { - self.vis.emit(event, e); + return function(eventPayload) { + switch (eventType) { + case 'brush': + const xRaw = _.get(eventPayload.data, 'series[0].values[0].xRaw'); + if (!xRaw) return; // not sure if this is possible? + return self.vis.emit(eventType, { + table: xRaw.table, + range: eventPayload.range, + column: xRaw.column, + }); + case 'click': + return self.vis.emit(eventType, eventPayload); + } }; }); From 997aad6594d51dac84e2ce15586ec0c9c174ac01 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 16 Apr 2020 13:29:52 +0200 Subject: [PATCH 69/81] properly export createRange action --- ...lugin-plugins-data-public.datapublicpluginstart.actions.md | 1 + ...kibana-plugin-plugins-data-public.datapublicpluginstart.md | 2 +- src/legacy/core_plugins/vis_type_vislib/public/plugin.ts | 4 +--- src/legacy/ui/public/new_platform/new_platform.karma_mock.js | 1 + src/plugins/data/public/mocks.ts | 1 + src/plugins/data/public/public.api.md | 4 +++- src/plugins/data/public/types.ts | 3 ++- 7 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md index 66404d7747343..25ce6eaa688f8 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md @@ -9,5 +9,6 @@ ```typescript actions: { createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction; + createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction; }; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md index 8522c626c59a1..4f43f10ce089e 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md @@ -14,7 +14,7 @@ export interface DataPublicPluginStart | Property | Type | Description | | --- | --- | --- | -| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;
} | | +| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;
createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction;
} | | | [autocomplete](./kibana-plugin-plugins-data-public.datapublicpluginstart.autocomplete.md) | AutocompleteStart | | | [fieldFormats](./kibana-plugin-plugins-data-public.datapublicpluginstart.fieldformats.md) | FieldFormatsStart | | | [indexPatterns](./kibana-plugin-plugins-data-public.datapublicpluginstart.indexpatterns.md) | IndexPatternsContract | | diff --git a/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts b/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts index f7cf090b43afc..26800f8a1620e 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_vislib/public/plugin.ts @@ -108,8 +108,6 @@ export class VisTypeVislibPlugin implements Plugin { public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) { setFormatService(data.fieldFormats); - setDataActions({ - createFiltersFromValueClickAction: data.actions.createFiltersFromValueClickAction, - }); + setDataActions(data.actions); } } diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index 414265e7e0dea..271586bb8c582 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -378,6 +378,7 @@ export const npStart = { data: { actions: { createFiltersFromValueClickAction: Promise.resolve(['yes']), + createFiltersFromRangeSelectAction: sinon.fake(), }, autocomplete: { getProvider: sinon.fake(), diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 0f708cc589d83..1f604b9eb6baa 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -46,6 +46,7 @@ const createStartContract = (): Start => { return { actions: { createFiltersFromValueClickAction: jest.fn().mockResolvedValue(['yes']), + createFiltersFromRangeSelectAction: jest.fn(), }, autocomplete: autocompleteMock, search: searchStartMock, diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index bd18e901ed66b..e51b737728344 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -249,6 +249,7 @@ export interface DataPublicPluginStart { // (undocumented) actions: { createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction; + createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction; }; // Warning: (ae-forgotten-export) The symbol "AutocompleteStart" needs to be exported by the entry point index.d.ts // @@ -1892,7 +1893,8 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:60:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:53:5 - (ae-forgotten-export) The symbol "createFiltersFromRangeSelectAction" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:61:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index e572e8015aa2e..5414de16be310 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -24,7 +24,7 @@ import { ExpressionsSetup } from 'src/plugins/expressions/public'; import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public'; import { AutocompleteSetup, AutocompleteStart } from './autocomplete'; import { FieldFormatsSetup, FieldFormatsStart } from './field_formats'; -import { createFiltersFromValueClickAction } from './actions'; +import { createFiltersFromRangeSelectAction, createFiltersFromValueClickAction } from './actions'; import { ISearchSetup, ISearchStart } from './search'; import { QuerySetup, QueryStart } from './query'; import { IndexPatternSelectProps } from './ui/index_pattern_select'; @@ -50,6 +50,7 @@ export interface DataPublicPluginSetup { export interface DataPublicPluginStart { actions: { createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction; + createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction; }; autocomplete: AutocompleteStart; indexPatterns: IndexPatternsContract; From fee20fcbe05ab19e0298c28155525e43c2fa358f Mon Sep 17 00:00:00 2001 From: ppisljar Date: Mon, 20 Apr 2020 23:23:31 -0700 Subject: [PATCH 70/81] some more updates --- ...plugin-plugins-data-public.fieldformats.md | 2 +- ...plugin-plugins-data-server.fieldformats.md | 2 +- .../create_filters_from_range_select.test.ts | 8 +++--- .../create_filters_from_range_select.ts | 10 ++----- .../create_filters_from_value_click.test.ts | 5 ++-- .../create_filters_from_value_click.ts | 26 ++++++++----------- .../public/actions/select_range_action.ts | 11 +++----- .../data/public/actions/value_click_action.ts | 23 +++++++--------- src/plugins/data/public/public.api.md | 2 +- src/plugins/data/server/server.api.md | 2 +- src/plugins/embeddable/public/index.ts | 3 ++- .../public/lib/triggers/triggers.ts | 23 ++++++++++++++-- src/plugins/ui_actions/public/types.ts | 7 ++--- .../public/embeddable/visualize_embeddable.ts | 4 +-- .../visualizations/public/expressions/vis.ts | 3 ++- .../public/xy_visualization/xy_expression.tsx | 18 ++++++------- 16 files changed, 74 insertions(+), 75 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md index d39871b99f744..244633c3c4c9e 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md @@ -10,7 +10,7 @@ fieldFormats: { FieldFormat: typeof FieldFormat; FieldFormatsRegistry: typeof FieldFormatsRegistry; - serialize: (agg: import("./search").AggConfig) => import("../../expressions").SerializedFieldFormat; + serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; DEFAULT_CONVERTER_COLOR: { range: string; regex: string; diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md index 11f18a195d271..2b986aee508e2 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md @@ -10,7 +10,7 @@ fieldFormats: { FieldFormatsRegistry: typeof FieldFormatsRegistry; FieldFormat: typeof FieldFormat; - serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions").SerializedFieldFormat; + serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; BoolFormat: typeof BoolFormat; BytesFormat: typeof BytesFormat; ColorFormat: typeof ColorFormat; diff --git a/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts index 0d53256772bd5..5d21b395b994f 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_range_select.test.ts @@ -19,20 +19,18 @@ import moment from 'moment'; -import { - createFiltersFromRangeSelectAction, - RangeSelectEvent, -} from './create_filters_from_range_select'; +import { createFiltersFromRangeSelectAction } from './create_filters_from_range_select'; import { IndexPatternsContract, RangeFilter } from '../../../public'; import { dataPluginMock } from '../../../public/mocks'; import { setIndexPatterns } from '../../../public/services'; import { mockDataServices } from '../../../public/search/aggs/test_helpers'; +import { TriggerContextMapping } from '../../../../ui_actions/public'; describe('brushEvent', () => { const DAY_IN_MS = 24 * 60 * 60 * 1000; const JAN_01_2014 = 1388559600000; - let baseEvent: RangeSelectEvent; + let baseEvent: TriggerContextMapping['SELECT_RANGE_TRIGGER']['data']; const indexPattern = { id: 'indexPatternId', diff --git a/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts b/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts index 3bf924dd30eab..409614ca9c380 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts @@ -22,15 +22,9 @@ import moment from 'moment'; import { esFilters, IFieldType, RangeFilterParams } from '../../../public'; import { getIndexPatterns } from '../../../public/services'; import { deserializeAggConfig } from '../../search/expressions/utils'; -import { KibanaDatatable } from '../../../../expressions'; +import { RangeSelectTriggerContext } from '../../../../embeddable/public'; -export interface RangeSelectEvent { - table: KibanaDatatable; - column: number; - range: number[]; -} - -export async function createFiltersFromRangeSelectAction(event: RangeSelectEvent) { +export async function createFiltersFromRangeSelectAction(event: RangeSelectTriggerContext['data']) { const column: Record = event.table.columns[event.column]; if (!column || !column.meta) { diff --git a/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts index 84c78a36e8e19..03ef949b52759 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts @@ -26,7 +26,8 @@ import { import { dataPluginMock } from '../../../public/mocks'; import { setIndexPatterns } from '../../../public/services'; import { mockDataServices } from '../../../public/search/aggs/test_helpers'; -import { createFiltersFromValueClickAction, EventData } from './create_filters_from_value_click'; +import { createFiltersFromValueClickAction } from './create_filters_from_value_click'; +import { ValueClickTriggerContext } from '../../../../embeddable/public'; const mockField = { name: 'bytes', @@ -38,7 +39,7 @@ const mockField = { }; describe('createFiltersFromValueClick', () => { - let dataPoints: EventData[]; + let dataPoints: ValueClickTriggerContext['data']; beforeEach(() => { dataPoints = [ diff --git a/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts index 1b4ea14c80ae4..a0ba3688a7000 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts @@ -21,18 +21,7 @@ import { KibanaDatatable } from '../../../../../plugins/expressions/public'; import { deserializeAggConfig } from '../../search/expressions'; import { esFilters, Filter } from '../../../public'; import { getIndexPatterns } from '../../../public/services'; - -export interface EventData { - table: Pick; - column: number; - row: number; - value: any; -} - -export interface ValueClickEvent { - data: EventData[]; - negate?: boolean; -} +import { ValueClickTriggerContext } from '../../../../embeddable/public'; /** * For terms aggregations on `__other__` buckets, this assembles a list of applicable filter @@ -44,7 +33,7 @@ export interface ValueClickEvent { * @return {array} - array of terms to filter against */ const getOtherBucketFilterTerms = ( - table: EventData['table'], + table: Pick, columnIndex: number, rowIndex: number ) => { @@ -81,7 +70,11 @@ const getOtherBucketFilterTerms = ( * @param {string} cellValue - value of the current cell * @return {Filter[]|undefined} - list of filters to provide to queryFilter.addFilters() */ -const createFilter = async (table: EventData['table'], columnIndex: number, rowIndex: number) => { +const createFilter = async ( + table: Pick, + columnIndex: number, + rowIndex: number +) => { if (!table || !table.columns || !table.columns[columnIndex]) { return; } @@ -118,7 +111,10 @@ const createFilter = async (table: EventData['table'], columnIndex: number, rowI }; /** @public */ -export const createFiltersFromValueClickAction = async ({ data, negate }: ValueClickEvent) => { +export const createFiltersFromValueClickAction = async ({ + data, + negate, +}: ValueClickTriggerContext) => { const filters: Filter[] = []; await Promise.all( diff --git a/src/plugins/data/public/actions/select_range_action.ts b/src/plugins/data/public/actions/select_range_action.ts index 29a0a3123028b..70a018e3c2bda 100644 --- a/src/plugins/data/public/actions/select_range_action.ts +++ b/src/plugins/data/public/actions/select_range_action.ts @@ -23,18 +23,13 @@ import { IncompatibleActionError, ActionByType, } from '../../../../plugins/ui_actions/public'; -import { - createFiltersFromRangeSelectAction, - RangeSelectEvent, -} from './filters/create_filters_from_range_select'; +import { createFiltersFromRangeSelectAction } from './filters/create_filters_from_range_select'; +import { RangeSelectTriggerContext } from '../../../embeddable/public'; import { FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_SELECT_RANGE = 'ACTION_SELECT_RANGE'; -export interface SelectRangeActionContext { - data: RangeSelectEvent; - timeFieldName: string; -} +export type SelectRangeActionContext = RangeSelectTriggerContext; async function isCompatible(context: SelectRangeActionContext) { try { diff --git a/src/plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts index ce35b9aaa2820..6a39ab3650f6e 100644 --- a/src/plugins/data/public/actions/value_click_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -26,22 +26,17 @@ import { } from '../../../../plugins/ui_actions/public'; import { getOverlays, getIndexPatterns } from '../services'; import { applyFiltersPopover } from '../ui/apply_filters'; -import { - createFiltersFromValueClickAction, - ValueClickEvent, -} from './filters/create_filters_from_value_click'; +import { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click'; +import { ValueClickTriggerContext } from '../../../embeddable/public'; import { Filter, FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_VALUE_CLICK = 'ACTION_VALUE_CLICK'; -export interface ValueClickActionContext { - data: ValueClickEvent; - timeFieldName: string; -} +export type ValueClickActionContext = ValueClickTriggerContext; async function isCompatible(context: ValueClickActionContext) { try { - const filters: Filter[] = await createFiltersFromValueClickAction(context.data); + const filters: Filter[] = await createFiltersFromValueClickAction(context); return filters.length > 0; } catch { return false; @@ -61,12 +56,12 @@ export function valueClickAction( }); }, isCompatible, - execute: async ({ timeFieldName, data }: ValueClickActionContext) => { - if (!(await isCompatible({ timeFieldName, data }))) { + execute: async (context: ValueClickActionContext) => { + if (!(await isCompatible(context))) { throw new IncompatibleActionError(); } - const filters: Filter[] = await createFiltersFromValueClickAction(data); + const filters: Filter[] = await createFiltersFromValueClickAction(context); let selectedFilters = filters; @@ -102,9 +97,9 @@ export function valueClickAction( selectedFilters = await filterSelectionPromise; } - if (timeFieldName) { + if (context.timeFieldName) { const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( - timeFieldName, + context.timeFieldName, selectedFilters ); filterManager.addFilters(restOfFilters); diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index e51b737728344..ac308251c1569 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -485,7 +485,7 @@ export type FieldFormatId = FIELD_FORMAT_IDS | string; export const fieldFormats: { FieldFormat: typeof FieldFormat; FieldFormatsRegistry: typeof FieldFormatsRegistry; - serialize: (agg: import("./search").AggConfig) => import("../../expressions").SerializedFieldFormat; + serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; DEFAULT_CONVERTER_COLOR: { range: string; regex: string; diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index f8a9a7792c492..c41023eab6d20 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -283,7 +283,7 @@ export interface FieldFormatConfig { export const fieldFormats: { FieldFormatsRegistry: typeof FieldFormatsRegistry; FieldFormat: typeof FieldFormat; - serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions").SerializedFieldFormat; + serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; BoolFormat: typeof BoolFormat; BytesFormat: typeof BytesFormat; ColorFormat: typeof ColorFormat; diff --git a/src/plugins/embeddable/public/index.ts b/src/plugins/embeddable/public/index.ts index bdb7bfbddc308..5ee66f9d19ac0 100644 --- a/src/plugins/embeddable/public/index.ts +++ b/src/plugins/embeddable/public/index.ts @@ -47,7 +47,8 @@ export { EmbeddableOutput, EmbeddablePanel, EmbeddableRoot, - EmbeddableVisTriggerContext, + ValueClickTriggerContext, + RangeSelectTriggerContext, ErrorEmbeddable, IContainer, IEmbeddable, diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index 50bfa270a51a2..5120a85b06d9e 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -18,16 +18,35 @@ */ import { Trigger } from '../../../../ui_actions/public'; +import { KibanaDatatable } from '../../../../expressions'; import { IEmbeddable } from '..'; export interface EmbeddableContext { embeddable: IEmbeddable; } -export interface EmbeddableVisTriggerContext { +interface EventData { + table: Pick; + column: number; + row: number; + value: any; +} + +export interface ValueClickTriggerContext { + embeddable?: IEmbeddable; + timeFieldName?: string; + data: EventData[]; + negate?: boolean; +} + +export interface RangeSelectTriggerContext { embeddable?: IEmbeddable; timeFieldName?: string; - data: unknown; + data: { + table: KibanaDatatable; + column: number; + range: number[]; + }; } export const CONTEXT_MENU_TRIGGER = 'CONTEXT_MENU_TRIGGER'; diff --git a/src/plugins/ui_actions/public/types.ts b/src/plugins/ui_actions/public/types.ts index c7e6d61e15f31..e6247a8bafff7 100644 --- a/src/plugins/ui_actions/public/types.ts +++ b/src/plugins/ui_actions/public/types.ts @@ -19,9 +19,10 @@ import { ActionByType } from './actions/action'; import { TriggerInternal } from './triggers/trigger_internal'; -import { EmbeddableVisTriggerContext, IEmbeddable } from '../../embeddable/public'; import { Filter } from '../../data/public'; import { SELECT_RANGE_TRIGGER, VALUE_CLICK_TRIGGER, APPLY_FILTER_TRIGGER } from './triggers'; +import { IEmbeddable } from '../../embeddable/public'; +import { RangeSelectTriggerContext, ValueClickTriggerContext } from '../../embeddable/public'; export type TriggerRegistry = Map>; export type ActionRegistry = Map>; @@ -36,8 +37,8 @@ export type TriggerContext = BaseContext; export interface TriggerContextMapping { [DEFAULT_TRIGGER]: TriggerContext; - [SELECT_RANGE_TRIGGER]: EmbeddableVisTriggerContext; - [VALUE_CLICK_TRIGGER]: EmbeddableVisTriggerContext; + [SELECT_RANGE_TRIGGER]: RangeSelectTriggerContext; + [VALUE_CLICK_TRIGGER]: ValueClickTriggerContext; [APPLY_FILTER_TRIGGER]: { embeddable: IEmbeddable; filters: Filter[]; diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts index ffb028ff131b3..851d58d411f79 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -33,7 +33,6 @@ import { EmbeddableInput, EmbeddableOutput, Embeddable, - EmbeddableVisTriggerContext, IContainer, } from '../../../../plugins/embeddable/public'; import { dispatchRenderComplete } from '../../../../plugins/kibana_utils/public'; @@ -261,10 +260,11 @@ export class VisualizeEmbeddable extends Embeddable { diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx index f12a0e5b907c7..6c1293eff3c30 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx @@ -28,7 +28,7 @@ import { import { EuiIcon, EuiText, IconType, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { EmbeddableVisTriggerContext } from '../../../../../src/plugins/embeddable/public'; +import { ValueClickTriggerContext } from '../../../../../src/plugins/embeddable/public'; import { VIS_EVENT_TO_TRIGGER } from '../../../../../src/plugins/visualizations/public'; import { LensMultiTable, FormatFactory } from '../types'; import { XYArgs, SeriesType, visualizationTypes } from './types'; @@ -277,15 +277,13 @@ export function XYChart({ const timeFieldName = xDomain && xAxisFieldName; - const context: EmbeddableVisTriggerContext = { - data: { - data: points.map(point => ({ - row: point.row, - column: point.column, - value: point.value, - table, - })), - }, + const context: ValueClickTriggerContext = { + data: points.map(point => ({ + row: point.row, + column: point.column, + value: point.value, + table, + })), timeFieldName, }; From 0553da9729c940433bb87dc7b288db4041fa42c5 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Tue, 21 Apr 2020 04:22:09 -0700 Subject: [PATCH 71/81] fixing types --- .../visualizations/public/embeddable/visualize_embeddable.ts | 3 +-- src/plugins/visualizations/public/expressions/vis.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts index 851d58d411f79..6a1f367f3965d 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -263,8 +263,7 @@ export class VisualizeEmbeddable extends Embeddable { From 6c223c363ed7859b9bebb43458e0250e292c02b5 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Tue, 21 Apr 2020 05:11:21 -0700 Subject: [PATCH 72/81] ... --- .../filters/create_filters_from_value_click.test.ts | 2 +- .../actions/filters/create_filters_from_value_click.ts | 2 +- src/plugins/data/public/actions/value_click_action.ts | 4 ++-- src/plugins/embeddable/public/lib/triggers/triggers.ts | 6 ++++-- .../public/embeddable/visualize_embeddable.ts | 2 +- src/plugins/visualizations/public/expressions/vis.ts | 7 ++++++- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts index 03ef949b52759..a0e285c20d776 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click.test.ts @@ -39,7 +39,7 @@ const mockField = { }; describe('createFiltersFromValueClick', () => { - let dataPoints: ValueClickTriggerContext['data']; + let dataPoints: ValueClickTriggerContext['data']['data']; beforeEach(() => { dataPoints = [ diff --git a/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts index a0ba3688a7000..2b426813a98a4 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts @@ -114,7 +114,7 @@ const createFilter = async ( export const createFiltersFromValueClickAction = async ({ data, negate, -}: ValueClickTriggerContext) => { +}: ValueClickTriggerContext['data']) => { const filters: Filter[] = []; await Promise.all( diff --git a/src/plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts index 6a39ab3650f6e..1141e485309cf 100644 --- a/src/plugins/data/public/actions/value_click_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -36,7 +36,7 @@ export type ValueClickActionContext = ValueClickTriggerContext; async function isCompatible(context: ValueClickActionContext) { try { - const filters: Filter[] = await createFiltersFromValueClickAction(context); + const filters: Filter[] = await createFiltersFromValueClickAction(context.data); return filters.length > 0; } catch { return false; @@ -61,7 +61,7 @@ export function valueClickAction( throw new IncompatibleActionError(); } - const filters: Filter[] = await createFiltersFromValueClickAction(context); + const filters: Filter[] = await createFiltersFromValueClickAction(context.data); let selectedFilters = filters; diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index 5120a85b06d9e..be25d9b1deecd 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -35,8 +35,10 @@ interface EventData { export interface ValueClickTriggerContext { embeddable?: IEmbeddable; timeFieldName?: string; - data: EventData[]; - negate?: boolean; + data: { + data: EventData[]; + negate?: boolean; + }; } export interface RangeSelectTriggerContext { diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts index 6a1f367f3965d..1c545bb36cff0 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -263,7 +263,7 @@ export class VisualizeEmbeddable extends Embeddable { From fc972f1e8baf561485aa5192fddc4a746494d920 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 21 Apr 2020 14:21:32 +0200 Subject: [PATCH 73/81] inline EventData --- .../embeddable/public/lib/triggers/triggers.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index be25d9b1deecd..da7be1eea199a 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -25,18 +25,16 @@ export interface EmbeddableContext { embeddable: IEmbeddable; } -interface EventData { - table: Pick; - column: number; - row: number; - value: any; -} - export interface ValueClickTriggerContext { embeddable?: IEmbeddable; timeFieldName?: string; data: { - data: EventData[]; + data: Array<{ + table: Pick; + column: number; + row: number; + value: any; + }>; negate?: boolean; }; } From d7cf94e8cce76b7f9d20038ffe9852da0bbc5fc2 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 21 Apr 2020 14:38:42 +0200 Subject: [PATCH 74/81] fix typescript in lens and update docs --- ...bana-plugin-plugins-data-public.fieldformats.md | 2 +- ...bana-plugin-plugins-data-server.fieldformats.md | 2 +- src/plugins/data/public/public.api.md | 2 +- src/plugins/data/server/server.api.md | 2 +- .../lens/public/xy_visualization/xy_expression.tsx | 14 ++++++++------ 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md index 244633c3c4c9e..d39871b99f744 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md @@ -10,7 +10,7 @@ fieldFormats: { FieldFormat: typeof FieldFormat; FieldFormatsRegistry: typeof FieldFormatsRegistry; - serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serialize: (agg: import("./search").AggConfig) => import("../../expressions").SerializedFieldFormat; DEFAULT_CONVERTER_COLOR: { range: string; regex: string; diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md index 2b986aee508e2..11f18a195d271 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md @@ -10,7 +10,7 @@ fieldFormats: { FieldFormatsRegistry: typeof FieldFormatsRegistry; FieldFormat: typeof FieldFormat; - serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions").SerializedFieldFormat; BoolFormat: typeof BoolFormat; BytesFormat: typeof BytesFormat; ColorFormat: typeof ColorFormat; diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index ac308251c1569..e51b737728344 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -485,7 +485,7 @@ export type FieldFormatId = FIELD_FORMAT_IDS | string; export const fieldFormats: { FieldFormat: typeof FieldFormat; FieldFormatsRegistry: typeof FieldFormatsRegistry; - serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serialize: (agg: import("./search").AggConfig) => import("../../expressions").SerializedFieldFormat; DEFAULT_CONVERTER_COLOR: { range: string; regex: string; diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index c41023eab6d20..f8a9a7792c492 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -283,7 +283,7 @@ export interface FieldFormatConfig { export const fieldFormats: { FieldFormatsRegistry: typeof FieldFormatsRegistry; FieldFormat: typeof FieldFormat; - serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions").SerializedFieldFormat; BoolFormat: typeof BoolFormat; BytesFormat: typeof BytesFormat; ColorFormat: typeof ColorFormat; diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx b/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx index 6c1293eff3c30..d6b6de479acfb 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/xy_expression.tsx @@ -278,12 +278,14 @@ export function XYChart({ const timeFieldName = xDomain && xAxisFieldName; const context: ValueClickTriggerContext = { - data: points.map(point => ({ - row: point.row, - column: point.column, - value: point.value, - table, - })), + data: { + data: points.map(point => ({ + row: point.row, + column: point.column, + value: point.value, + table, + })), + }, timeFieldName, }; From 4c9816e3bba1280940c8f0f69ac8c4521aa3df76 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 21 Apr 2020 16:01:24 +0200 Subject: [PATCH 75/81] improve filters types --- src/plugins/embeddable/public/index.ts | 2 ++ .../public/lib/triggers/triggers.ts | 12 ++++++-- .../drilldown.test.tsx | 4 +-- .../drilldown.tsx | 30 +++++++++++++++---- .../dashboard_to_dashboard_drilldown/types.ts | 7 +++-- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/plugins/embeddable/public/index.ts b/src/plugins/embeddable/public/index.ts index 00761fbb23c78..e61ad2a6eefed 100644 --- a/src/plugins/embeddable/public/index.ts +++ b/src/plugins/embeddable/public/index.ts @@ -67,6 +67,8 @@ export { withEmbeddableSubscription, SavedObjectEmbeddableInput, isSavedObjectEmbeddableInput, + isRangeSelectTriggerContext, + isValueClickTriggerContext, } from './lib'; export function plugin(initializerContext: PluginInitializerContext) { diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index 9eb3c6f88f783..617edf434c792 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -26,7 +26,7 @@ export interface EmbeddableContext { } export interface ValueClickTriggerContext { - embeddable?: IEmbeddable; + embeddable?: T; timeFieldName?: string; data: { data: Array<{ @@ -39,8 +39,12 @@ export interface ValueClickTriggerContext { }; } +export const isValueClickTriggerContext = ( + context: ValueClickTriggerContext | RangeSelectTriggerContext +): context is ValueClickTriggerContext => context.data && 'data' in context.data; + export interface RangeSelectTriggerContext { - embeddable?: IEmbeddable; + embeddable?: T; timeFieldName?: string; data: { table: KibanaDatatable; @@ -49,6 +53,10 @@ export interface RangeSelectTriggerContext }; } +export const isRangeSelectTriggerContext = ( + context: ValueClickTriggerContext | RangeSelectTriggerContext +): context is RangeSelectTriggerContext => context.data && 'range' in context.data; + export const CONTEXT_MENU_TRIGGER = 'CONTEXT_MENU_TRIGGER'; export const contextMenuTrigger: Trigger<'CONTEXT_MENU_TRIGGER'> = { id: CONTEXT_MENU_TRIGGER, diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx index e0276ec33d097..f76eef53e1cc5 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx @@ -109,9 +109,7 @@ describe('.execute() & getHref', () => { }; const context = ({ - data: { - range: useRangeEvent ? {} : undefined, - }, + data: useRangeEvent ? { range: {} } : { data: [] }, timeFieldName: 'order_date', embeddable: { getInput: () => ({ diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index 2bae9cc35865b..68aac6c2bd360 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -16,6 +16,10 @@ import { DrilldownDefinition as Drilldown } from '../../../../../drilldowns/publ import { txtGoToDashboard } from './i18n'; import { DataPublicPluginStart, esFilters } from '../../../../../../../src/plugins/data/public'; import { VisualizeEmbeddableContract } from '../../../../../../../src/plugins/visualizations/public'; +import { + isRangeSelectTriggerContext, + isValueClickTriggerContext, +} from '../../../../../../../src/plugins/embeddable/public'; export interface Params { getSavedObjectsClient: () => CoreStart['savedObjects']['client']; @@ -111,15 +115,29 @@ export class DashboardToDashboardDrilldown // for brush event this time range would be overwritten let timeRange = config.useCurrentDateRange ? currentTimeRange : undefined; let filtersFromEvent = await (async () => { - // TODO: not sure what would be the best way to handle types here - // context.data is `unknown` and comes from `EmbeddableVisTriggerContext` try { - return (context.data as any).range - ? await createFiltersFromRangeSelectAction(context.data as any) - : await createFiltersFromValueClickAction(context.data as any); + if (isRangeSelectTriggerContext(context)) + return await createFiltersFromRangeSelectAction(context.data); + if (isValueClickTriggerContext(context)) + return await createFiltersFromValueClickAction(context.data); + + // eslint-disable-next-line no-console + console.warn( + ` + DashboardToDashboard drilldown: can't extract filters from action. + Is it not supported action?`, + context + ); + + return []; } catch (e) { // eslint-disable-next-line no-console - console.warn("DashboardToDashboard drilldown: can't extract filters from event", e); + console.warn( + ` + DashboardToDashboard drilldown: error extracting filters from action. + Continuing without applying filters from event`, + e + ); return []; } })(); diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts index 6c5e66e3dfed4..530d48e216530 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts @@ -6,12 +6,15 @@ import { EmbeddableContext, - EmbeddableVisTriggerContext, + ValueClickTriggerContext, + RangeSelectTriggerContext, IEmbeddable, } from '../../../../../../../src/plugins/embeddable/public'; export type PlaceContext = EmbeddableContext; -export type ActionContext = EmbeddableVisTriggerContext; +export type ActionContext = + | ValueClickTriggerContext + | RangeSelectTriggerContext; export interface Config { dashboardId?: string; From 99327a8d6f02f8c8a4e50f8aff09026921f71366 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 21 Apr 2020 17:15:52 +0200 Subject: [PATCH 76/81] docs --- ...ibana-plugin-plugins-data-public.search.md | 3 +- src/plugins/data/public/public.api.md | 103 +++++++++--------- 2 files changed, 55 insertions(+), 51 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md index 78ac05b9fd386..9a22339fd0530 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md @@ -27,8 +27,9 @@ search: { InvalidEsCalendarIntervalError: typeof InvalidEsCalendarIntervalError; InvalidEsIntervalFormatError: typeof InvalidEsIntervalFormatError; isDateHistogramBucketAggConfig: typeof isDateHistogramBucketAggConfig; + isNumberType: (agg: import("./search").AggConfig) => boolean; isStringType: (agg: import("./search").AggConfig) => boolean; - isType: (type: string) => (agg: import("./search").AggConfig) => boolean; + isType: (...types: string[]) => (agg: import("./search").AggConfig) => boolean; isValidEsInterval: typeof isValidEsInterval; isValidInterval: typeof isValidInterval; parentPipelineType: string; diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index ff1502f5fdb7b..4d3f5e4483e82 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -6,7 +6,7 @@ import { $Values } from '@kbn/utility-types'; import _ from 'lodash'; -import { Action } from 'history'; +import { Action as Action_2 } from 'history'; import { ApplicationStart } from 'kibana/public'; import { Assign } from '@kbn/utility-types'; import { Breadcrumb } from '@elastic/eui'; @@ -54,7 +54,8 @@ import { Subscription } from 'rxjs'; import { Toast } from 'kibana/public'; import { ToastsStart } from 'kibana/public'; import { UiActionsSetup } from 'src/plugins/ui_actions/public'; -import { UiActionsStart } from 'src/plugins/ui_actions/public'; +import { UiActionsStart as UiActionsStart_2 } from 'src/plugins/ui_actions/public'; +import { UiComponent } from 'src/plugins/kibana_utils/public'; import { Unit } from '@elastic/datemath'; import { UnregisterCallback } from 'history'; import { UserProvidedValues } from 'src/core/server/types'; @@ -394,6 +395,7 @@ export const esFilters: { generateFilters: typeof generateFilters; onlyDisabledFiltersChanged: (newFilters?: import("../common").Filter[] | undefined, oldFilters?: import("../common").Filter[] | undefined) => boolean; changeTimeFilter: typeof changeTimeFilter; + convertRangeFilterToTimeRangeString: typeof convertRangeFilterToTimeRangeString; mapAndFlattenFilters: (filters: import("../common").Filter[]) => import("../common").Filter[]; extractTimeFilter: typeof extractTimeFilter; }; @@ -1843,54 +1845,55 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/common/es_query/filters/match_all_filter.ts:28:3 - (ae-forgotten-export) The symbol "MatchAllFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrase_filter.ts:33:3 - (ae-forgotten-export) The symbol "PhraseFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrases_filter.ts:31:3 - (ae-forgotten-export) The symbol "PhrasesFilterMeta" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "FilterLabel" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "generateFilters" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:391:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:407:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:410:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:414:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FilterLabel" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "generateFilters" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "convertRangeFilterToTimeRangeString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:385:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:385:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:385:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:385:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:391:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:393:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:403:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:404:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:413:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:416:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts From aca9c8a94953eaf918e4a73d7c6d4a297919f3bd Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 22 Apr 2020 11:05:28 +0200 Subject: [PATCH 77/81] merge --- src/plugins/embeddable/public/lib/triggers/triggers.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index 2366b7db0a11f..c097e3e8c13be 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -17,6 +17,7 @@ * under the License. */ +import { KibanaDatatable } from '../../../../expressions'; import { Trigger } from '../../../../ui_actions/public'; import { IEmbeddable } from '..'; From 8566cbcc227207de7bbe75c6a9cda31b6ba1a4fe Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 22 Apr 2020 13:28:06 +0200 Subject: [PATCH 78/81] @mdefazio review --- .../components/dashboard_drilldown_config/i18n.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/i18n.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/i18n.ts index 5bd6b3b262e20..a37f2bfa01bd4 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/i18n.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/i18n.ts @@ -16,13 +16,13 @@ export const txtChooseDestinationDashboard = i18n.translate( export const txtUseCurrentFilters = i18n.translate( 'xpack.dashboard.components.DashboardDrilldownConfig.useCurrentFilters', { - defaultMessage: "Use origin dashboard's filters and query", + defaultMessage: 'Use filters and query from origin dashboard', } ); export const txtUseCurrentDateRange = i18n.translate( 'xpack.dashboard.components.DashboardDrilldownConfig.useCurrentDateRange', { - defaultMessage: "Use origin dashboard's date range", + defaultMessage: 'Use date range from origin dashboard', } ); From 218d66fbfa3c93638fe524c79207fdf81f8fb8db Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 22 Apr 2020 18:27:46 +0200 Subject: [PATCH 79/81] adjust actions order --- .../dashboard/public/application/actions/clone_panel_action.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx index 869646a653ee4..ff4e50ba8c327 100644 --- a/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx +++ b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx @@ -39,7 +39,7 @@ export interface ClonePanelActionContext { export class ClonePanelAction implements ActionByType { public readonly type = ACTION_CLONE_PANEL; public readonly id = ACTION_CLONE_PANEL; - public order = 4; + public order = 45; constructor(private core: CoreStart) {} From 0997398f3fef76a61238d74afdc52b25ae928fbc Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 23 Apr 2020 14:10:10 +0200 Subject: [PATCH 80/81] docs --- src/plugins/data/public/public.api.md | 98 ++++++++++++++------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 59f56d3983b35..1e94ec7051788 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -392,6 +392,7 @@ export const esFilters: { generateFilters: typeof generateFilters; onlyDisabledFiltersChanged: (newFilters?: import("../common").Filter[] | undefined, oldFilters?: import("../common").Filter[] | undefined) => boolean; changeTimeFilter: typeof changeTimeFilter; + convertRangeFilterToTimeRangeString: typeof convertRangeFilterToTimeRangeString; mapAndFlattenFilters: (filters: import("../common").Filter[]) => import("../common").Filter[]; extractTimeFilter: typeof extractTimeFilter; }; @@ -1786,54 +1787,55 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/common/es_query/filters/match_all_filter.ts:28:3 - (ae-forgotten-export) The symbol "MatchAllFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrase_filter.ts:33:3 - (ae-forgotten-export) The symbol "PhraseFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrases_filter.ts:31:3 - (ae-forgotten-export) The symbol "PhrasesFilterMeta" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "FilterLabel" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "generateFilters" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:381:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:381:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:381:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:381:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:386:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:387:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:398:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:399:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:404:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FilterLabel" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "generateFilters" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "convertRangeFilterToTimeRangeString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "FieldFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:391:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:407:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:410:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:414:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts From 8ec37f5b87648b317e9b6e8d9db41ff5fbe59d3b Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 24 Apr 2020 07:16:26 +0200 Subject: [PATCH 81/81] @stacey-gammon review --- .../flyout_create_drilldown/flyout_create_drilldown.tsx | 2 +- .../actions/flyout_edit_drilldown/flyout_edit_drilldown.tsx | 2 +- .../components/collect_config_container.tsx | 6 +++--- .../dashboard_drilldown_config.tsx | 2 +- .../dashboard_to_dashboard_drilldown/drilldown.test.tsx | 2 +- .../test/functional/services/dashboard/drilldowns_manage.ts | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx index da4d683043290..20eaba9178634 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx @@ -71,7 +71,7 @@ export class FlyoutCreateDrilldownAction implements ActionByType; - error: string | null; + error?: string; } export class CollectConfigContainer extends React.Component< @@ -62,7 +62,7 @@ export class CollectConfigContainer extends React.Component< isLoading: false, searchString: undefined, selectedDashboard: undefined, - error: null, + error: undefined, }; constructor(props: CollectConfigProps) { @@ -94,7 +94,7 @@ export class CollectConfigContainer extends React.Component< onDashboardSelect={dashboardId => { onConfig({ ...config, dashboardId }); if (this.state.error) { - this.setState({ error: null }); + this.setState({ error: undefined }); } }} onSearchChange={this.debouncedLoadDashboards} diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx index ac74f4718cc2b..a41a5fb718219 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/components/dashboard_drilldown_config/dashboard_drilldown_config.tsx @@ -22,7 +22,7 @@ export interface DashboardDrilldownConfigProps { onKeepRangeToggle?: () => void; onSearchChange: (searchString: string) => void; isLoading: boolean; - error?: string | null; + error?: string; } export const DashboardDrilldownConfig: React.FC = ({ diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx index b671edf37a175..8b69b20cac3e3 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.test.tsx @@ -164,7 +164,7 @@ describe('.execute() & getHref', () => { expect(href).toEqual(expect.stringContaining(`dashboard/${testDashboardId}`)); }); - test('query is removed with query if filters are disabled', async () => { + test('query is removed if filters are disabled', async () => { const queryString = 'querystring'; const queryLanguage = 'kuery'; const { href } = await setupTestBed( diff --git a/x-pack/test/functional/services/dashboard/drilldowns_manage.ts b/x-pack/test/functional/services/dashboard/drilldowns_manage.ts index a8711e9230adb..1710cb8bfb71a 100644 --- a/x-pack/test/functional/services/dashboard/drilldowns_manage.ts +++ b/x-pack/test/functional/services/dashboard/drilldowns_manage.ts @@ -6,8 +6,8 @@ import { FtrProviderContext } from '../../ftr_provider_context'; -const CREATE_DRILLDOWN_FLYOUT_DATA_TEST_SUBJ = 'dashboardCreateDrilldownFlyout'; -const MANAGE_DRILLDOWNS_FLYOUT_DATA_TEST_SUBJ = 'dashboardEditDrilldownFlyout'; +const CREATE_DRILLDOWN_FLYOUT_DATA_TEST_SUBJ = 'createDrilldownFlyout'; +const MANAGE_DRILLDOWNS_FLYOUT_DATA_TEST_SUBJ = 'editDrilldownFlyout'; const DASHBOARD_TO_DASHBOARD_ACTION_LIST_ITEM = 'actionFactoryItem-DASHBOARD_TO_DASHBOARD_DRILLDOWN'; const DASHBOARD_TO_DASHBOARD_ACTION_WIZARD =