Skip to content
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pageLoadAssetSize:
embeddableAlertsTable: 6524
enterpriseSearch: 37565
entityStore: 9718
esql: 29547
esql: 29469
esqlDataGrid: 10209
esUiShared: 101220
evals: 6117
Expand Down Expand Up @@ -115,7 +115,7 @@ pageLoadAssetSize:
logstash: 15882
maintenanceWindows: 8775
management: 14304
maps: 45917
maps: 36281
mapsEms: 6734
metricsDataAccess: 44950
ml: 99842
Expand Down Expand Up @@ -205,7 +205,7 @@ pageLoadAssetSize:
visTypeTagcloud: 7876
visTypeTimelion: 12512
visTypeTimeseries: 20000
visTypeVega: 38538
visTypeVega: 11562
visTypeVislib: 14679
visTypeXy: 32342
visualizationListing: 5148
Expand Down
Original file line number Diff line number Diff line change
@@ -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
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export { vegaVisType } from './vega_type';
export { createVegaFn } from './vega_fn';
export { getVegaVisRenderer } from './vega_vis_renderer';
19 changes: 11 additions & 8 deletions src/platform/plugins/private/vis_types/vega/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,11 @@ import {
setUsageCollectionStart,
} from './services';

import { createVegaFn } from './vega_fn';
import { vegaVisType } from './vega_type';
import type { IServiceSettings } from './vega_view/vega_map_view/service_settings/service_settings_types';

import type { ConfigSchema } from '../server/config';

import { getVegaInspectorView } from './vega_inspector';
import { getVegaVisRenderer } from './vega_vis_renderer';
import { getServiceSettingsLazy } from './vega_view/vega_map_view/service_settings/get_service_settings_lazy';

/** @internal */
Expand All @@ -64,6 +61,7 @@ export interface VegaPluginSetupDependencies {
export interface VegaPluginStartDependencies {
data: DataPublicPluginStart;
embeddable: EmbeddableStart;
expressions: ReturnType<ExpressionsPublicPlugin['start']>;
mapsEms: MapsEmsPluginPublicStart;
dataViews: DataViewsPublicPluginStart;
uiActions: UiActionsStart;
Expand All @@ -79,7 +77,7 @@ export class VegaPlugin implements Plugin<void, void> {
}

public setup(
core: CoreSetup,
core: CoreSetup<VegaPluginStartDependencies>,
{ inspector, data, expressions, visualizations }: VegaPluginSetupDependencies
) {
setInjectedVars({
Expand All @@ -96,10 +94,15 @@ export class VegaPlugin implements Plugin<void, void> {

inspector.registerView(getVegaInspectorView({ uiSettings: core.uiSettings }));

expressions.registerFunction(() => createVegaFn(visualizationDependencies));
expressions.registerRenderer(getVegaVisRenderer(visualizationDependencies));

visualizations.createBaseVisualization(vegaVisType);
visualizations.createBaseVisualizationAsync('vega', async () => {
const [[, startPlugins], { vegaVisType, createVegaFn, getVegaVisRenderer }] =
await Promise.all([core.getStartServices(), import('./async_module')]);
if (!startPlugins.expressions.getFunction('vega')) {
expressions.registerFunction(() => createVegaFn(visualizationDependencies));
expressions.registerRenderer(getVegaVisRenderer(visualizationDependencies));
}
return vegaVisType;
});
}

public start(core: CoreStart, deps: VegaPluginStartDependencies) {
Expand Down
1 change: 1 addition & 0 deletions src/platform/plugins/shared/visualizations/moon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ dependsOn:
- '@kbn/cps'
- '@kbn/kql'
- '@kbn/cps-utils'
- '@kbn/std'
tags:
- plugin
- prod
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import type { Schema, VisualizationsSetup, VisualizationsStart } from '.';

const createSetupContract = (): VisualizationsSetup => ({
createBaseVisualization: jest.fn(),
createBaseVisualizationAsync: jest.fn(),
registerAlias: jest.fn(),
visEditorsRegistry: { registerDefault: jest.fn(), register: jest.fn(), get: jest.fn() },
listingViewRegistry: { add: jest.fn() },
Expand Down
6 changes: 2 additions & 4 deletions src/platform/plugins/shared/visualizations/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ import {
setSavedSearch,
setDataViews,
setInspector,
getTypes,
setNotifications,
} from './services';
import type { ListingViewRegistry } from './types';
Expand Down Expand Up @@ -501,9 +500,8 @@ export class VisualizationsPlugin
savedObjectName: i18n.translate('visualizations.visualizeSavedObjectName', {
defaultMessage: 'Visualization',
}),
getIconForSavedObject: (savedObject) => {
const visState = JSON.parse(savedObject.attributes.visState ?? '{}');
return getTypes().get(visState.type)?.icon ?? '';
getIconForSavedObject: () => {
return 'visualizeApp';
Comment on lines +503 to +504
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you change this, in the Dashboard Add from library you will lose the chart icons.
Not a big deal for the agg-base visualize charts, but Vega will be affected to.

Before:
Image
After:
Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you change this, in the Dashboard Add from library you will lose the chart icons.
Not a big deal for the agg-base visualize charts, but Vega will be affected to.

I think this is ok and even beneficial in the long run. There are plans to create a vega embeddable in the near future for "as code". This change will make it clear when a vega library item is vega embeddable or legacy vega vis.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see but for now I don't think this is a valid change, it will create confusion until we don't have the vega embeddable is ready. We should not release this change until Vega is not clearly distinguishable from the rest.

Copy link
Copy Markdown
Contributor

@markov00 markov00 Jun 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just hardcode a check for the visState.type and return the Vega icon if vega and visualizeApp otherwise. We don't really need the registry for that. We can then clean this up with the vega embeddable

},
});
embeddable.registerLegacyURLTransform(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import _ from 'lodash';
import { asyncMap } from '@kbn/std';
import type { Reference } from '@kbn/content-management-utils';
import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/public';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
Expand Down Expand Up @@ -52,7 +53,7 @@ const getDefaults = (opts: GetVisOptions) => ({
version: 1,
});

function mapHitSource(
async function mapHitSource(
visTypes: Pick<TypesStart, 'get'>,
{ attributes, id, references, updatedAt, managed }: VisualizationSavedObject
) {
Expand Down Expand Up @@ -93,13 +94,13 @@ function mapHitSource(
return newAttributes;
}

newAttributes.type = visTypes.get(typeName as string);
newAttributes.type = await visTypes.get(typeName as string);
Comment thread
nreese marked this conversation as resolved.
Outdated
newAttributes.savedObjectType = 'visualization';
newAttributes.icon = newAttributes.type?.icon;
newAttributes.image = newAttributes.type?.image;
newAttributes.typeTitle = newAttributes.type?.title;
newAttributes.editor = { editUrl: `/edit/${id}` };
newAttributes.readOnly = Boolean(visTypes.get(typeName as string)?.disableEdit);
newAttributes.readOnly = Boolean(newAttributes.type?.disableEdit);

return newAttributes;
}
Expand Down Expand Up @@ -177,7 +178,7 @@ export async function findListItems(

return {
total,
hits: savedObjects.map((savedObject: SavedObjectsFindResult) => {
hits: await asyncMap(savedObjects, async (savedObject: SavedObjectsFindResult) => {
const config = extensionByType[savedObject.type];
const { updated_at, updated_by, created_at, created_by, ...rest } = savedObject;
const visObject = {
Expand All @@ -195,7 +196,7 @@ export async function findListItems(
references: savedObject.references,
};
} else {
return mapHitSource(visTypes, visObject);
return await mapHitSource(visTypes, visObject);
}
}),
};
Expand Down
32 changes: 10 additions & 22 deletions src/platform/plugins/shared/visualizations/public/vis.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,16 @@
*/

import { Vis } from './vis';
import type { VisTypeDefinition } from './vis_types';
import { BaseVisType } from './vis_types';

jest.mock('./services', () => {
class MockVisualizationController {
constructor() {}

render(): Promise<void> {
return new Promise((resolve) => {
resolve();
});
}

destroy() {}
}

// eslint-disable-next-line @typescript-eslint/no-var-requires
const { BaseVisType } = require('./vis_types/base_vis_type');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { SearchSource } = require('@kbn/data-plugin/common/search/search_source');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const stubIndexPattern = require('@kbn/data-plugin/common/stubs');
const visType = new BaseVisType({
name: 'pie',
title: 'pie',
icon: 'pie-icon',
visualization: MockVisualizationController,
});

return {
getTypes: () => ({ get: () => visType }),
getAggs: () => ({
createAggConfigs: (indexPattern: any, cfg: any) => ({
aggs: cfg.map((aggConfig: any) => ({ ...aggConfig, serialize: () => aggConfig })),
Expand Down Expand Up @@ -71,7 +52,14 @@ describe('Vis Class', function () {
};

beforeEach(async function () {
vis = new Vis('test', stateFixture as any);
vis = new Vis(
new BaseVisType({
name: 'pie',
title: 'pie',
icon: 'pie-icon',
} as unknown as VisTypeDefinition<object>),
stateFixture as any
);
await vis.setState(stateFixture as any);
});

Expand Down
36 changes: 16 additions & 20 deletions src/platform/plugins/shared/visualizations/public/vis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const getSearchSource = async (inputSearchSource: ISearchSource, savedSearchId?:
type PartialVisState = Assign<SerializedVis, { data: Partial<SerializedVisData> }>;

export class Vis<TVisParams extends VisParams = VisParams> {
public readonly type: BaseVisType<TVisParams>;
public type: BaseVisType<TVisParams>;
public readonly id?: string;
public title: string = '';
public description: string = '';
Expand All @@ -69,27 +69,13 @@ export class Vis<TVisParams extends VisParams = VisParams> {

public readonly uiState: PersistedState;

constructor(visType: string, visState: SerializedVis<TVisParams> = {} as any) {
this.type = this.getType(visType);
constructor(visType: BaseVisType<TVisParams>, visState: SerializedVis<TVisParams> = {} as any) {
this.type = visType;
this.params = this.getParams(visState.params);
this.uiState = new PersistedState(visState.uiState);
this.id = visState.id;
}

private getType(visType: string) {
const type = getTypes().get<TVisParams>(visType);
if (!type) {
const errorMessage = i18n.translate('visualizations.visualizationTypeInvalidMessage', {
defaultMessage: 'Invalid visualization type "{visType}"',
values: {
visType,
},
});
throw new Error(errorMessage);
}
return type;
}

private getParams(params: VisParams) {
return defaults({}, cloneDeep(params ?? {}), cloneDeep(this.type.visConfig?.defaults ?? {}));
}
Expand All @@ -109,8 +95,18 @@ export class Vis<TVisParams extends VisParams = VisParams> {

let typeChanged = false;
if (state.type && this.type.name !== state.type) {
// @ts-ignore
this.type = this.getType(state.type);
const newVisType = await getTypes().get<TVisParams>(state.type);
if (!newVisType) {
throw new Error(
i18n.translate('visualizations.visualizationTypeInvalidMessage', {
defaultMessage: 'Invalid visualization type "{visType}"',
values: {
visType: state.type,
},
})
);
}
this.type = newVisType;
typeChanged = true;
}
if (state.title !== undefined) {
Expand Down Expand Up @@ -174,7 +170,7 @@ export class Vis<TVisParams extends VisParams = VisParams> {

clone(): Vis<TVisParams> {
const { data, ...restOfSerialized } = this.serialize();
const vis = new Vis<TVisParams>(this.type.name, restOfSerialized as any);
const vis = new Vis<TVisParams>(this.type, restOfSerialized as any);
vis.setState({ ...restOfSerialized, data: {} });
const aggs = this.data.indexPattern
? getAggs().createAggConfigs(this.data.indexPattern, data.aggs)
Expand Down
Loading
Loading