Skip to content

Commit

Permalink
register data and visualizations for ES|QL when compatible and missing
Browse files Browse the repository at this point in the history
  • Loading branch information
eokoneyo committed Jul 23, 2024
1 parent b27532c commit fa819ac
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 10 deletions.
8 changes: 7 additions & 1 deletion x-pack/plugins/lens/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,13 @@ export class LensPlugin {
);

// Displays the add ESQL panel in the dashboard add Panel menu
const createESQLPanelAction = new CreateESQLPanelAction(startDependencies, core);
const createESQLPanelAction = new CreateESQLPanelAction(startDependencies, core, async () => {
if (!this.editorFrameService) {
await this.initDependenciesForApi();
}

return this.editorFrameService!;
});
startDependencies.uiActions.addTriggerAction(ADD_PANEL_TRIGGER, createESQLPanelAction);

const discoverLocator = startDependencies.share?.url.locators.get('DISCOVER_APP_LOCATOR');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import type { CoreStart } from '@kbn/core/public';
import { coreMock } from '@kbn/core/public/mocks';
import type { LensPluginStartDependencies } from '../../plugin';
import type { EditorFrameService, Datasource, Visualization } from '../../editor_frame_service';
import { createMockStartDependencies } from '../../editor_frame_service/mocks';
import { getMockPresentationContainer } from '@kbn/presentation-containers/mocks';
import { CreateESQLPanelAction } from './create_action';
Expand All @@ -16,17 +17,53 @@ describe('create Lens panel action', () => {
const mockStartDependencies =
createMockStartDependencies() as unknown as LensPluginStartDependencies;
const mockPresentationContainer = getMockPresentationContainer();

const mockEditorFrameService = {
loadVisualizations: jest.fn(),
loadDatasources: jest.fn(),
} as unknown as EditorFrameService;

const mockGetEditorFrameService = jest.fn(() => Promise.resolve(mockEditorFrameService));

describe('compatibility check', () => {
it('is incompatible if ui setting for ES|QL is off', async () => {
const configurablePanelAction = new CreateESQLPanelAction(mockStartDependencies, core);
const configurablePanelAction = new CreateESQLPanelAction(
mockStartDependencies,
core,
mockGetEditorFrameService
);
const isCompatible = await configurablePanelAction.isCompatible({
embeddable: mockPresentationContainer,
});

expect(isCompatible).toBeFalsy();
});

it('is compatible if ui setting for ES|QL is on', async () => {
it('is incompatible if ui setting for ES|QL is enabled, without dataSourceMap and visualizationMap', async () => {
const updatedCore = {
...core,
uiSettings: {
...core.uiSettings,
get: (setting: string) => {
return setting === 'enableESQL';
},
},
} as CoreStart;

const createESQLAction = new CreateESQLPanelAction(
mockStartDependencies,
updatedCore,
mockGetEditorFrameService
);

const isCompatible = await createESQLAction.isCompatible({
embeddable: mockPresentationContainer,
});

expect(isCompatible).toBeFalsy();
});

it('is compatible if ui setting for ES|QL is enabled and dataSourceMap, alongside visualizationMap exist', async () => {
const updatedCore = {
...core,
uiSettings: {
Expand All @@ -36,7 +73,16 @@ describe('create Lens panel action', () => {
},
},
} as CoreStart;
const createESQLAction = new CreateESQLPanelAction(mockStartDependencies, updatedCore);

const createESQLAction = new CreateESQLPanelAction(
mockStartDependencies,
updatedCore,
mockGetEditorFrameService
);

jest.spyOn(mockEditorFrameService, 'loadVisualizations').mockReturnValue({} as Visualization);
jest.spyOn(mockEditorFrameService, 'loadDatasources').mockReturnValue({} as Datasource);

const isCompatible = await createESQLAction.isCompatible({
embeddable: mockPresentationContainer,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { EmbeddableApiContext } from '@kbn/presentation-publishing';
import { apiIsPresentationContainer } from '@kbn/presentation-containers';
import { COMMON_VISUALIZATION_GROUPING } from '@kbn/visualizations-plugin/public';
import type { LensPluginStartDependencies } from '../../plugin';
import type { EditorFrameService } from '../../editor_frame_service';

const ACTION_CREATE_ESQL_CHART = 'ACTION_CREATE_ESQL_CHART';

Expand All @@ -25,7 +26,8 @@ export class CreateESQLPanelAction implements Action<EmbeddableApiContext> {

constructor(
protected readonly startDependencies: LensPluginStartDependencies,
protected readonly core: CoreStart
protected readonly core: CoreStart,
protected readonly getEditorFrameService: () => Promise<EditorFrameService>
) {}

public getDisplayName(): string {
Expand All @@ -41,18 +43,22 @@ export class CreateESQLPanelAction implements Action<EmbeddableApiContext> {

public async isCompatible({ embeddable }: EmbeddableApiContext) {
if (!apiIsPresentationContainer(embeddable)) return false;
// compatible only when ES|QL advanced setting is enabled
const { isCreateActionCompatible } = await getAsyncHelpers();
return isCreateActionCompatible(this.core);
const editorFrameService = await this.getEditorFrameService();

return isCreateActionCompatible(this.core, editorFrameService);
}

public async execute({ embeddable }: EmbeddableApiContext) {
if (!apiIsPresentationContainer(embeddable)) throw new IncompatibleActionError();
const { executeCreateAction } = await getAsyncHelpers();
const editorFrameService = await this.getEditorFrameService();

executeCreateAction({
deps: this.startDependencies,
core: this.core,
api: embeddable,
editorFrameService,
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { suggestionsApi } from '../../lens_suggestions_api';
import { generateId } from '../../id_generator';
import { executeEditAction } from './edit_action_helpers';
import { Embeddable } from '../../embeddable';
import type { EditorFrameService } from '../../editor_frame_service';

// datasourceMap and visualizationMap setters/getters
export const [getVisualizationMap, setVisualizationMap] = createGetterSetter<
Expand All @@ -31,20 +32,41 @@ export const [getDatasourceMap, setDatasourceMap] = createGetterSetter<
Record<string, Datasource<unknown, unknown>>
>('DatasourceMap', false);

export function isCreateActionCompatible(core: CoreStart) {
return core.uiSettings.get(ENABLE_ESQL);
export async function isCreateActionCompatible(
core: CoreStart,
editorFrameService: EditorFrameService
) {
let isCompatible: boolean = core.uiSettings.get(ENABLE_ESQL);

if (isCompatible && !getDatasourceMap() && !getVisualizationMap()) {
const [visualizationMap, datasourceMap] = await Promise.all([
editorFrameService.loadVisualizations(),
editorFrameService.loadDatasources(),
]);

if (visualizationMap && datasourceMap) {
setDatasourceMap(datasourceMap);
setVisualizationMap(visualizationMap);
} else {
isCompatible = false;
}
}

return isCompatible;
}

export async function executeCreateAction({
deps,
core,
api,
editorFrameService,
}: {
deps: LensPluginStartDependencies;
core: CoreStart;
api: PresentationContainer;
editorFrameService: EditorFrameService;
}) {
const isCompatibleAction = isCreateActionCompatible(core);
const isCompatibleAction = await isCreateActionCompatible(core, editorFrameService);

const getFallbackDataView = async () => {
const indexName = await getIndexForESQLQuery({ dataViews: deps.dataViews });
Expand Down

0 comments on commit fa819ac

Please sign in to comment.