[Lens] Enables right clicks to the discover drilldown (#136088)

* Adds href to the discover drilldown

* Add href function to the Discover action

* Apply nit

Co-authored-by: Joe Reuter <johannes.reuter@elastic.co>
This commit is contained in:
Stratoula Kalafateli 2022-07-12 13:50:24 +03:00 committed by GitHub
parent 754fdea25d
commit 2de673f665
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 17 deletions

View file

@ -294,13 +294,13 @@ export class LensPlugin {
}
visualizations.registerAlias(getLensAliasConfig());
if (discover) {
uiActionsEnhanced.registerDrilldown(
new OpenInDiscoverDrilldown({
discover,
dataViews: () => this.dataViewsService!,
hasDiscoverAccess: () => this.hasDiscoverAccess,
application: () => startServices().core.application,
})
);
}

View file

@ -10,7 +10,7 @@ import { createAction } from '@kbn/ui-actions-plugin/public';
import type { DiscoverStart } from '@kbn/discover-plugin/public';
import { IEmbeddable } from '@kbn/embeddable-plugin/public';
import { DataViewsService } from '@kbn/data-views-plugin/public';
import { execute, isCompatible } from './open_in_discover_helpers';
import { execute, isCompatible, getHref } from './open_in_discover_helpers';
const ACTION_OPEN_IN_DISCOVER = 'ACTION_OPEN_IN_DISCOVER';
@ -32,6 +32,14 @@ export const createOpenInDiscoverAction = (
i18n.translate('xpack.lens.app.exploreDataInDiscover', {
defaultMessage: 'Explore data in Discover',
}),
getHref: async (context: Context) => {
return getHref({
discover,
dataViews,
hasDiscoverAccess,
...context,
});
},
isCompatible: async (context: Context) => {
return isCompatible({
hasDiscoverAccess,

View file

@ -8,7 +8,8 @@
import React, { FormEvent } from 'react';
import { IEmbeddable, EmbeddableInput } from '@kbn/embeddable-plugin/public';
import { DiscoverSetup } from '@kbn/discover-plugin/public';
import { execute, isCompatible } from './open_in_discover_helpers';
import type { ApplicationStart } from '@kbn/core/public';
import { getHref, isCompatible } from './open_in_discover_helpers';
import { mount } from 'enzyme';
import { Filter } from '@kbn/es-query';
import {
@ -20,7 +21,7 @@ import { DataViewsService } from '@kbn/data-views-plugin/public';
jest.mock('./open_in_discover_helpers', () => ({
isCompatible: jest.fn(() => true),
execute: jest.fn(),
getHref: jest.fn(),
}));
describe('open in discover drilldown', () => {
@ -30,6 +31,7 @@ describe('open in discover drilldown', () => {
discover: {} as DiscoverSetup,
dataViews: () => ({} as DataViewsService),
hasDiscoverAccess: () => true,
application: () => ({} as ApplicationStart),
});
});
it('provides UI to edit config', () => {
@ -54,14 +56,12 @@ describe('open in discover drilldown', () => {
);
expect(isCompatible).toHaveBeenCalledWith(expect.objectContaining({ filters }));
});
it('calls through to execute helper', async () => {
it('calls through to getHref helper', async () => {
const filters: Filter[] = [{ meta: { disabled: false } }];
await drilldown.execute(
{ openInNewTab: true },
{ embeddable: { type: 'lens' } as IEmbeddable<EmbeddableInput>, filters }
);
expect(execute).toHaveBeenCalledWith(
expect.objectContaining({ filters, openInSameTab: false })
);
expect(getHref).toHaveBeenCalledWith(expect.objectContaining({ filters }));
});
});

View file

@ -9,6 +9,7 @@ import React from 'react';
import { IEmbeddable, EmbeddableInput } from '@kbn/embeddable-plugin/public';
import type { Query, Filter, TimeRange } from '@kbn/es-query';
import { APPLY_FILTER_TRIGGER } from '@kbn/data-plugin/public';
import type { ApplicationStart } from '@kbn/core/public';
import { CollectConfigProps as CollectConfigPropsBase } from '@kbn/kibana-utils-plugin/public';
import { reactToUiComponent } from '@kbn/kibana-react-plugin/public';
import {
@ -20,7 +21,7 @@ import { DiscoverSetup } from '@kbn/discover-plugin/public';
import { ApplyGlobalFilterActionContext } from '@kbn/unified-search-plugin/public';
import { i18n } from '@kbn/i18n';
import { DataViewsService } from '@kbn/data-views-plugin/public';
import { execute, isCompatible, isLensEmbeddable } from './open_in_discover_helpers';
import { isCompatible, isLensEmbeddable, getHref, getLocation } from './open_in_discover_helpers';
interface EmbeddableQueryInput extends EmbeddableInput {
query?: Query;
@ -35,6 +36,7 @@ interface UrlDrilldownDeps {
discover: Pick<DiscoverSetup, 'locator'>;
dataViews: () => Pick<DataViewsService, 'get'>;
hasDiscoverAccess: () => boolean;
application: () => ApplicationStart;
}
export type ActionContext = ApplyGlobalFilterActionContext;
@ -119,14 +121,28 @@ export class OpenInDiscoverDrilldown
return this.deps.hasDiscoverAccess() && isLensEmbeddable(context.embeddable as IEmbeddable);
};
public readonly execute = async (config: Config, context: ActionContext) => {
execute({
public readonly getHref = async (config: Config, context: ActionContext) => {
return getHref({
discover: this.deps.discover,
dataViews: this.deps.dataViews(),
hasDiscoverAccess: this.deps.hasDiscoverAccess(),
...context,
embeddable: context.embeddable as IEmbeddable,
openInSameTab: !config.openInNewTab,
});
};
public readonly execute = async (config: Config, context: ActionContext) => {
if (config.openInNewTab) {
window.open(await this.getHref(config, context), '_blank');
} else {
const { app, path, state } = await getLocation({
discover: this.deps.discover,
dataViews: this.deps.dataViews(),
hasDiscoverAccess: this.deps.hasDiscoverAccess(),
...context,
embeddable: context.embeddable as IEmbeddable,
});
await this.deps.application().navigateToApp(app, { path, state });
}
};
}

View file

@ -38,14 +38,12 @@ export async function isCompatible({ hasDiscoverAccess, embeddable }: Context) {
}
}
export async function execute({
async function getDiscoverLocationParams({
embeddable,
discover,
filters,
openInSameTab,
dataViews,
timeFieldName,
}: Context) {
}: Pick<Context, 'dataViews' | 'embeddable' | 'filters' | 'timeFieldName'>) {
if (!isLensEmbeddable(embeddable)) {
// shouldn't be executed because of the isCompatible check
throw new Error('Can only be executed in the context of Lens visualization');
@ -67,10 +65,72 @@ export async function execute({
timeRangeToApply = timeRange;
}
}
const discoverUrl = discover.locator?.getRedirectUrl({
return {
...args,
timeRange: timeRangeToApply,
filters: filtersToApply,
};
}
export async function getHref({
embeddable,
discover,
filters,
dataViews,
timeFieldName,
}: Context) {
const params = await getDiscoverLocationParams({
embeddable,
filters,
dataViews,
timeFieldName,
});
const discoverUrl = discover.locator?.getRedirectUrl(params);
return discoverUrl;
}
export async function getLocation({
embeddable,
discover,
filters,
dataViews,
timeFieldName,
}: Context) {
const params = await getDiscoverLocationParams({
embeddable,
filters,
dataViews,
timeFieldName,
});
const discoverLocation = discover.locator?.getLocation(params);
if (!discoverLocation) {
throw new Error('Discover location not found');
}
return discoverLocation;
}
export async function execute({
embeddable,
discover,
filters,
openInSameTab,
dataViews,
timeFieldName,
hasDiscoverAccess,
}: Context) {
const discoverUrl = await getHref({
embeddable,
discover,
filters,
dataViews,
timeFieldName,
hasDiscoverAccess,
});
window.open(discoverUrl, !openInSameTab ? '_blank' : '_self');
}