mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[embeddable] remove setCustomEmbeddableFactoryProvider from setup API (#203853)
Part of https://github.com/elastic/kibana/issues/167429 Remove `setCustomEmbeddableFactoryProvider` from embeddable setup API. `setCustomEmbeddableFactoryProvider` only used in `embeddable_enhanced` plugin. Replaced with `initializeReactEmbeddableDynamicActions` in react embeddable system. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
b059879764
commit
7218d01aa4
12 changed files with 4 additions and 285 deletions
|
@ -99,7 +99,6 @@ const createSetupContract = (): Setup => {
|
|||
registerReactEmbeddableFactory: jest.fn().mockImplementation(registerReactEmbeddableFactory),
|
||||
registerEmbeddableFactory: jest.fn(),
|
||||
registerEnhancement: jest.fn(),
|
||||
setCustomEmbeddableFactoryProvider: jest.fn(),
|
||||
};
|
||||
return setupContract;
|
||||
};
|
||||
|
|
|
@ -9,83 +9,6 @@
|
|||
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { testPlugin } from './tests/test_plugin';
|
||||
import { EmbeddableFactoryProvider } from './types';
|
||||
import { defaultEmbeddableFactoryProvider } from './lib';
|
||||
import { HelloWorldEmbeddable } from './tests/fixtures';
|
||||
|
||||
test('can set custom embeddable factory provider', async () => {
|
||||
const coreSetup = coreMock.createSetup();
|
||||
const coreStart = coreMock.createStart();
|
||||
const { setup, doStart } = testPlugin(coreSetup, coreStart);
|
||||
|
||||
const customProvider: EmbeddableFactoryProvider = (def) => ({
|
||||
...defaultEmbeddableFactoryProvider(def),
|
||||
getDisplayName: () => 'Intercepted!',
|
||||
});
|
||||
|
||||
setup.setCustomEmbeddableFactoryProvider(customProvider);
|
||||
setup.registerEmbeddableFactory('test', {
|
||||
type: 'test',
|
||||
latestVersion: '1.0.0',
|
||||
create: () => Promise.resolve(undefined),
|
||||
getDisplayName: () => 'Test',
|
||||
isEditable: () => Promise.resolve(true),
|
||||
});
|
||||
|
||||
const start = doStart();
|
||||
const factory = start.getEmbeddableFactory('test');
|
||||
expect(factory!.getDisplayName()).toEqual('Intercepted!');
|
||||
});
|
||||
|
||||
test('custom embeddable factory provider test for intercepting embeddable creation and destruction', async () => {
|
||||
const coreSetup = coreMock.createSetup();
|
||||
const coreStart = coreMock.createStart();
|
||||
const { setup, doStart } = testPlugin(coreSetup, coreStart);
|
||||
|
||||
let updateCount = 0;
|
||||
const customProvider: EmbeddableFactoryProvider = (def) => {
|
||||
return {
|
||||
...defaultEmbeddableFactoryProvider(def),
|
||||
create: async (input, parent) => {
|
||||
const embeddable = await defaultEmbeddableFactoryProvider(def).create(input, parent);
|
||||
if (embeddable) {
|
||||
const subscription = embeddable.getInput$().subscribe(
|
||||
() => {
|
||||
updateCount++;
|
||||
},
|
||||
() => {},
|
||||
() => {
|
||||
subscription.unsubscribe();
|
||||
updateCount = 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
return embeddable;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
setup.setCustomEmbeddableFactoryProvider(customProvider);
|
||||
setup.registerEmbeddableFactory('test', {
|
||||
type: 'test',
|
||||
latestVersion: '1.0.0',
|
||||
create: (input, parent) => Promise.resolve(new HelloWorldEmbeddable(input, parent)),
|
||||
getDisplayName: () => 'Test',
|
||||
isEditable: () => Promise.resolve(true),
|
||||
});
|
||||
|
||||
const start = doStart();
|
||||
const factory = start.getEmbeddableFactory('test');
|
||||
|
||||
const embeddable = await factory?.create({ id: '123' });
|
||||
embeddable!.updateInput({ title: 'boo' });
|
||||
// initial subscription, plus the second update.
|
||||
expect(updateCount).toEqual(2);
|
||||
|
||||
embeddable!.destroy();
|
||||
await new Promise((resolve) => process.nextTick(resolve));
|
||||
expect(updateCount).toEqual(0);
|
||||
});
|
||||
|
||||
describe('embeddable factory', () => {
|
||||
const coreSetup = coreMock.createSetup();
|
||||
|
|
|
@ -27,7 +27,6 @@ import type { ContentManagementPublicStart } from '@kbn/content-management-plugi
|
|||
import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public';
|
||||
import {
|
||||
EmbeddableFactoryRegistry,
|
||||
EmbeddableFactoryProvider,
|
||||
EnhancementsRegistry,
|
||||
EnhancementRegistryDefinition,
|
||||
EnhancementRegistryItem,
|
||||
|
@ -108,10 +107,6 @@ export interface EmbeddableSetup {
|
|||
* @deprecated
|
||||
*/
|
||||
registerEnhancement: (enhancement: EnhancementRegistryDefinition) => void;
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
setCustomEmbeddableFactoryProvider: (customProvider: EmbeddableFactoryProvider) => void;
|
||||
}
|
||||
|
||||
export interface EmbeddableStart extends PersistableStateService<EmbeddableStateWithType> {
|
||||
|
@ -137,7 +132,6 @@ export class EmbeddablePublicPlugin implements Plugin<EmbeddableSetup, Embeddabl
|
|||
new Map();
|
||||
private readonly embeddableFactories: EmbeddableFactoryRegistry = new Map();
|
||||
private readonly enhancements: EnhancementsRegistry = new Map();
|
||||
private customEmbeddableFactoryProvider?: EmbeddableFactoryProvider;
|
||||
private stateTransferService: EmbeddableStateTransfer = {} as EmbeddableStateTransfer;
|
||||
private isRegistryReady = false;
|
||||
private appList?: ReadonlyMap<string, PublicAppInfo>;
|
||||
|
@ -154,25 +148,12 @@ export class EmbeddablePublicPlugin implements Plugin<EmbeddableSetup, Embeddabl
|
|||
|
||||
registerEmbeddableFactory: this.registerEmbeddableFactory,
|
||||
registerEnhancement: this.registerEnhancement,
|
||||
setCustomEmbeddableFactoryProvider: (provider: EmbeddableFactoryProvider) => {
|
||||
if (this.customEmbeddableFactoryProvider) {
|
||||
throw new Error(
|
||||
'Custom embeddable factory provider is already set, and can only be set once'
|
||||
);
|
||||
}
|
||||
this.customEmbeddableFactoryProvider = provider;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public start(core: CoreStart, deps: EmbeddableStartDependencies): EmbeddableStart {
|
||||
this.embeddableFactoryDefinitions.forEach((def) => {
|
||||
this.embeddableFactories.set(
|
||||
def.type,
|
||||
this.customEmbeddableFactoryProvider
|
||||
? this.customEmbeddableFactoryProvider(def)
|
||||
: defaultEmbeddableFactoryProvider(def)
|
||||
);
|
||||
this.embeddableFactories.set(def.type, defaultEmbeddableFactoryProvider(def));
|
||||
});
|
||||
|
||||
this.appListSubscription = core.application.applications$.subscribe((appList) => {
|
||||
|
@ -311,12 +292,7 @@ export class EmbeddablePublicPlugin implements Plugin<EmbeddableSetup, Embeddabl
|
|||
if (!this.embeddableFactories.get(type)) {
|
||||
const def = this.embeddableFactoryDefinitions.get(type);
|
||||
if (!def) return;
|
||||
this.embeddableFactories.set(
|
||||
type,
|
||||
this.customEmbeddableFactoryProvider
|
||||
? this.customEmbeddableFactoryProvider(def)
|
||||
: defaultEmbeddableFactoryProvider(def)
|
||||
);
|
||||
this.embeddableFactories.set(type, defaultEmbeddableFactoryProvider(def));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15942,7 +15942,6 @@
|
|||
"xpack.elasticAssistantPlugin.attackDiscovery.defaultAttackDiscoveryGraph.nodes.retriever.helpers.throwIfErrorCountsExceeded.maxGenerationAttemptsErrorMessage": "Nombre maximum de tentatives de génération ({generationAttempts}) atteint. Essayez d'envoyer un nombre d'alertes moins élevé à ce modèle.",
|
||||
"xpack.elasticAssistantPlugin.attackDiscovery.defaultAttackDiscoveryGraph.nodes.retriever.helpers.throwIfErrorCountsExceeded.maxHallucinationFailuresErrorMessage": "Nombre maximum d'échecs d'hallucinations ({hallucinationFailures}) atteint. Essayez d'envoyer un nombre d'alertes moins élevé à ce modèle.",
|
||||
"xpack.elasticAssistantPlugin.server.newChat": "Nouveau chat",
|
||||
"xpack.embeddableEnhanced.Drilldowns": "Explorations",
|
||||
"xpack.enterpriseSearch.accessControlIndexSelector.p.accessControlSyncsAreLabel": "Les synchronisations de contrôle d'accès maintiennent les informations d'autorisation à jour pour assurer la sécurité au niveau du document (DLS)",
|
||||
"xpack.enterpriseSearch.actions.backButtonLabel": "Retour",
|
||||
"xpack.enterpriseSearch.actions.cancelButtonLabel": "Annuler",
|
||||
|
|
|
@ -15805,7 +15805,6 @@
|
|||
"xpack.elasticAssistantPlugin.attackDiscovery.defaultAttackDiscoveryGraph.nodes.retriever.helpers.throwIfErrorCountsExceeded.maxGenerationAttemptsErrorMessage": "最大生成試行回数({generationAttempts})に達しました。このモデルに送信するアラートの数を減らしてください。",
|
||||
"xpack.elasticAssistantPlugin.attackDiscovery.defaultAttackDiscoveryGraph.nodes.retriever.helpers.throwIfErrorCountsExceeded.maxHallucinationFailuresErrorMessage": "最大ハルシネーション失敗回数({hallucinationFailures})に達しました。このモデルに送信するアラートの数を減らしてください。",
|
||||
"xpack.elasticAssistantPlugin.server.newChat": "新しいチャット",
|
||||
"xpack.embeddableEnhanced.Drilldowns": "ドリルダウン",
|
||||
"xpack.enterpriseSearch.accessControlIndexSelector.p.accessControlSyncsAreLabel": "アクセス制御の同期により、ドキュメントレベルセキュリティ(DLS)の権限情報が最新の状態に保たれます。",
|
||||
"xpack.enterpriseSearch.actions.backButtonLabel": "戻る",
|
||||
"xpack.enterpriseSearch.actions.cancelButtonLabel": "キャンセル",
|
||||
|
|
|
@ -15525,7 +15525,6 @@
|
|||
"xpack.elasticAssistantPlugin.attackDiscovery.defaultAttackDiscoveryGraph.nodes.retriever.helpers.throwIfErrorCountsExceeded.maxGenerationAttemptsErrorMessage": "已达到最大生成尝试次数 ({generationAttempts})。尝试向此模型发送更少的告警。",
|
||||
"xpack.elasticAssistantPlugin.attackDiscovery.defaultAttackDiscoveryGraph.nodes.retriever.helpers.throwIfErrorCountsExceeded.maxHallucinationFailuresErrorMessage": "已达到最大幻觉失败次数 ({hallucinationFailures})。尝试向此模型发送更少的告警。",
|
||||
"xpack.elasticAssistantPlugin.server.newChat": "新聊天",
|
||||
"xpack.embeddableEnhanced.Drilldowns": "向下钻取",
|
||||
"xpack.enterpriseSearch.accessControlIndexSelector.p.accessControlSyncsAreLabel": "访问控制同步会使权限信息保持最新以实现文档级别安全性 (DLS)",
|
||||
"xpack.enterpriseSearch.actions.backButtonLabel": "返回",
|
||||
"xpack.enterpriseSearch.actions.cancelButtonLabel": "取消",
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { UiActionsPresentableGrouping as PresentableGrouping } from '@kbn/ui-actions-plugin/public';
|
||||
|
||||
export const drilldownGrouping: PresentableGrouping = [
|
||||
{
|
||||
id: 'drilldowns',
|
||||
getDisplayName: () =>
|
||||
i18n.translate('xpack.embeddableEnhanced.Drilldowns', {
|
||||
defaultMessage: 'Drilldowns',
|
||||
}),
|
||||
getIconType: () => 'symlink',
|
||||
order: 25,
|
||||
},
|
||||
];
|
|
@ -1,8 +0,0 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export * from './drilldown_grouping';
|
|
@ -19,9 +19,7 @@ export function plugin(context: PluginInitializerContext) {
|
|||
return new EmbeddableEnhancedPlugin(context);
|
||||
}
|
||||
|
||||
export type { EnhancedEmbeddable, EnhancedEmbeddableContext } from './types';
|
||||
export {
|
||||
type HasDynamicActions,
|
||||
apiHasDynamicActions,
|
||||
} from './embeddables/interfaces/has_dynamic_actions';
|
||||
export { drilldownGrouping as embeddableEnhancedDrilldownGrouping } from './actions';
|
||||
|
|
|
@ -6,23 +6,12 @@
|
|||
*/
|
||||
|
||||
import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public';
|
||||
import {
|
||||
defaultEmbeddableFactoryProvider,
|
||||
EmbeddableContext,
|
||||
EmbeddableFactory,
|
||||
EmbeddableFactoryDefinition,
|
||||
EmbeddableInput,
|
||||
EmbeddableOutput,
|
||||
EmbeddableSetup,
|
||||
EmbeddableStart,
|
||||
IEmbeddable,
|
||||
} from '@kbn/embeddable-plugin/public';
|
||||
import { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public';
|
||||
import {
|
||||
apiHasUniqueId,
|
||||
EmbeddableApiContext,
|
||||
StateComparators,
|
||||
} from '@kbn/presentation-publishing';
|
||||
import type { FinderAttributes } from '@kbn/saved-objects-finder-plugin/common';
|
||||
import {
|
||||
AdvancedUiActionsSetup,
|
||||
AdvancedUiActionsStart,
|
||||
|
@ -30,13 +19,12 @@ import {
|
|||
UiActionsEnhancedDynamicActionManager as DynamicActionManager,
|
||||
} from '@kbn/ui-actions-enhanced-plugin/public';
|
||||
import deepEqual from 'react-fast-compare';
|
||||
import { BehaviorSubject, distinctUntilChanged } from 'rxjs';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import {
|
||||
DynamicActionStorage,
|
||||
type DynamicActionStorageApi,
|
||||
} from './embeddables/dynamic_action_storage';
|
||||
import { HasDynamicActions } from './embeddables/interfaces/has_dynamic_actions';
|
||||
import { EnhancedEmbeddable } from './types';
|
||||
import { getDynamicActionsState } from './get_dynamic_actions_state';
|
||||
|
||||
export interface SetupDependencies {
|
||||
|
@ -79,8 +67,6 @@ export class EmbeddableEnhancedPlugin
|
|||
private uiActions?: StartDependencies['uiActionsEnhanced'];
|
||||
|
||||
public setup(core: CoreSetup<StartDependencies>, plugins: SetupDependencies): SetupContract {
|
||||
this.setCustomEmbeddableFactoryProvider(plugins);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -94,45 +80,6 @@ export class EmbeddableEnhancedPlugin
|
|||
|
||||
public stop() {}
|
||||
|
||||
private setCustomEmbeddableFactoryProvider(plugins: SetupDependencies) {
|
||||
plugins.embeddable.setCustomEmbeddableFactoryProvider(
|
||||
<
|
||||
I extends EmbeddableInput = EmbeddableInput,
|
||||
O extends EmbeddableOutput = EmbeddableOutput,
|
||||
E extends IEmbeddable<I, O> = IEmbeddable<I, O>,
|
||||
T extends FinderAttributes = {}
|
||||
>(
|
||||
def: EmbeddableFactoryDefinition<I, O, E, T>
|
||||
): EmbeddableFactory<I, O, E, T> => {
|
||||
const factory: EmbeddableFactory<I, O, E, T> = defaultEmbeddableFactoryProvider<I, O, E, T>(
|
||||
def
|
||||
);
|
||||
return {
|
||||
...factory,
|
||||
create: async (...args) => {
|
||||
const embeddable = await factory.create(...args);
|
||||
if (!embeddable) return embeddable;
|
||||
return this.enhanceEmbeddableWithDynamicActions(embeddable);
|
||||
},
|
||||
createFromSavedObject: async (...args) => {
|
||||
const embeddable = await factory.createFromSavedObject(...args);
|
||||
if (!embeddable) return embeddable;
|
||||
return this.enhanceEmbeddableWithDynamicActions(embeddable);
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private readonly isEmbeddableContext = (context: unknown): context is EmbeddableContext => {
|
||||
if (!(context as EmbeddableContext)?.embeddable) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('For drilldowns to work action context should contain .embeddable field.');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
private initializeDynamicActions(
|
||||
uuid: string,
|
||||
getTitle: () => string | undefined,
|
||||
|
@ -183,77 +130,6 @@ export class EmbeddableEnhancedPlugin
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Remove this entire enhanceEmbeddableWithDynamicActions method once the embeddable refactor work is complete
|
||||
*/
|
||||
private enhanceEmbeddableWithDynamicActions<E extends IEmbeddable>(
|
||||
embeddable: E
|
||||
): EnhancedEmbeddable<E> {
|
||||
const enhancedEmbeddable = embeddable as EnhancedEmbeddable<E>;
|
||||
|
||||
const dynamicActionsState$ = new BehaviorSubject<DynamicActionsSerializedState['enhancements']>(
|
||||
{
|
||||
dynamicActions: { events: [] },
|
||||
...(embeddable.getInput().enhancements ?? {}),
|
||||
}
|
||||
);
|
||||
const api = {
|
||||
dynamicActionsState$,
|
||||
setDynamicActions: (newState: DynamicActionsSerializedState['enhancements']) => {
|
||||
embeddable.updateInput({ enhancements: newState });
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Keep the dynamicActionsState$ publishing subject in sync with changes to the embeddable's input.
|
||||
*/
|
||||
embeddable
|
||||
.getInput$()
|
||||
.pipe(
|
||||
distinctUntilChanged(({ enhancements: old }, { enhancements: updated }) =>
|
||||
deepEqual(old, updated)
|
||||
)
|
||||
)
|
||||
.subscribe((input) => {
|
||||
dynamicActionsState$.next({
|
||||
dynamicActions: { events: [] },
|
||||
...(input.enhancements ?? {}),
|
||||
} as DynamicActionsSerializedState['enhancements']);
|
||||
});
|
||||
|
||||
const storage = new DynamicActionStorage(
|
||||
String(embeddable.runtimeId),
|
||||
embeddable.getTitle,
|
||||
api
|
||||
);
|
||||
const dynamicActions = new DynamicActionManager({
|
||||
isCompatible: async (context: unknown) => {
|
||||
if (!this.isEmbeddableContext(context)) return false;
|
||||
return context.embeddable.runtimeId === embeddable.runtimeId;
|
||||
},
|
||||
storage,
|
||||
uiActions: this.uiActions!,
|
||||
});
|
||||
|
||||
const stop = this.startDynamicActions(dynamicActions);
|
||||
embeddable.getInput$().subscribe({
|
||||
next: () => {
|
||||
storage.reload$.next();
|
||||
},
|
||||
error: stop,
|
||||
complete: stop,
|
||||
});
|
||||
|
||||
enhancedEmbeddable.enhancements = {
|
||||
...enhancedEmbeddable.enhancements,
|
||||
dynamicActions,
|
||||
};
|
||||
enhancedEmbeddable.dynamicActionsState$ = api.dynamicActionsState$;
|
||||
enhancedEmbeddable.setDynamicActions = api.setDynamicActions;
|
||||
|
||||
return enhancedEmbeddable;
|
||||
}
|
||||
|
||||
private startDynamicActions(dynamicActions: DynamicActionManager) {
|
||||
dynamicActions.start().catch((error) => {
|
||||
/* eslint-disable no-console */
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { IEmbeddable } from '@kbn/embeddable-plugin/public';
|
||||
import { HasDynamicActions } from './embeddables/interfaces/has_dynamic_actions';
|
||||
|
||||
export type EnhancedEmbeddable<E extends IEmbeddable = IEmbeddable> = E & HasDynamicActions;
|
||||
|
||||
/**
|
||||
* @deprecated use `EmbeddableApiContext` from `@kbn/presentation-publishing`
|
||||
*/
|
||||
export interface EnhancedEmbeddableContext {
|
||||
embeddable: EnhancedEmbeddable;
|
||||
}
|
|
@ -9,12 +9,9 @@
|
|||
"kbn_references": [
|
||||
"@kbn/core",
|
||||
"@kbn/embeddable-plugin",
|
||||
"@kbn/ui-actions-plugin",
|
||||
"@kbn/ui-actions-enhanced-plugin",
|
||||
"@kbn/i18n",
|
||||
"@kbn/kibana-utils-plugin",
|
||||
"@kbn/data-plugin",
|
||||
"@kbn/saved-objects-finder-plugin",
|
||||
"@kbn/presentation-publishing",
|
||||
],
|
||||
"exclude": [
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue