Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ describe('checking migration metadata changes on all registered SO types', () =>
"application_usage_daily": "20142d23fe5d05ba22b4bc46614d99883bc488f0",
"application_usage_totals": "a29ab014edc20382b9ce22ede221b18cee5d93a6",
"background-task-node": "e61f0ea9923fa05b3af0aae6c6baf2f0283e14b3",
"canvas-element": "cdedc2123eb8a1506b87a56b0bcce60f4ec08bc8",
"canvas-workpad": "9d82aafb19586b119e5c9382f938abe28c26ca5c",
"canvas-workpad-template": "c077b0087346776bb3542b51e1385d172cb24179",
"canvas-element": "5cea187f4d74520e3da36b18e465e91d344fad3e",
"canvas-workpad": "b38728356a6ee25d560f519671735fdbadf4604a",
"canvas-workpad-template": "e32ebe04845a65e33fd441c3d0ab47053c2e3016",
"cases": "91771732e2e488e4c1b1ac468057925d1c6b32b5",
"cases-comments": "5cb0a421588831c2a950e50f486048b8aabbae25",
"cases-configure": "44ed7b8e0f44df39516b8870589b89e32224d2bf",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { EmbeddablePersistableStateService } from '@kbn/embeddable-plugin/common';
import { EmbeddableRegistryDefinition } from '@kbn/embeddable-plugin/server';
import { CONTROL_GROUP_TYPE } from '../../common';
import type { EmbeddableRegistryItem } from '@kbn/embeddable-plugin/server';
import type { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common';
import type { PersistableStateService } from '@kbn/kibana-utils-plugin/common';
import {
createControlGroupExtract,
createControlGroupInject,
Expand All @@ -18,13 +18,12 @@ import {
import { controlGroupTelemetry } from './control_group_telemetry';

export const controlGroupContainerPersistableStateServiceFactory = (
persistableStateService: EmbeddablePersistableStateService
): EmbeddableRegistryDefinition => {
getControlsFactory: (controlFactoryId: string) => EmbeddableRegistryItem
): PersistableStateService<EmbeddableStateWithType> => {
return {
id: CONTROL_GROUP_TYPE,
extract: createControlGroupExtract(persistableStateService),
inject: createControlGroupInject(persistableStateService),
extract: createControlGroupExtract(getControlsFactory),
inject: createControlGroupInject(getControlsFactory),
telemetry: controlGroupTelemetry,
migrations,
getAllMigrations: () => migrations,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,24 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { SavedObjectReference } from '@kbn/core/types';
import {
EmbeddableInput,
EmbeddablePersistableStateService,
EmbeddableStateWithType,
} from '@kbn/embeddable-plugin/common/types';
import type { SavedObjectReference } from '@kbn/core/server';
import { EmbeddableInput, EmbeddableStateWithType } from '@kbn/embeddable-plugin/common/types';
import { MigrateFunctionsObject } from '@kbn/kibana-utils-plugin/common';

import { EmbeddableRegistryItem } from '@kbn/embeddable-plugin/server/types';
import type { ControlPanelsState, SerializedControlState } from '../../common';
import {
makeControlOrdersZeroBased,
removeHideExcludeAndHideExists,
} from './control_group_migrations';
import { SerializableControlGroupState } from './types';
import { ControlsPersistableStateService } from '../types';

const getPanelStatePrefix = (state: SerializedControlState) => `${state.explicitInput.id}:`;

export const createControlGroupInject = (
persistableStateService: EmbeddablePersistableStateService
): EmbeddablePersistableStateService['inject'] => {
getControlsFactory: (controlsFactoryId: string) => EmbeddableRegistryItem
): ControlsPersistableStateService['inject'] => {
return (state: EmbeddableStateWithType, references: SavedObjectReference[]) => {
const workingState = { ...state } as EmbeddableStateWithType | SerializableControlGroupState;

Expand All @@ -46,8 +44,8 @@ export const createControlGroupInject = (
.map((reference) => ({ ...reference, name: reference.name.replace(prefix, '') }));

const panelReferences = filteredReferences.length === 0 ? references : filteredReferences;

const { type, ...injectedState } = persistableStateService.inject(
const factory = getControlsFactory(workingPanels[key].type);
const { type, ...injectedState } = factory.inject(
{ ...workingPanels[key].explicitInput, type: workingPanels[key].type },
panelReferences
);
Expand All @@ -59,8 +57,8 @@ export const createControlGroupInject = (
};

export const createControlGroupExtract = (
persistableStateService: EmbeddablePersistableStateService
): EmbeddablePersistableStateService['extract'] => {
getControlsFactory: (controlsFactoryId: string) => EmbeddableRegistryItem
): ControlsPersistableStateService['extract'] => {
return (state: EmbeddableStateWithType) => {
const workingState = { ...state } as EmbeddableStateWithType | SerializableControlGroupState;
const references: SavedObjectReference[] = [];
Expand All @@ -72,7 +70,8 @@ export const createControlGroupExtract = (
for (const [key, panel] of Object.entries(workingState.panels)) {
const prefix = getPanelStatePrefix(panel);

const { state: panelState, references: panelReferences } = persistableStateService.extract({
const factory = getControlsFactory(panel.type);
const { state: panelState, references: panelReferences } = factory.extract({
...panel.explicitInput,
type: panel.type,
});
Expand Down
1 change: 1 addition & 0 deletions src/platform/plugins/shared/controls/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ export {
export { initializeControlGroupTelemetry } from './control_group/control_group_telemetry';

export type { ControlGroupTelemetry } from './control_group/types';
export type { ControlsSetup, ControlsStart } from './types';
8 changes: 8 additions & 0 deletions src/platform/plugins/shared/controls/server/mocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import type { OptionsListControlState } from '../common/options_list';
import type { DefaultDataControlState } from '../common/types';
import { ControlsSetup } from './types';

export const mockDataControlState = {
id: 'id',
Expand All @@ -24,3 +25,10 @@ export const mockOptionsListControlState = {
singleSelect: false,
exclude: false,
} as OptionsListControlState;

export const createControlsSetupMock = (): jest.Mocked<ControlsSetup> => ({
telemetry: jest.fn((state, collector) => ({})),
inject: jest.fn((state, references) => state),
extract: jest.fn((state) => ({ state, references: [] })),
getAllMigrations: jest.fn().mockReturnValue({}),
});
62 changes: 46 additions & 16 deletions src/platform/plugins/shared/controls/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,71 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { CoreSetup, Plugin } from '@kbn/core/server';
import { PluginSetup as DataSetup } from '@kbn/data-plugin/server';
import { EmbeddableSetup } from '@kbn/embeddable-plugin/server';
import { PluginSetup as UnifiedSearchSetup } from '@kbn/unified-search-plugin/server';
import type { CoreSetup, Plugin } from '@kbn/core/server';
import type { PluginSetup as DataSetup } from '@kbn/data-plugin/server';
import type { EmbeddableRegistryDefinition } from '@kbn/embeddable-plugin/server';
import type { PluginSetup as UnifiedSearchSetup } from '@kbn/unified-search-plugin/server';
import type {
EmbeddableFactoryRegistry,
EmbeddableRegistryItem,
} from '@kbn/embeddable-plugin/server/types';
import { setupOptionsListSuggestionsRoute } from './options_list/options_list_suggestions_route';
import { controlGroupContainerPersistableStateServiceFactory } from './control_group/control_group_container_factory';
import { optionsListPersistableStateServiceFactory } from './options_list/options_list_embeddable_factory';
import { rangeSliderPersistableStateServiceFactory } from './range_slider/range_slider_embeddable_factory';
import { timeSliderPersistableStateServiceFactory } from './time_slider/time_slider_embeddable_factory';
import { esqlStaticControlPersistableStateServiceFactory } from './esql_control/esql_control_factory';
import { setupOptionsListClusterSettingsRoute } from './options_list/options_list_cluster_settings_route';
import { ControlsSetup, ControlsStart } from './types';

interface SetupDeps {
embeddable: EmbeddableSetup;
data: DataSetup;
unifiedSearch: UnifiedSearchSetup;
}

export class ControlsPlugin implements Plugin<object, object, SetupDeps> {
public setup(core: CoreSetup, { embeddable, unifiedSearch }: SetupDeps) {
embeddable.registerEmbeddableFactory(
controlGroupContainerPersistableStateServiceFactory(embeddable)
);
embeddable.registerEmbeddableFactory(optionsListPersistableStateServiceFactory());
embeddable.registerEmbeddableFactory(rangeSliderPersistableStateServiceFactory());
embeddable.registerEmbeddableFactory(timeSliderPersistableStateServiceFactory());
embeddable.registerEmbeddableFactory(esqlStaticControlPersistableStateServiceFactory());
export class ControlsPlugin implements Plugin<ControlsSetup, ControlsStart, SetupDeps> {
private readonly controlsFactories: EmbeddableFactoryRegistry = new Map();

public setup(core: CoreSetup, { unifiedSearch }: SetupDeps) {
this.registerControlsFactory(optionsListPersistableStateServiceFactory());
this.registerControlsFactory(rangeSliderPersistableStateServiceFactory());
this.registerControlsFactory(timeSliderPersistableStateServiceFactory());
this.registerControlsFactory(esqlStaticControlPersistableStateServiceFactory());

setupOptionsListClusterSettingsRoute(core);
setupOptionsListSuggestionsRoute(core, unifiedSearch.autocomplete.getAutocompleteSettings);
return {};
return controlGroupContainerPersistableStateServiceFactory(this.getControlsFactory);
}

public start() {
return {};
return controlGroupContainerPersistableStateServiceFactory(this.getControlsFactory);
}

public stop() {}

private registerControlsFactory = (factory: EmbeddableRegistryDefinition) => {
if (this.controlsFactories.has(factory.id)) {
throw new Error(`Control factory with id ${factory.id} already exists`);
}

this.controlsFactories.set(factory.id, {
id: factory.id,
telemetry: factory.telemetry ?? ((state, stats) => stats),
inject: factory.inject ?? ((state) => state),
extract: factory.extract ?? ((state) => ({ state, references: [] })),
migrations: factory.migrations ?? {},
});
};

private getControlsFactory = (controlsFactoryId: string): EmbeddableRegistryItem => {
return (
this.controlsFactories.get(controlsFactoryId) ?? {
id: controlsFactoryId,
telemetry: (state, stats) => stats,
inject: (state) => state,
extract: (state) => ({ state, references: [] }),
migrations: {},
}
);
};
}
15 changes: 15 additions & 0 deletions src/platform/plugins/shared/controls/server/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* 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".
*/

import { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common';
import { PersistableStateService } from '@kbn/kibana-utils-plugin/common';

export type ControlsPersistableStateService = PersistableStateService<EmbeddableStateWithType>;
export type ControlsSetup = ControlsPersistableStateService;
export type ControlsStart = ControlsPersistableStateService;
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,21 @@ import {
type ModelVersionTestMigrator,
} from '@kbn/core-test-helpers-model-versions';
import { createEmbeddableSetupMock } from '@kbn/embeddable-plugin/server/mocks';
import { createControlsSetupMock } from '@kbn/controls-plugin/server/mocks';

import { createDashboardSavedObjectType } from './dashboard_saved_object';

const embeddableSetupMock = createEmbeddableSetupMock();
const controlsSetupMock = createControlsSetupMock();

describe('dashboard saved object model version transformations', () => {
let migrator: ModelVersionTestMigrator;

beforeEach(() => {
migrator = createModelVersionTestMigrator({
type: createDashboardSavedObjectType({ migrationDeps: { embeddable: embeddableSetupMock } }),
type: createDashboardSavedObjectType({
migrationDeps: { embeddable: embeddableSetupMock, controls: controlsSetupMock },
}),
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import { SavedObjectReference, SavedObjectUnsanitizedDoc } from '@kbn/core/serve
import { SavedObjectsUtils } from '@kbn/core-saved-objects-utils-server';

import { createExtract, createInject } from '../../../common';
import { createControlsSetupMock } from '@kbn/controls-plugin/server/mocks';
import { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common';
import { createDashboardSavedObjectTypeMigrations } from './dashboard_saved_object_migrations';
import { DashboardDoc730ToLatest } from './migrate_to_730/types';

const embeddableSetupMock = createEmbeddableSetupMock();
const controlsSetupMock = createControlsSetupMock();
const extract = createExtract(embeddableSetupMock);
const inject = createInject(embeddableSetupMock);
const extractImplementation = (state: EmbeddableStateWithType) => {
Expand All @@ -43,6 +45,7 @@ embeddableSetupMock.getAllMigrations.mockImplementation(() => ({}));

const migrations = createDashboardSavedObjectTypeMigrations({
embeddable: embeddableSetupMock,
controls: controlsSetupMock,
});

const contextMock = savedObjectsServiceMock.createMigrationContext();
Expand Down Expand Up @@ -702,6 +705,7 @@ describe('dashboard', () => {
}));
const migrationsList = createDashboardSavedObjectTypeMigrations({
embeddable: newEmbeddableSetupMock,
controls: controlsSetupMock,
});
expect(migrationsList['7.13.0']).toBeDefined();
const migratedDoc = SavedObjectsUtils.getMigrationFunction(migrationsList['7.13.0'])(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
mergeMigrationFunctionMaps,
MigrateFunctionsObject,
} from '@kbn/kibana-utils-plugin/common';
import { ControlsSetup } from '@kbn/controls-plugin/server';
import { EmbeddableSetup } from '@kbn/embeddable-plugin/server';
import { SavedObjectMigrationFn, SavedObjectMigrationMap } from '@kbn/core/server';

Expand All @@ -25,6 +26,7 @@ import { createExtractPanelReferencesMigration } from './migrate_extract_panel_r

export interface DashboardSavedObjectTypeMigrationsDeps {
embeddable: EmbeddableSetup;
controls: ControlsSetup;
}

export const createDashboardSavedObjectTypeMigrations = (
Expand All @@ -35,6 +37,10 @@ export const createDashboardSavedObjectTypeMigrations = (
migrateByValueDashboardPanels
) as MigrateFunctionsObject;

const controlsMigrations = deps.controls.getAllMigrations();

const dependencyMigrations = mergeMigrationFunctionMaps(embeddableMigrations, controlsMigrations);

const dashboardMigrations = {
'6.7.2': flow(migrateMatchAllQuery),
'7.0.0': flow(migrations700),
Expand All @@ -45,5 +51,5 @@ export const createDashboardSavedObjectTypeMigrations = (
'7.17.3': flow(migrateExplicitlyHiddenTitles),
};

return mergeMigrationFunctionMaps(dashboardMigrations, embeddableMigrations);
return mergeMigrationFunctionMaps(dashboardMigrations, dependencyMigrations);
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import { savedObjectsServiceMock } from '@kbn/core/server/mocks';
import { createControlsSetupMock } from '@kbn/controls-plugin/server/mocks';
import { createEmbeddableSetupMock } from '@kbn/embeddable-plugin/server/mocks';
import { SavedObjectsUtils } from '@kbn/core-saved-objects-utils-server';

Expand All @@ -23,6 +24,7 @@ import { createDashboardSavedObjectTypeMigrations } from '../dashboard_saved_obj
const mockContext = savedObjectsServiceMock.createMigrationContext();
const migrations = createDashboardSavedObjectTypeMigrations({
embeddable: createEmbeddableSetupMock(),
controls: createControlsSetupMock(),
});

test('dashboard migration 7.3.0 migrates filters to query on search source', () => {
Expand Down
11 changes: 10 additions & 1 deletion src/platform/plugins/shared/dashboard/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { ContentManagementServerSetup } from '@kbn/content-management-plugin/ser
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from '@kbn/core/server';
import { registerContentInsights } from '@kbn/content-management-content-insights-server';

import { ControlsSetup } from '@kbn/controls-plugin/server';
import {
initializeDashboardTelemetryTask,
scheduleDashboardTelemetry,
Expand All @@ -34,6 +35,7 @@ import { registerAPIRoutes } from './api';

interface SetupDeps {
embeddable: EmbeddableSetup;
controls: ControlsSetup;
usageCollection?: UsageCollectionSetup;
taskManager: TaskManagerSetupContract;
contentManagement: ContentManagementServerSetup;
Expand All @@ -60,6 +62,7 @@ export class DashboardPlugin
createDashboardSavedObjectType({
migrationDeps: {
embeddable: plugins.embeddable,
controls: plugins.controls,
},
})
);
Expand All @@ -78,7 +81,13 @@ export class DashboardPlugin
plugins.contentManagement.favorites.registerFavoriteType('dashboard');

if (plugins.taskManager) {
initializeDashboardTelemetryTask(this.logger, core, plugins.taskManager, plugins.embeddable);
initializeDashboardTelemetryTask(
this.logger,
core,
plugins.taskManager,
plugins.controls,
plugins.embeddable
);
}
core.capabilities.registerProvider(capabilitiesProvider);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@ export const collectPanelsByType = (
};

export const controlsCollectorFactory =
(embeddableService: EmbeddablePersistableStateService) =>
(controlsService: EmbeddablePersistableStateService) =>
(attributes: DashboardSavedObjectAttributes, collectorData: DashboardCollectorData) => {
if (!isEmpty(attributes.controlGroupInput)) {
collectorData.controls = embeddableService.telemetry(
collectorData.controls = controlsService.telemetry(
{
...attributes.controlGroupInput,
type: CONTROL_GROUP_TYPE,
Expand Down
Loading