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 37142cf1794c32..bc34d4113f847b 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 @@ -52,5 +52,6 @@ esFilters: { convertRangeFilterToTimeRangeString: typeof convertRangeFilterToTimeRangeString; mapAndFlattenFilters: (filters: import("../common").Filter[]) => import("../common").Filter[]; extractTimeFilter: typeof extractTimeFilter; + extractTimeRange: typeof extractTimeRange; } ``` diff --git a/src/plugins/dashboard/public/index.ts b/src/plugins/dashboard/public/index.ts index 17968dd0281e6c..dcfde67cd9f131 100644 --- a/src/plugins/dashboard/public/index.ts +++ b/src/plugins/dashboard/public/index.ts @@ -32,7 +32,11 @@ export { export { DashboardConstants, createDashboardEditUrl } from './dashboard_constants'; export { DashboardStart, DashboardUrlGenerator } from './plugin'; -export { DASHBOARD_APP_URL_GENERATOR, createDashboardUrlGenerator } from './url_generator'; +export { + DASHBOARD_APP_URL_GENERATOR, + createDashboardUrlGenerator, + DashboardUrlGeneratorState, +} from './url_generator'; export { addEmbeddableToDashboardUrl } from './url_utils/url_helper'; export { SavedObjectDashboard } from './saved_dashboards'; export { SavedDashboardPanel } from './types'; diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index 041a02a251e8ab..f0b57fec169fd2 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -65,6 +65,7 @@ import { ACTION_REPLACE_PANEL, ClonePanelAction, ClonePanelActionContext, + createDashboardContainerByValueRenderer, DASHBOARD_CONTAINER_TYPE, DashboardContainerFactory, DashboardContainerFactoryDefinition, @@ -77,17 +78,17 @@ import { import { createDashboardUrlGenerator, DASHBOARD_APP_URL_GENERATOR, - DashboardAppLinkGeneratorState, + DashboardUrlGeneratorState, } from './url_generator'; import { createSavedDashboardLoader } from './saved_dashboards'; import { DashboardConstants } from './dashboard_constants'; import { addEmbeddableToDashboardUrl } from './url_utils/url_helper'; import { PlaceholderEmbeddableFactory } from './application/embeddable/placeholder'; -import { createDashboardContainerByValueRenderer } from './application'; +import { UrlGeneratorState } from '../../share/public'; declare module '../../share/public' { export interface UrlGeneratorStateMapping { - [DASHBOARD_APP_URL_GENERATOR]: DashboardAppLinkGeneratorState; + [DASHBOARD_APP_URL_GENERATOR]: UrlGeneratorState; } } diff --git a/src/plugins/dashboard/public/url_generator.ts b/src/plugins/dashboard/public/url_generator.ts index 188de7fd857be8..68a50396e00d69 100644 --- a/src/plugins/dashboard/public/url_generator.ts +++ b/src/plugins/dashboard/public/url_generator.ts @@ -26,7 +26,7 @@ import { RefreshInterval, } from '../../data/public'; import { setStateToKbnUrl } from '../../kibana_utils/public'; -import { UrlGeneratorsDefinition, UrlGeneratorState } from '../../share/public'; +import { UrlGeneratorsDefinition } from '../../share/public'; import { SavedObjectLoader } from '../../saved_objects/public'; import { ViewMode } from '../../embeddable/public'; @@ -35,7 +35,7 @@ export const GLOBAL_STATE_STORAGE_KEY = '_g'; export const DASHBOARD_APP_URL_GENERATOR = 'DASHBOARD_APP_URL_GENERATOR'; -export type DashboardAppLinkGeneratorState = UrlGeneratorState<{ +export interface DashboardUrlGeneratorState { /** * If given, the dashboard saved object with this id will be loaded. If not given, * a new, unsaved dashboard will be loaded up. @@ -79,7 +79,7 @@ export type DashboardAppLinkGeneratorState = UrlGeneratorState<{ * View mode of the dashboard. */ viewMode?: ViewMode; -}>; +} export const createDashboardUrlGenerator = ( getStartServices: () => Promise<{ diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 846471420327fa..e95150e8f6f732 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -58,6 +58,7 @@ import { changeTimeFilter, mapAndFlattenFilters, extractTimeFilter, + extractTimeRange, convertRangeFilterToTimeRangeString, } from './query'; @@ -99,6 +100,7 @@ export const esFilters = { convertRangeFilterToTimeRangeString, mapAndFlattenFilters, extractTimeFilter, + extractTimeRange, }; export { diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index a8868c07061c3b..65670bc1cf83e6 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -499,6 +499,7 @@ export const esFilters: { convertRangeFilterToTimeRangeString: typeof convertRangeFilterToTimeRangeString; mapAndFlattenFilters: (filters: import("../common").Filter[]) => import("../common").Filter[]; extractTimeFilter: typeof extractTimeFilter; + extractTimeRange: typeof extractTimeRange; }; // Warning: (ae-missing-release-tag) "esKuery" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1973,52 +1974,53 @@ export const UI_SETTINGS: { // 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 "convertRangeFilterToTimeRangeString" 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:136:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:136:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:136:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:136:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:176:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:232:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:369:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:369:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:369:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:369:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:371:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:372:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:381:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:382:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:384:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:392:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:393:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:396: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:66:23 - (ae-forgotten-export) The symbol "extractTimeRange" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:138:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:138:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:138:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:138:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:178: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 "formatHitProvider" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:371:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:371:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:371:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:371:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:373:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:374:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:383:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:385:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:386:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:391:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:394:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:395:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:398: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:41:60 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:54:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:55:5 - (ae-forgotten-export) The symbol "createFiltersFromRangeSelectAction" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/data/public/query/timefilter/index.ts b/src/plugins/data/public/query/timefilter/index.ts index 19386c10ab59fd..dc9a4ef8c21a67 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 { changeTimeFilter, convertRangeFilterToTimeRangeString } from './lib/change_time_filter'; -export { extractTimeFilter } from './lib/extract_time_filter'; +export { extractTimeFilter, extractTimeRange } from './lib/extract_time_filter'; export { validateTimeRange } from './lib/validate_timerange'; diff --git a/src/plugins/data/public/query/timefilter/lib/extract_time_filter.ts b/src/plugins/data/public/query/timefilter/lib/extract_time_filter.ts index 23dd1547baf10b..2f93196e3218b9 100644 --- a/src/plugins/data/public/query/timefilter/lib/extract_time_filter.ts +++ b/src/plugins/data/public/query/timefilter/lib/extract_time_filter.ts @@ -18,7 +18,8 @@ */ import { keys, partition } from 'lodash'; -import { Filter, isRangeFilter, RangeFilter } from '../../../../common'; +import { Filter, isRangeFilter, RangeFilter, TimeRange } from '../../../../common'; +import { convertRangeFilterToTimeRangeString } from './change_time_filter'; export function extractTimeFilter(timeFieldName: string, filters: Filter[]) { const [timeRangeFilter, restOfFilters] = partition(filters, (obj: Filter) => { @@ -36,3 +37,15 @@ export function extractTimeFilter(timeFieldName: string, filters: Filter[]) { timeRangeFilter: timeRangeFilter[0] as RangeFilter | undefined, }; } + +export function extractTimeRange( + filters: Filter[], + timeFieldName?: string +): { restOfFilters: Filter[]; timeRange?: TimeRange } { + if (!timeFieldName) return { restOfFilters: filters, timeRange: undefined }; + const { timeRangeFilter, restOfFilters } = extractTimeFilter(timeFieldName, filters); + return { + restOfFilters, + timeRange: timeRangeFilter ? convertRangeFilterToTimeRangeString(timeRangeFilter) : undefined, + }; +} diff --git a/x-pack/plugins/dashboard_enhanced/kibana.json b/x-pack/plugins/dashboard_enhanced/kibana.json index ba5d8052ca7876..264fa0438ea118 100644 --- a/x-pack/plugins/dashboard_enhanced/kibana.json +++ b/x-pack/plugins/dashboard_enhanced/kibana.json @@ -8,6 +8,7 @@ "requiredBundles": [ "kibanaUtils", "embeddableEnhanced", - "kibanaReact" + "kibanaReact", + "uiActions" ] } 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 4804a700c6cff3..2de862a6708a81 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 @@ -6,7 +6,12 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { ActionByType } from '../../../../../../../../src/plugins/ui_actions/public'; +import { + ActionByType, + APPLY_FILTER_TRIGGER, + SELECT_RANGE_TRIGGER, + VALUE_CLICK_TRIGGER, +} from '../../../../../../../../src/plugins/ui_actions/public'; import { toMountPoint } from '../../../../../../../../src/plugins/kibana_react/public'; import { isEnhancedEmbeddable } from '../../../../../../embeddable_enhanced/public'; import { EmbeddableContext } from '../../../../../../../../src/plugins/embeddable/public'; @@ -42,7 +47,9 @@ export class FlyoutCreateDrilldownAction implements ActionByType -1; + return supportedTriggers.some((trigger) => + [VALUE_CLICK_TRIGGER, SELECT_RANGE_TRIGGER, APPLY_FILTER_TRIGGER].includes(trigger) + ); } public async isCompatible(context: EmbeddableContext) { diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/constants.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/constants.ts index e2a530b156da5c..daefcf2d68cc53 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/constants.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/constants.ts @@ -4,4 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ +/** + * note: + * don't change this string without carefull consideration, + * because it is stored in saved objects. + * Also temporary dashboard drilldown migration code inside embeddable plugin relies on it + * x-pack/plugins/embeddable_enhanced/public/embeddables/embeddable_action_storage.ts + */ export const DASHBOARD_TO_DASHBOARD_DRILLDOWN = 'DASHBOARD_TO_DASHBOARD_DRILLDOWN'; 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 52b232afa9410f..40fa469feb34b8 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 @@ -5,9 +5,8 @@ */ import { DashboardToDashboardDrilldown } from './drilldown'; -import { savedObjectsServiceMock, coreMock } from '../../../../../../../src/core/public/mocks'; -import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; -import { ActionContext, Config } from './types'; +import { Config } from './types'; +import { coreMock, savedObjectsServiceMock } from '../../../../../../../src/core/public/mocks'; import { Filter, FilterStateStore, @@ -15,16 +14,13 @@ import { RangeFilter, TimeRange, } from '../../../../../../../src/plugins/data/common'; -import { esFilters } from '../../../../../../../src/plugins/data/public'; - +import { + ApplyGlobalFilterActionContext, + esFilters, +} from '../../../../../../../src/plugins/data/public'; // convenient to use real implementation here. import { createDashboardUrlGenerator } from '../../../../../../../src/plugins/dashboard/public/url_generator'; import { UrlGeneratorsService } from '../../../../../../../src/plugins/share/public/url_generators'; -import { VisualizeEmbeddableContract } from '../../../../../../../src/plugins/visualizations/public'; -import { - RangeSelectContext, - ValueClickContext, -} from '../../../../../../../src/plugins/embeddable/public'; import { StartDependencies } from '../../../plugin'; import { SavedObjectLoader } from '../../../../../../../src/plugins/saved_objects/public'; import { StartServicesGetter } from '../../../../../../../src/plugins/kibana_utils/public/core'; @@ -82,11 +78,10 @@ describe('.execute() & getHref', () => { config: Partial, embeddableInput: { filters?: Filter[]; timeRange?: TimeRange; query?: Query }, filtersFromEvent: Filter[], - useRangeEvent = false + timeFieldName?: string ) { 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({ @@ -102,9 +97,6 @@ describe('.execute() & getHref', () => { }, plugins: { uiActionsEnhanced: {}, - data: { - actions: dataPluginActions, - }, }, self: {}, })) as unknown) as StartServicesGetter>, @@ -119,12 +111,6 @@ describe('.execute() & getHref', () => { ) ), }); - const selectRangeFiltersSpy = jest - .spyOn(dataPluginActions, 'createFiltersFromRangeSelectAction') - .mockImplementation(() => Promise.resolve(filtersFromEvent)); - const valueClickFiltersSpy = jest - .spyOn(dataPluginActions, 'createFiltersFromValueClickAction') - .mockImplementation(() => Promise.resolve(filtersFromEvent)); const completeConfig: Config = { dashboardId: 'id', @@ -134,12 +120,7 @@ describe('.execute() & getHref', () => { }; const context = ({ - data: { - ...(useRangeEvent - ? ({ range: {} } as RangeSelectContext['data']) - : ({ data: [] } as ValueClickContext['data'])), - timeFieldName: 'order_date', - }, + filters: filtersFromEvent, embeddable: { getInput: () => ({ filters: [], @@ -148,18 +129,11 @@ describe('.execute() & getHref', () => { ...embeddableInput, }), }, - } as unknown) as ActionContext; + timeFieldName, + } as unknown) as ApplyGlobalFilterActionContext; await drilldown.execute(completeConfig, context); - 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('dashboards'); @@ -180,8 +154,7 @@ describe('.execute() & getHref', () => { dashboardId: testDashboardId, }, {}, - [], - false + [] ); expect(href).toEqual(expect.stringContaining(`view/${testDashboardId}`)); @@ -289,8 +262,7 @@ describe('.execute() & getHref', () => { to: 'now', }, }, - [], - false + [] ); expect(href).not.toEqual(expect.stringContaining('now-300m')); @@ -308,7 +280,7 @@ describe('.execute() & getHref', () => { }, }, [getMockTimeRangeFilter()], - true + getMockTimeRangeFilter().meta.key ); expect(href).not.toEqual(expect.stringContaining('now-300m')); 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 26a69132cffb17..703acbc8d9d59c 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 @@ -6,20 +6,24 @@ import React from 'react'; import { reactToUiComponent } from '../../../../../../../src/plugins/kibana_react/public'; -import { DashboardUrlGenerator } from '../../../../../../../src/plugins/dashboard/public'; -import { ActionContext, Config } from './types'; +import { + DashboardUrlGenerator, + DashboardUrlGeneratorState, +} from '../../../../../../../src/plugins/dashboard/public'; import { CollectConfigContainer } from './components'; import { DASHBOARD_TO_DASHBOARD_DRILLDOWN } from './constants'; import { UiActionsEnhancedDrilldownDefinition as Drilldown } from '../../../../../ui_actions_enhanced/public'; import { txtGoToDashboard } from './i18n'; -import { esFilters } from '../../../../../../../src/plugins/data/public'; -import { VisualizeEmbeddableContract } from '../../../../../../../src/plugins/visualizations/public'; import { - isRangeSelectTriggerContext, - isValueClickTriggerContext, -} from '../../../../../../../src/plugins/embeddable/public'; + ApplyGlobalFilterActionContext, + esFilters, + isFilters, + isQuery, + isTimeRange, +} from '../../../../../../../src/plugins/data/public'; import { StartServicesGetter } from '../../../../../../../src/plugins/kibana_utils/public'; import { StartDependencies } from '../../../plugin'; +import { Config } from './types'; export interface Params { start: StartServicesGetter>; @@ -27,7 +31,7 @@ export interface Params { } export class DashboardToDashboardDrilldown - implements Drilldown> { + implements Drilldown { constructor(protected readonly params: Params) {} public readonly id = DASHBOARD_TO_DASHBOARD_DRILLDOWN; @@ -57,15 +61,12 @@ export class DashboardToDashboardDrilldown public readonly getHref = async ( config: Config, - context: ActionContext + context: ApplyGlobalFilterActionContext ): Promise => { return this.getDestinationUrl(config, context); }; - public readonly execute = async ( - config: Config, - context: ActionContext - ) => { + public readonly execute = async (config: Config, context: ApplyGlobalFilterActionContext) => { const dashboardPath = await this.getDestinationUrl(config, context); const dashboardHash = dashboardPath.split('#')[1]; @@ -76,73 +77,43 @@ export class DashboardToDashboardDrilldown private getDestinationUrl = async ( config: Config, - context: ActionContext + context: ApplyGlobalFilterActionContext ): Promise => { + const state: DashboardUrlGeneratorState = { + dashboardId: config.dashboardId, + }; + + if (context.embeddable) { + const input = context.embeddable.getInput(); + if (isQuery(input.query) && config.useCurrentFilters) state.query = input.query; + + // 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 + if (isTimeRange(input.timeRange) && config.useCurrentDateRange) + state.timeRange = input.timeRange; + + // if useCurrentDashboardFilters enabled, then preserve all the filters (pinned and unpinned) + // otherwise preserve only pinned + if (isFilters(input.filters)) + state.filters = config.useCurrentFilters + ? input.filters + : input.filters?.filter((f) => esFilters.isFilterPinned(f)); + } + const { - createFiltersFromRangeSelectAction, - createFiltersFromValueClickAction, - } = this.params.start().plugins.data.actions; - 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 existingFilters = - (config.useCurrentFilters - ? 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.useCurrentDateRange ? currentTimeRange : undefined; - let filtersFromEvent = await (async () => { - try { - 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: error extracting filters from action. - Continuing without applying filters from event`, - e - ); - return []; - } - })(); - - if (context.data.timeFieldName) { - const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( - context.data.timeFieldName, - filtersFromEvent - ); - filtersFromEvent = restOfFilters; - if (timeRangeFilter) { - timeRange = esFilters.convertRangeFilterToTimeRangeString(timeRangeFilter); - } + restOfFilters: filtersFromEvent, + timeRange: timeRangeFromEvent, + } = esFilters.extractTimeRange(context.filters, context.timeFieldName); + + if (filtersFromEvent) { + state.filters = [...(state.filters ?? []), ...filtersFromEvent]; } - return this.params.getDashboardUrlGenerator().createUrl({ - dashboardId: config.dashboardId, - query: config.useCurrentFilters ? query : undefined, - timeRange, - filters: [...existingFilters, ...filtersFromEvent], - }); + if (timeRangeFromEvent) { + state.timeRange = timeRangeFromEvent; + } + + return this.params.getDashboardUrlGenerator().createUrl(state); }; } diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/index.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/index.ts index 914f34980a2722..49065a96b4f7b3 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/index.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/index.ts @@ -9,7 +9,4 @@ export { DashboardToDashboardDrilldown, Params as DashboardToDashboardDrilldownParams, } from './drilldown'; -export { - ActionContext as DashboardToDashboardActionContext, - Config as DashboardToDashboardConfig, -} from './types'; +export { Config } from './types'; 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 6be2e2a77269fc..426e250499de02 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,16 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - ValueClickContext, - RangeSelectContext, - IEmbeddable, -} from '../../../../../../../src/plugins/embeddable/public'; - -export type ActionContext = - | ValueClickContext - | RangeSelectContext; - export interface Config { dashboardId?: string; useCurrentFilters: boolean; diff --git a/x-pack/plugins/embeddable_enhanced/public/embeddables/embeddable_action_storage.test.ts b/x-pack/plugins/embeddable_enhanced/public/embeddables/embeddable_action_storage.test.ts index 5c5d98d75295de..fffb75451f8ac7 100644 --- a/x-pack/plugins/embeddable_enhanced/public/embeddables/embeddable_action_storage.test.ts +++ b/x-pack/plugins/embeddable_enhanced/public/embeddables/embeddable_action_storage.test.ts @@ -11,6 +11,9 @@ import { } from './embeddable_action_storage'; import { UiActionsEnhancedSerializedEvent } from '../../../ui_actions_enhanced/public'; import { of } from '../../../../../src/plugins/kibana_utils/public'; +// use real const to make test fail in case someone accidentally changes it +import { DASHBOARD_TO_DASHBOARD_DRILLDOWN } from '../../../dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown'; +import { APPLY_FILTER_TRIGGER } from '../../../../../src/plugins/ui_actions/public'; class TestEmbeddable extends Embeddable { public readonly type = 'test'; @@ -539,4 +542,42 @@ describe('EmbeddableActionStorage', () => { expect(await storage.list()).toEqual([]); }); }); + + describe('migrate', () => { + test('DASHBOARD_TO_DASHBOARD_DRILLDOWN triggers migration', async () => { + const embeddable = new TestEmbeddable(); + const OTHER_TRIGGER = 'OTHER_TRIGGER'; + embeddable.updateInput({ + enhancements: { + dynamicActions: { + events: [ + { + eventId: '1', + triggers: [OTHER_TRIGGER], + action: { + factoryId: DASHBOARD_TO_DASHBOARD_DRILLDOWN, + name: '', + config: {}, + }, + }, + { + eventId: '2', + triggers: [OTHER_TRIGGER], + action: { + factoryId: 'SOME_OTHER', + name: '', + config: {}, + }, + }, + ], + }, + }, + }); + const storage = new EmbeddableActionStorage(embeddable); + + const [event1, event2] = await storage.list(); + expect(event1.triggers).toEqual([APPLY_FILTER_TRIGGER]); + expect(event2.triggers).toEqual([OTHER_TRIGGER]); + }); + }); }); diff --git a/x-pack/plugins/embeddable_enhanced/public/embeddables/embeddable_action_storage.ts b/x-pack/plugins/embeddable_enhanced/public/embeddables/embeddable_action_storage.ts index fdc42585a80ce3..8881b2063c8db3 100644 --- a/x-pack/plugins/embeddable_enhanced/public/embeddables/embeddable_action_storage.ts +++ b/x-pack/plugins/embeddable_enhanced/public/embeddables/embeddable_action_storage.ts @@ -46,7 +46,7 @@ export class EmbeddableActionStorage extends AbstractActionStorage { public async create(event: SerializedEvent) { const input = this.embbeddable.getInput(); - const events = input.enhancements?.dynamicActions?.events || []; + const events = this.getEventsFromEmbeddable(); const exists = !!events.find(({ eventId }) => eventId === event.eventId); if (exists) { @@ -61,7 +61,7 @@ export class EmbeddableActionStorage extends AbstractActionStorage { public async update(event: SerializedEvent) { const input = this.embbeddable.getInput(); - const events = input.enhancements?.dynamicActions?.events || []; + const events = this.getEventsFromEmbeddable(); const index = events.findIndex(({ eventId }) => eventId === event.eventId); if (index === -1) { @@ -77,7 +77,7 @@ export class EmbeddableActionStorage extends AbstractActionStorage { public async remove(eventId: string) { const input = this.embbeddable.getInput(); - const events = input.enhancements?.dynamicActions?.events || []; + const events = this.getEventsFromEmbeddable(); const index = events.findIndex((event) => eventId === event.eventId); if (index === -1) { @@ -93,7 +93,7 @@ export class EmbeddableActionStorage extends AbstractActionStorage { public async read(eventId: string): Promise { const input = this.embbeddable.getInput(); - const events = input.enhancements?.dynamicActions?.events || []; + const events = this.getEventsFromEmbeddable(); const event = events.find((ev) => eventId === ev.eventId); if (!event) { @@ -107,8 +107,28 @@ export class EmbeddableActionStorage extends AbstractActionStorage { } public async list(): Promise { + return this.getEventsFromEmbeddable(); + } + + private getEventsFromEmbeddable() { const input = this.embbeddable.getInput(); const events = input.enhancements?.dynamicActions?.events || []; - return events; + return this.migrate(events); + } + + // TODO: https://github.com/elastic/kibana/issues/71431 + // Migration implementation should use registry + // Action factories implementations should register own migrations + private migrate(events: SerializedEvent[]): SerializedEvent[] { + return events.map((event) => { + // Initially dashboard drilldown relied on VALUE_CLICK & RANGE_SELECT + if (event.action.factoryId === 'DASHBOARD_TO_DASHBOARD_DRILLDOWN') { + return { + ...event, + triggers: ['FILTER_TRIGGER'], + }; + } + return event; + }); } } diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/components/connected_flyout_manage_drilldowns/connected_flyout_manage_drilldowns.tsx b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/components/connected_flyout_manage_drilldowns/connected_flyout_manage_drilldowns.tsx index 20d15b4f4d2bd3..283464b137ff9b 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/components/connected_flyout_manage_drilldowns/connected_flyout_manage_drilldowns.tsx +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/components/connected_flyout_manage_drilldowns/connected_flyout_manage_drilldowns.tsx @@ -11,9 +11,8 @@ import { DrilldownWizardConfig, FlyoutDrilldownWizard } from '../flyout_drilldow import { FlyoutListManageDrilldowns } from '../flyout_list_manage_drilldowns'; import { IStorageWrapper } from '../../../../../../../src/plugins/kibana_utils/public'; import { - VALUE_CLICK_TRIGGER, - SELECT_RANGE_TRIGGER, TriggerContextMapping, + APPLY_FILTER_TRIGGER, } from '../../../../../../../src/plugins/ui_actions/public'; import { useContainerState } from '../../../../../../../src/plugins/kibana_utils/public'; import { DrilldownListItem } from '../list_manage_drilldowns'; @@ -67,8 +66,9 @@ export function createFlyoutManageDrilldowns({ return (props: ConnectedFlyoutManageDrilldownsProps) => { const isCreateOnly = props.viewMode === 'create'; + // TODO: https://github.com/elastic/kibana/issues/59569 const selectedTriggers: Array = React.useMemo( - () => [VALUE_CLICK_TRIGGER, SELECT_RANGE_TRIGGER], + () => [APPLY_FILTER_TRIGGER], [] );