{
private readonly embeddableFactories: EmbeddableFactoryRegistry = new Map();
private readonly enhancements: EnhancementsRegistry = new Map();
public setup(core: CoreSetup) {
+ const commonContract = {
+ getEmbeddableFactory: this.getEmbeddableFactory,
+ getEnhancement: this.getEnhancement,
+ };
return {
registerEmbeddableFactory: this.registerEmbeddableFactory,
registerEnhancement: this.registerEnhancement,
+ telemetry: getTelemetryFunction(commonContract),
+ extract: getExtractFunction(commonContract),
+ inject: getInjectFunction(commonContract),
+ migrate: getMigrateFunction(commonContract),
};
}
diff --git a/src/plugins/embeddable/server/server.api.md b/src/plugins/embeddable/server/server.api.md
index 87f7d76cffaa..d3921ab11457 100644
--- a/src/plugins/embeddable/server/server.api.md
+++ b/src/plugins/embeddable/server/server.api.md
@@ -18,12 +18,11 @@ export interface EmbeddableRegistryDefinition {
// (undocumented)
registerEmbeddableFactory: (factory: EmbeddableRegistryDefinition) => void;
// (undocumented)
diff --git a/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/constants.ts b/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/constants.ts
new file mode 100644
index 000000000000..922ec36619a4
--- /dev/null
+++ b/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/constants.ts
@@ -0,0 +1,14 @@
+/*
+ * 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.
+ */
+
+/**
+ * NOTE: DO NOT CHANGE THIS STRING WITHOUT CAREFUL CONSIDERATOIN, 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 EMBEDDABLE_TO_DASHBOARD_DRILLDOWN = 'DASHBOARD_TO_DASHBOARD_DRILLDOWN';
diff --git a/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/dashboard_drilldown_persistable_state.test.ts b/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/dashboard_drilldown_persistable_state.test.ts
new file mode 100644
index 000000000000..dd890b246322
--- /dev/null
+++ b/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/dashboard_drilldown_persistable_state.test.ts
@@ -0,0 +1,48 @@
+/*
+ * 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 { createExtract, createInject } from './dashboard_drilldown_persistable_state';
+import { SerializedEvent } from '../../../../ui_actions_enhanced/common';
+
+const drilldownId = 'test_id';
+const extract = createExtract({ drilldownId });
+const inject = createInject({ drilldownId });
+
+const state: SerializedEvent = {
+ eventId: 'event_id',
+ triggers: [],
+ action: {
+ factoryId: drilldownId,
+ name: 'name',
+ config: {
+ dashboardId: 'dashboardId_1',
+ },
+ },
+};
+
+test('should extract and injected dashboard reference', () => {
+ const { state: extractedState, references } = extract(state);
+ expect(extractedState).not.toEqual(state);
+ expect(extractedState.action.config.dashboardId).toBeUndefined();
+ expect(references).toMatchInlineSnapshot(`
+ Array [
+ Object {
+ "id": "dashboardId_1",
+ "name": "drilldown:test_id:event_id:dashboardId",
+ "type": "dashboard",
+ },
+ ]
+ `);
+
+ let injectedState = inject(extractedState, references);
+ expect(injectedState).toEqual(state);
+
+ references[0].id = 'dashboardId_2';
+
+ injectedState = inject(extractedState, references);
+ expect(injectedState).not.toEqual(extractedState);
+ expect(injectedState.action.config.dashboardId).toBe('dashboardId_2');
+});
diff --git a/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/dashboard_drilldown_persistable_state.ts b/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/dashboard_drilldown_persistable_state.ts
new file mode 100644
index 000000000000..bd972723c649
--- /dev/null
+++ b/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/dashboard_drilldown_persistable_state.ts
@@ -0,0 +1,75 @@
+/*
+ * 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 { SavedObjectReference } from '../../../../../../src/core/types';
+import { PersistableStateService } from '../../../../../../src/plugins/kibana_utils/common';
+import { SerializedAction, SerializedEvent } from '../../../../ui_actions_enhanced/common';
+import { DrilldownConfig } from './types';
+
+type DashboardDrilldownPersistableState = PersistableStateService;
+
+const generateRefName = (state: SerializedEvent, id: string) =>
+ `drilldown:${id}:${state.eventId}:dashboardId`;
+
+const injectDashboardId = (state: SerializedEvent, dashboardId: string): SerializedEvent => {
+ return {
+ ...state,
+ action: {
+ ...state.action,
+ config: {
+ ...state.action.config,
+ dashboardId,
+ },
+ },
+ };
+};
+
+export const createInject = ({
+ drilldownId,
+}: {
+ drilldownId: string;
+}): DashboardDrilldownPersistableState['inject'] => {
+ return (state: SerializedEvent, references: SavedObjectReference[]) => {
+ const action = state.action as SerializedAction;
+ const refName = generateRefName(state, drilldownId);
+ const ref = references.find((r) => r.name === refName);
+ if (!ref) return state;
+ if (ref.id && ref.id === action.config.dashboardId) return state;
+ return injectDashboardId(state, ref.id);
+ };
+};
+
+export const createExtract = ({
+ drilldownId,
+}: {
+ drilldownId: string;
+}): DashboardDrilldownPersistableState['extract'] => {
+ return (state: SerializedEvent) => {
+ const action = state.action as SerializedAction;
+ const references: SavedObjectReference[] = action.config.dashboardId
+ ? [
+ {
+ name: generateRefName(state, drilldownId),
+ type: 'dashboard',
+ id: action.config.dashboardId,
+ },
+ ]
+ : [];
+
+ const { dashboardId, ...restOfConfig } = action.config;
+
+ return {
+ state: {
+ ...state,
+ action: ({
+ ...state.action,
+ config: restOfConfig,
+ } as unknown) as SerializedAction,
+ },
+ references,
+ };
+ };
+};
diff --git a/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/index.ts b/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/index.ts
new file mode 100644
index 000000000000..f6a757ad7a18
--- /dev/null
+++ b/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/index.ts
@@ -0,0 +1,9 @@
+/*
+ * 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 { createExtract, createInject } from './dashboard_drilldown_persistable_state';
+export { EMBEDDABLE_TO_DASHBOARD_DRILLDOWN } from './constants';
+export { DrilldownConfig } from './types';
diff --git a/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/types.ts b/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/types.ts
new file mode 100644
index 000000000000..3be2a9739837
--- /dev/null
+++ b/x-pack/plugins/dashboard_enhanced/common/drilldowns/dashboard_drilldown/types.ts
@@ -0,0 +1,12 @@
+/*
+ * 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.
+ */
+
+// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
+export type DrilldownConfig = {
+ dashboardId?: string;
+ useCurrentFilters: boolean;
+ useCurrentDateRange: boolean;
+};
diff --git a/x-pack/plugins/dashboard_enhanced/common/drilldowns/index.ts b/x-pack/plugins/dashboard_enhanced/common/drilldowns/index.ts
new file mode 100644
index 000000000000..76c9abbd4bfb
--- /dev/null
+++ b/x-pack/plugins/dashboard_enhanced/common/drilldowns/index.ts
@@ -0,0 +1,7 @@
+/*
+ * 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 * from './dashboard_drilldown';
diff --git a/x-pack/plugins/dashboard_enhanced/common/index.ts b/x-pack/plugins/dashboard_enhanced/common/index.ts
new file mode 100644
index 000000000000..8cc3e1290653
--- /dev/null
+++ b/x-pack/plugins/dashboard_enhanced/common/index.ts
@@ -0,0 +1,7 @@
+/*
+ * 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 * from './drilldowns';
diff --git a/x-pack/plugins/dashboard_enhanced/kibana.json b/x-pack/plugins/dashboard_enhanced/kibana.json
index f79a69c9f4ab..b24c0b6983f4 100644
--- a/x-pack/plugins/dashboard_enhanced/kibana.json
+++ b/x-pack/plugins/dashboard_enhanced/kibana.json
@@ -1,7 +1,7 @@
{
"id": "dashboardEnhanced",
"version": "kibana",
- "server": false,
+ "server": true,
"ui": true,
"requiredPlugins": ["data", "uiActionsEnhanced", "embeddable", "dashboard", "share"],
"configPath": ["xpack", "dashboardEnhanced"],
diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/abstract_dashboard_drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/abstract_dashboard_drilldown.tsx
index b098d6661981..451254efd964 100644
--- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/abstract_dashboard_drilldown.tsx
+++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/abstract_dashboard_drilldown.tsx
@@ -9,19 +9,19 @@ import { DataPublicPluginStart } from 'src/plugins/data/public';
import { DashboardStart } from 'src/plugins/dashboard/public';
import { reactToUiComponent } from '../../../../../../../src/plugins/kibana_react/public';
import {
- TriggerId,
TriggerContextMapping,
+ TriggerId,
} from '../../../../../../../src/plugins/ui_actions/public';
import { CollectConfigContainer } from './components';
import {
- UiActionsEnhancedDrilldownDefinition as Drilldown,
- UiActionsEnhancedBaseActionFactoryContext as BaseActionFactoryContext,
AdvancedUiActionsStart,
+ UiActionsEnhancedBaseActionFactoryContext as BaseActionFactoryContext,
+ UiActionsEnhancedDrilldownDefinition as Drilldown,
} from '../../../../../ui_actions_enhanced/public';
import { txtGoToDashboard } from './i18n';
import {
- StartServicesGetter,
CollectConfigProps,
+ StartServicesGetter,
} from '../../../../../../../src/plugins/kibana_utils/public';
import { KibanaURL } from '../../../../../../../src/plugins/share/public';
import { Config } from './types';
diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/types.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/types.ts
index 330a501a78d3..7f5137812ee3 100644
--- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/types.ts
+++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/types.ts
@@ -6,12 +6,8 @@
import { UiActionsEnhancedBaseActionFactoryContext } from '../../../../../ui_actions_enhanced/public';
import { APPLY_FILTER_TRIGGER } from '../../../../../../../src/plugins/ui_actions/public';
+import { DrilldownConfig } from '../../../../common';
-// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
-export type Config = {
- dashboardId?: string;
- useCurrentFilters: boolean;
- useCurrentDateRange: boolean;
-};
+export type Config = DrilldownConfig;
export type FactoryContext = UiActionsEnhancedBaseActionFactoryContext;
diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/embeddable_to_dashboard_drilldown/embeddable_to_dashboard_drilldown.test.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/embeddable_to_dashboard_drilldown/embeddable_to_dashboard_drilldown.test.tsx
index f6de2ba931c5..5bfb175ea0d0 100644
--- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/embeddable_to_dashboard_drilldown/embeddable_to_dashboard_drilldown.test.tsx
+++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/embeddable_to_dashboard_drilldown/embeddable_to_dashboard_drilldown.test.tsx
@@ -65,6 +65,12 @@ test('getHref is defined', () => {
expect(drilldown.getHref).toBeDefined();
});
+test('inject/extract are defined', () => {
+ const drilldown = new EmbeddableToDashboardDrilldown({} as any);
+ expect(drilldown.extract).toBeDefined();
+ expect(drilldown.inject).toBeDefined();
+});
+
describe('.execute() & getHref', () => {
/**
* A convenience test setup helper
diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/embeddable_to_dashboard_drilldown/embeddable_to_dashboard_drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/embeddable_to_dashboard_drilldown/embeddable_to_dashboard_drilldown.tsx
index 25bc93ad38b3..921c2aed0062 100644
--- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/embeddable_to_dashboard_drilldown/embeddable_to_dashboard_drilldown.tsx
+++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/embeddable_to_dashboard_drilldown/embeddable_to_dashboard_drilldown.tsx
@@ -22,6 +22,7 @@ import {
} from '../abstract_dashboard_drilldown';
import { KibanaURL } from '../../../../../../../src/plugins/share/public';
import { EMBEDDABLE_TO_DASHBOARD_DRILLDOWN } from './constants';
+import { createExtract, createInject } from '../../../../common';
type Trigger = typeof APPLY_FILTER_TRIGGER;
type Context = TriggerContextMapping[Trigger];
@@ -80,4 +81,8 @@ export class EmbeddableToDashboardDrilldown extends AbstractDashboardDrilldown {
+ constructor(protected readonly context: PluginInitializerContext) {}
+
+ public setup(core: CoreSetup, plugins: SetupDependencies): SetupContract {
+ plugins.uiActionsEnhanced.registerActionFactory({
+ id: EMBEDDABLE_TO_DASHBOARD_DRILLDOWN,
+ inject: createInject({ drilldownId: EMBEDDABLE_TO_DASHBOARD_DRILLDOWN }),
+ extract: createExtract({ drilldownId: EMBEDDABLE_TO_DASHBOARD_DRILLDOWN }),
+ });
+
+ return {};
+ }
+
+ public start(core: CoreStart, plugins: StartDependencies): StartContract {
+ return {};
+ }
+
+ public stop() {}
+}
diff --git a/x-pack/plugins/ui_actions_enhanced/common/index.ts b/x-pack/plugins/ui_actions_enhanced/common/index.ts
new file mode 100644
index 000000000000..9f4141dbcae7
--- /dev/null
+++ b/x-pack/plugins/ui_actions_enhanced/common/index.ts
@@ -0,0 +1,7 @@
+/*
+ * 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 * from './types';
diff --git a/x-pack/plugins/ui_actions_enhanced/server/dynamic_action_enhancement.ts b/x-pack/plugins/ui_actions_enhanced/server/dynamic_action_enhancement.ts
index b36643620091..ade78c31211a 100644
--- a/x-pack/plugins/ui_actions_enhanced/server/dynamic_action_enhancement.ts
+++ b/x-pack/plugins/ui_actions_enhanced/server/dynamic_action_enhancement.ts
@@ -7,11 +7,11 @@
import { EnhancementRegistryDefinition } from '../../../../src/plugins/embeddable/server';
import { SavedObjectReference } from '../../../../src/core/types';
import { DynamicActionsState, SerializedEvent } from './types';
-import { AdvancedUiActionsPublicPlugin } from './plugin';
+import { AdvancedUiActionsServerPlugin } from './plugin';
import { SerializableState } from '../../../../src/plugins/kibana_utils/common';
export const dynamicActionEnhancement = (
- uiActionsEnhanced: AdvancedUiActionsPublicPlugin
+ uiActionsEnhanced: AdvancedUiActionsServerPlugin
): EnhancementRegistryDefinition => {
return {
id: 'dynamicActions',
diff --git a/x-pack/plugins/ui_actions_enhanced/server/index.ts b/x-pack/plugins/ui_actions_enhanced/server/index.ts
index 5419c4135796..e1363be35e2e 100644
--- a/x-pack/plugins/ui_actions_enhanced/server/index.ts
+++ b/x-pack/plugins/ui_actions_enhanced/server/index.ts
@@ -4,13 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { AdvancedUiActionsPublicPlugin } from './plugin';
+import { AdvancedUiActionsServerPlugin } from './plugin';
export function plugin() {
- return new AdvancedUiActionsPublicPlugin();
+ return new AdvancedUiActionsServerPlugin();
}
-export { AdvancedUiActionsPublicPlugin as Plugin };
+export { AdvancedUiActionsServerPlugin as Plugin };
export {
SetupContract as AdvancedUiActionsSetup,
StartContract as AdvancedUiActionsStart,
diff --git a/x-pack/plugins/ui_actions_enhanced/server/plugin.ts b/x-pack/plugins/ui_actions_enhanced/server/plugin.ts
index d6d18848be4d..718304018730 100644
--- a/x-pack/plugins/ui_actions_enhanced/server/plugin.ts
+++ b/x-pack/plugins/ui_actions_enhanced/server/plugin.ts
@@ -16,7 +16,7 @@ import {
} from './types';
export interface SetupContract {
- registerActionFactory: any;
+ registerActionFactory: (definition: ActionFactoryDefinition) => void;
}
export type StartContract = void;
@@ -25,7 +25,7 @@ interface SetupDependencies {
embeddable: EmbeddableSetup; // Embeddable are needed because they register basic triggers/actions.
}
-export class AdvancedUiActionsPublicPlugin
+export class AdvancedUiActionsServerPlugin
implements Plugin {
protected readonly actionFactories: ActionFactoryRegistry = new Map();
diff --git a/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_to_dashboard_drilldown.ts b/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_to_dashboard_drilldown.ts
index 43b88915b69d..9326f7e240e3 100644
--- a/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_to_dashboard_drilldown.ts
+++ b/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_to_dashboard_drilldown.ts
@@ -14,7 +14,14 @@ 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 PageObjects = getPageObjects([
+ 'dashboard',
+ 'common',
+ 'header',
+ 'timePicker',
+ 'settings',
+ 'copySavedObjectsToSpace',
+ ]);
const pieChart = getService('pieChart');
const log = getService('log');
const browser = getService('browser');
@@ -22,120 +29,188 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const testSubjects = getService('testSubjects');
const filterBar = getService('filterBar');
const security = getService('security');
+ const spaces = getService('spaces');
describe('Dashboard to dashboard drilldown', function () {
- before(async () => {
- log.debug('Dashboard Drilldowns:initTests');
- await security.testUser.setRoles(['test_logstash_reader', 'global_dashboard_all']);
- await PageObjects.common.navigateToApp('dashboard');
- await PageObjects.dashboard.preserveCrossAppState();
+ describe('Create & use drilldowns', () => {
+ before(async () => {
+ log.debug('Dashboard Drilldowns:initTests');
+ await security.testUser.setRoles(['test_logstash_reader', 'global_dashboard_all']);
+ await PageObjects.common.navigateToApp('dashboard');
+ await PageObjects.dashboard.preserveCrossAppState();
+ });
+
+ after(async () => {
+ await security.testUser.restoreDefaults();
+ });
+
+ it('should create dashboard to dashboard drilldown, use it, and then delete it', async () => {
+ await PageObjects.dashboard.gotoDashboardEditMode(
+ dashboardDrilldownsManage.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: dashboardDrilldownsManage.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(
+ dashboardDrilldownsManage.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.clickOnPieSlice('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);
+
+ 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(
+ dashboardDrilldownsManage.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
+ );
+ });
});
- after(async () => {
- await security.testUser.restoreDefaults();
- });
-
- it('should create dashboard to dashboard drilldown, use it, and then delete it', async () => {
- await PageObjects.dashboard.gotoDashboardEditMode(
- dashboardDrilldownsManage.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: dashboardDrilldownsManage.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(
- dashboardDrilldownsManage.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.clickOnPieSlice('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);
-
- 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);
+ describe('Copy to space', () => {
+ const destinationSpaceId = 'custom_space';
+ before(async () => {
+ await spaces.create({
+ id: destinationSpaceId,
+ name: 'custom_space',
+ disabledFeatures: [],
+ });
+ await PageObjects.settings.navigateTo();
+ await PageObjects.settings.clickKibanaSavedObjects();
});
- // 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(
- dashboardDrilldownsManage.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();
+ after(async () => {
+ await spaces.delete(destinationSpaceId);
});
- expect(await PageObjects.timePicker.getTimeDurationInHours()).to.be(
- originalTimeRangeDurationHours
- );
+ it('Dashboards linked by a drilldown are both copied to a space', async () => {
+ await PageObjects.copySavedObjectsToSpace.openCopyToSpaceFlyoutForObject(
+ dashboardDrilldownsManage.DASHBOARD_WITH_AREA_CHART_NAME
+ );
+ await PageObjects.copySavedObjectsToSpace.setupForm({
+ destinationSpaceId,
+ });
+ await PageObjects.copySavedObjectsToSpace.startCopy();
+
+ // Wait for successful copy
+ await testSubjects.waitForDeleted(`cts-summary-indicator-loading-${destinationSpaceId}`);
+ await testSubjects.existOrFail(`cts-summary-indicator-success-${destinationSpaceId}`);
+
+ const summaryCounts = await PageObjects.copySavedObjectsToSpace.getSummaryCounts();
+
+ expect(summaryCounts).to.eql({
+ success: 5, // 2 dashboards (linked by a drilldown) + 2 visualizations + 1 index pattern
+ pending: 0,
+ skipped: 0,
+ errors: 0,
+ });
+
+ await PageObjects.copySavedObjectsToSpace.finishCopy();
+
+ // Actually use copied dashboards in a new space:
+
+ await PageObjects.common.navigateToApp('dashboard', {
+ basePath: `/s/${destinationSpaceId}`,
+ });
+ await PageObjects.dashboard.preserveCrossAppState();
+ await PageObjects.dashboard.loadSavedDashboard(
+ dashboardDrilldownsManage.DASHBOARD_WITH_AREA_CHART_NAME
+ );
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ await PageObjects.dashboard.waitForRenderComplete();
+
+ // 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);
+ });
+ await pieChart.expectPieSliceCount(10);
+ });
});
});
diff --git a/x-pack/test/functional/es_archives/reporting/hugedata/data.json.gz b/x-pack/test/functional/es_archives/reporting/hugedata/data.json.gz
index c524379640df..c616730ff35b 100644
Binary files a/x-pack/test/functional/es_archives/reporting/hugedata/data.json.gz and b/x-pack/test/functional/es_archives/reporting/hugedata/data.json.gz differ
diff --git a/x-pack/test/functional/es_archives/spaces/copy_saved_objects/data.json b/x-pack/test/functional/es_archives/spaces/copy_saved_objects/data.json
index 3434e1f80a7c..552142d3b190 100644
--- a/x-pack/test/functional/es_archives/spaces/copy_saved_objects/data.json
+++ b/x-pack/test/functional/es_archives/spaces/copy_saved_objects/data.json
@@ -126,7 +126,7 @@
"title": "Dashboard Foo",
"hits": 0,
"description": "",
- "panelsJSON": "[{}]",
+ "panelsJSON": "[]",
"optionsJSON": "{}",
"version": 1,
"timeRestore": false,
@@ -156,7 +156,7 @@
"title": "Dashboard Bar",
"hits": 0,
"description": "",
- "panelsJSON": "[{}]",
+ "panelsJSON": "[]",
"optionsJSON": "{}",
"version": 1,
"timeRestore": false,
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/dashboard/sample_dashboard.json b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/dashboard/sample_dashboard.json
index ef08d6932421..7f416c26cc9a 100644
--- a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/dashboard/sample_dashboard.json
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/dashboard/sample_dashboard.json
@@ -11,6 +11,12 @@
"title": "[Logs Sample] Overview ECS",
"version": 1
},
+ "references": [
+ { "id": "sample_visualization", "name": "panel_0", "type": "visualization" },
+ { "id": "sample_search", "name": "panel_1", "type": "search" },
+ { "id": "sample_search", "name": "panel_2", "type": "search" },
+ { "id": "sample_visualization", "name": "panel_3", "type": "visualization" }
+ ],
"id": "sample_dashboard",
"type": "dashboard"
-}
\ No newline at end of file
+}
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/dashboard/sample_dashboard2.json b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/dashboard/sample_dashboard2.json
index 7ea63c5d444b..c99506fec3cf 100644
--- a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/dashboard/sample_dashboard2.json
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/kibana/dashboard/sample_dashboard2.json
@@ -11,6 +11,12 @@
"title": "[Logs Sample2] Overview ECS",
"version": 1
},
+ "references": [
+ { "id": "sample_visualization", "name": "panel_0", "type": "visualization" },
+ { "id": "sample_search", "name": "panel_1", "type": "search" },
+ { "id": "sample_search", "name": "panel_2", "type": "search" },
+ { "id": "sample_visualization", "name": "panel_3", "type": "visualization" }
+ ],
"id": "sample_dashboard2",
"type": "dashboard"
-}
\ No newline at end of file
+}
diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/kibana/dashboard/sample_dashboard.json b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/kibana/dashboard/sample_dashboard.json
index ef08d6932421..4513c07f2778 100644
--- a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/kibana/dashboard/sample_dashboard.json
+++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.2.0/kibana/dashboard/sample_dashboard.json
@@ -11,6 +11,12 @@
"title": "[Logs Sample] Overview ECS",
"version": 1
},
+ "references": [
+ { "id": "sample_visualization", "name": "panel_0", "type": "visualization" },
+ { "id": "sample_search2", "name": "panel_1", "type": "search" },
+ { "id": "sample_search2", "name": "panel_2", "type": "search" },
+ { "id": "sample_visualization", "name": "panel_3", "type": "visualization" }
+ ],
"id": "sample_dashboard",
"type": "dashboard"
-}
\ No newline at end of file
+}