[8.x] [controls] lazy load control actions (#206876) (#207277)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[controls] lazy load control actions
(#206876)](https://github.com/elastic/kibana/pull/206876)

<!--- Backport version: 9.6.4 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Nathan
Reese","email":"reese.nathan@elastic.co"},"sourceCommit":{"committedDate":"2025-01-20T21:00:48Z","message":"[controls]
lazy load control actions (#206876)\n\n* register control actions with
async method\r\n* move floating actions into controls plugin\r\n*
replace `PANEL_HOVER_TRIGGER` => `CONTROL_HOVER_TRIGGER`\r\n* Load
controls in single chunk\r\n<img width=\"400\" alt=\"Screenshot
2025-01-16 at 11 40
08 AM\"\r\nsrc=\"https://github.com/user-attachments/assets/3171c9bf-26bc-4c07-950d-c35603cfb65a\"\r\n/>\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"f4df5856f249552f01ccb020a3ffd90c1517b71d","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Embedding","Team:Presentation","release_note:skip","v9.0.0","project:embeddableRebuild","backport:version","v8.18.0"],"title":"[controls]
lazy load control
actions","number":206876,"url":"https://github.com/elastic/kibana/pull/206876","mergeCommit":{"message":"[controls]
lazy load control actions (#206876)\n\n* register control actions with
async method\r\n* move floating actions into controls plugin\r\n*
replace `PANEL_HOVER_TRIGGER` => `CONTROL_HOVER_TRIGGER`\r\n* Load
controls in single chunk\r\n<img width=\"400\" alt=\"Screenshot
2025-01-16 at 11 40
08 AM\"\r\nsrc=\"https://github.com/user-attachments/assets/3171c9bf-26bc-4c07-950d-c35603cfb65a\"\r\n/>\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"f4df5856f249552f01ccb020a3ffd90c1517b71d"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/206876","number":206876,"mergeCommit":{"message":"[controls]
lazy load control actions (#206876)\n\n* register control actions with
async method\r\n* move floating actions into controls plugin\r\n*
replace `PANEL_HOVER_TRIGGER` => `CONTROL_HOVER_TRIGGER`\r\n* Load
controls in single chunk\r\n<img width=\"400\" alt=\"Screenshot
2025-01-16 at 11 40
08 AM\"\r\nsrc=\"https://github.com/user-attachments/assets/3171c9bf-26bc-4c07-950d-c35603cfb65a\"\r\n/>\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by:
Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"f4df5856f249552f01ccb020a3ffd90c1517b71d"}},{"branch":"8.x","label":"v8.18.0","branchLabelMappingKey":"^v8.18.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
This commit is contained in:
Nathan Reese 2025-01-21 06:37:49 -07:00 committed by GitHub
parent 216d9b58b2
commit c570a3431f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
35 changed files with 204 additions and 232 deletions

View file

@ -19,7 +19,7 @@ pageLoadAssetSize:
cloudSecurityPosture: 19109
console: 46091
contentManagement: 16254
controls: 60000
controls: 12000
core: 564663
crossClusterReplication: 65408
customIntegrations: 22034
@ -38,7 +38,7 @@ pageLoadAssetSize:
discover: 99999
discoverEnhanced: 42730
discoverShared: 17111
embeddable: 87309
embeddable: 24000
embeddableEnhanced: 22107
enterpriseSearch: 66810
entityManager: 17175
@ -123,8 +123,8 @@ pageLoadAssetSize:
observabilityShared: 111036
osquery: 107090
painlessLab: 179748
presentationPanel: 11501
presentationUtil: 33186
presentationPanel: 12000
presentationUtil: 25000
productDocBase: 22500
profiling: 36694
remoteClusters: 51327

View file

@ -11,9 +11,7 @@ export {
contextMenuTrigger,
CONTEXT_MENU_TRIGGER,
panelBadgeTrigger,
panelHoverTrigger,
panelNotificationTrigger,
PANEL_BADGE_TRIGGER,
PANEL_HOVER_TRIGGER,
PANEL_NOTIFICATION_TRIGGER,
} from './triggers';

View file

@ -21,17 +21,6 @@ export const contextMenuTrigger: Trigger = {
}),
};
export const PANEL_HOVER_TRIGGER = 'PANEL_HOVER_TRIGGER';
export const panelHoverTrigger: Trigger = {
id: PANEL_HOVER_TRIGGER,
title: i18n.translate('presentationPanel.hoverTrigger.title', {
defaultMessage: 'Panel hover',
}),
description: i18n.translate('presentationPanel.hoverTrigger.description', {
defaultMessage: "A new action will be added to the panel's hover menu",
}),
};
export const PANEL_BADGE_TRIGGER = 'PANEL_BADGE_TRIGGER';
export const panelBadgeTrigger: Trigger = {
id: PANEL_BADGE_TRIGGER,

View file

@ -11,15 +11,43 @@ import React, { SyntheticEvent } from 'react';
import { EuiButtonIcon, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import type { EmbeddableApiContext, HasUniqueId } from '@kbn/presentation-publishing';
import {
apiCanAccessViewMode,
apiHasParentApi,
apiHasType,
apiHasUniqueId,
apiIsOfType,
HasParentApi,
type EmbeddableApiContext,
type HasUniqueId,
HasType,
} from '@kbn/presentation-publishing';
import {
IncompatibleActionError,
FrequentCompatibilityChangeAction,
type Action,
} from '@kbn/ui-actions-plugin/public';
import { isClearableControl } from '../types';
import { PresentationContainer, apiIsPresentationContainer } from '@kbn/presentation-containers';
import { CONTROL_GROUP_TYPE } from '../../common';
import { CanClearSelections, isClearableControl } from '../types';
import { ACTION_CLEAR_CONTROL } from '.';
import { ACTION_CLEAR_CONTROL } from './constants';
type ClearControlActionApi = HasType &
HasUniqueId &
CanClearSelections &
HasParentApi<PresentationContainer & HasType>;
const compatibilityCheck = (api: unknown | null): api is ClearControlActionApi =>
Boolean(
apiHasType(api) &&
apiHasUniqueId(api) &&
isClearableControl(api) &&
apiHasParentApi(api) &&
apiCanAccessViewMode(api.parentApi) &&
apiIsOfType(api.parentApi, CONTROL_GROUP_TYPE) &&
apiIsPresentationContainer(api.parentApi)
);
export class ClearControlAction
implements Action<EmbeddableApiContext>, FrequentCompatibilityChangeAction<EmbeddableApiContext>
@ -73,12 +101,10 @@ export class ClearControlAction
}
public async isCompatible({ embeddable }: EmbeddableApiContext) {
const { isCompatible } = await import('./clear_control_action_compatibility_check');
return isCompatible(embeddable);
return compatibilityCheck(embeddable);
}
public async execute({ embeddable }: EmbeddableApiContext) {
const { compatibilityCheck } = await import('./clear_control_action_compatibility_check');
if (!compatibilityCheck(embeddable)) throw new IncompatibleActionError();
embeddable.clearSelections();

View file

@ -1,42 +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", 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 { PresentationContainer, apiIsPresentationContainer } from '@kbn/presentation-containers';
import {
HasParentApi,
HasType,
HasUniqueId,
apiCanAccessViewMode,
apiHasParentApi,
apiHasType,
apiHasUniqueId,
apiIsOfType,
} from '@kbn/presentation-publishing';
import { CONTROL_GROUP_TYPE } from '../../common';
import { isClearableControl, type CanClearSelections } from '../types';
type ClearControlActionApi = HasType &
HasUniqueId &
CanClearSelections &
HasParentApi<PresentationContainer & HasType>;
export const compatibilityCheck = (api: unknown | null): api is ClearControlActionApi =>
Boolean(
apiHasType(api) &&
apiHasUniqueId(api) &&
isClearableControl(api) &&
apiHasParentApi(api) &&
apiCanAccessViewMode(api.parentApi) &&
apiIsOfType(api.parentApi, CONTROL_GROUP_TYPE) &&
apiIsPresentationContainer(api.parentApi)
);
export function isCompatible(api: unknown) {
return compatibilityCheck(api);
}

View file

@ -0,0 +1,22 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { Trigger } from '@kbn/ui-actions-plugin/public';
export const CONTROL_HOVER_TRIGGER = 'CONTROL_HOVER_TRIGGER';
export const controlHoverTrigger: Trigger = {
id: CONTROL_HOVER_TRIGGER,
title: i18n.translate('controls.hoverTrigger.title', {
defaultMessage: 'Control hover',
}),
description: i18n.translate('controls.hoverTrigger.description', {
defaultMessage: "Add action to controls's hover menu",
}),
};

View file

@ -11,12 +11,40 @@ import React from 'react';
import { EuiButtonIcon, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import type { HasUniqueId, EmbeddableApiContext } from '@kbn/presentation-publishing';
import {
type HasUniqueId,
type EmbeddableApiContext,
type HasType,
type HasParentApi,
type PublishesViewMode,
apiHasType,
apiHasUniqueId,
apiHasParentApi,
apiCanAccessViewMode,
apiIsOfType,
getInheritedViewMode,
} from '@kbn/presentation-publishing';
import { IncompatibleActionError, type Action } from '@kbn/ui-actions-plugin/public';
import { ACTION_DELETE_CONTROL } from '.';
import { PresentationContainer, apiIsPresentationContainer } from '@kbn/presentation-containers';
import { CONTROL_GROUP_TYPE } from '../../common';
import { ACTION_DELETE_CONTROL } from './constants';
import { coreServices } from '../services/kibana_services';
type DeleteControlActionApi = HasType &
HasUniqueId &
HasParentApi<PresentationContainer & PublishesViewMode & HasType>;
export const compatibilityCheck = (api: unknown | null): api is DeleteControlActionApi =>
Boolean(
apiHasType(api) &&
apiHasUniqueId(api) &&
apiHasParentApi(api) &&
apiCanAccessViewMode(api.parentApi) &&
apiIsOfType(api.parentApi, CONTROL_GROUP_TYPE) &&
apiIsPresentationContainer(api.parentApi)
);
export class DeleteControlAction implements Action<EmbeddableApiContext> {
public readonly type = ACTION_DELETE_CONTROL;
public readonly id = ACTION_DELETE_CONTROL;
@ -49,12 +77,10 @@ export class DeleteControlAction implements Action<EmbeddableApiContext> {
}
public async isCompatible({ embeddable }: EmbeddableApiContext) {
const { isCompatible } = await import('./delete_control_action_compatibility_check');
return isCompatible(embeddable);
return compatibilityCheck(embeddable) && getInheritedViewMode(embeddable.parentApi) === 'edit';
}
public async execute({ embeddable }: EmbeddableApiContext) {
const { compatibilityCheck } = await import('./delete_control_action_compatibility_check');
if (!compatibilityCheck(embeddable)) throw new IncompatibleActionError();
coreServices.overlays

View file

@ -1,42 +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", 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 { ViewMode } from '@kbn/embeddable-plugin/public';
import { PresentationContainer, apiIsPresentationContainer } from '@kbn/presentation-containers';
import {
HasParentApi,
HasType,
HasUniqueId,
PublishesViewMode,
apiCanAccessViewMode,
apiHasParentApi,
apiHasType,
apiHasUniqueId,
apiIsOfType,
getInheritedViewMode,
} from '@kbn/presentation-publishing';
import { CONTROL_GROUP_TYPE } from '../../common';
type DeleteControlActionApi = HasType &
HasUniqueId &
HasParentApi<PresentationContainer & PublishesViewMode & HasType>;
export const compatibilityCheck = (api: unknown | null): api is DeleteControlActionApi =>
Boolean(
apiHasType(api) &&
apiHasUniqueId(api) &&
apiHasParentApi(api) &&
apiCanAccessViewMode(api.parentApi) &&
apiIsOfType(api.parentApi, CONTROL_GROUP_TYPE) &&
apiIsPresentationContainer(api.parentApi)
);
export function isCompatible(api: unknown) {
return compatibilityCheck(api) && getInheritedViewMode(api.parentApi) === ViewMode.EDIT;
}

View file

@ -11,10 +11,35 @@ import React from 'react';
import { EuiButtonIcon, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import type { EmbeddableApiContext, HasUniqueId } from '@kbn/presentation-publishing';
import {
apiHasType,
apiHasUniqueId,
hasEditCapabilities,
type EmbeddableApiContext,
type HasUniqueId,
apiHasParentApi,
apiCanAccessViewMode,
apiIsOfType,
getInheritedViewMode,
} from '@kbn/presentation-publishing';
import { IncompatibleActionError, type Action } from '@kbn/ui-actions-plugin/public';
import { ACTION_EDIT_CONTROL } from '.';
import { apiIsPresentationContainer } from '@kbn/presentation-containers';
import { CONTROL_GROUP_TYPE } from '../../common';
import { ACTION_EDIT_CONTROL } from './constants';
import { DataControlApi } from '../controls/data_controls/types';
const compatibilityCheck = (api: unknown): api is DataControlApi => {
return Boolean(
apiHasType(api) &&
apiHasUniqueId(api) &&
hasEditCapabilities(api) &&
apiHasParentApi(api) &&
apiCanAccessViewMode(api.parentApi) &&
apiIsOfType(api.parentApi, CONTROL_GROUP_TYPE) &&
apiIsPresentationContainer(api.parentApi)
);
};
export class EditControlAction implements Action<EmbeddableApiContext> {
public readonly type = ACTION_EDIT_CONTROL;
@ -48,12 +73,14 @@ export class EditControlAction implements Action<EmbeddableApiContext> {
}
public async isCompatible({ embeddable }: EmbeddableApiContext) {
const { isCompatible } = await import('./edit_control_action_compatibility_check');
return isCompatible(embeddable);
return (
compatibilityCheck(embeddable) &&
getInheritedViewMode(embeddable.parentApi) === 'edit' &&
embeddable.isEditingEnabled()
);
}
public async execute({ embeddable }: EmbeddableApiContext) {
const { compatibilityCheck } = await import('./edit_control_action_compatibility_check');
if (!compatibilityCheck(embeddable)) throw new IncompatibleActionError();
await embeddable.onEdit();
}

View file

@ -1,43 +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", 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 { ViewMode } from '@kbn/embeddable-plugin/public';
import { apiIsPresentationContainer } from '@kbn/presentation-containers';
import {
apiCanAccessViewMode,
apiHasParentApi,
apiHasType,
apiHasUniqueId,
apiIsOfType,
getInheritedViewMode,
hasEditCapabilities,
} from '@kbn/presentation-publishing';
import { CONTROL_GROUP_TYPE } from '../../common';
import { DataControlApi } from '../controls/data_controls/types';
export const compatibilityCheck = (api: unknown): api is DataControlApi => {
return Boolean(
apiHasType(api) &&
apiHasUniqueId(api) &&
hasEditCapabilities(api) &&
apiHasParentApi(api) &&
apiCanAccessViewMode(api.parentApi) &&
apiIsOfType(api.parentApi, CONTROL_GROUP_TYPE) &&
apiIsPresentationContainer(api.parentApi)
);
};
export function isCompatible(api: unknown) {
return (
compatibilityCheck(api) &&
getInheritedViewMode(api.parentApi) === ViewMode.EDIT &&
api.isEditingEnabled()
);
}

View file

@ -0,0 +1,34 @@
/*
* 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 { UiActionsStart } from '@kbn/ui-actions-plugin/public';
import { ACTION_CLEAR_CONTROL, ACTION_DELETE_CONTROL, ACTION_EDIT_CONTROL } from './constants';
import { CONTROL_HOVER_TRIGGER, controlHoverTrigger } from './controls_hover_trigger';
export function registerActions(uiActions: UiActionsStart) {
uiActions.registerTrigger(controlHoverTrigger);
uiActions.registerActionAsync(ACTION_DELETE_CONTROL, async () => {
const { DeleteControlAction } = await import('../controls_module');
return new DeleteControlAction();
});
uiActions.attachAction(CONTROL_HOVER_TRIGGER, ACTION_DELETE_CONTROL);
uiActions.registerActionAsync(ACTION_EDIT_CONTROL, async () => {
const { EditControlAction } = await import('../controls_module');
return new EditControlAction();
});
uiActions.attachAction(CONTROL_HOVER_TRIGGER, ACTION_EDIT_CONTROL);
uiActions.registerActionAsync(ACTION_CLEAR_CONTROL, async () => {
const { ClearControlAction } = await import('../controls_module');
return new ClearControlAction();
});
uiActions.attachAction(CONTROL_HOVER_TRIGGER, ACTION_CLEAR_CONTROL);
}

View file

@ -11,12 +11,12 @@ import React, { useImperativeHandle } from 'react';
import { BehaviorSubject } from 'rxjs';
import { setMockedPresentationUtilServices } from '@kbn/presentation-util-plugin/public/mocks';
import { uiActionsService } from '@kbn/presentation-util-plugin/public/services/kibana_services';
import { render, waitFor } from '@testing-library/react';
import { Action } from '@kbn/ui-actions-plugin/public';
import type { ControlLabelPosition, ControlWidth } from '../../../common';
import { uiActionsService } from '../../services/kibana_services';
import { ControlPanel } from './control_panel';
import { Action } from '@kbn/ui-actions-plugin/public';
describe('render', () => {
let mockApi = {};

View file

@ -27,7 +27,7 @@ import {
apiPublishesViewMode,
useBatchedOptionalPublishingSubjects,
} from '@kbn/presentation-publishing';
import { FloatingActions } from '@kbn/presentation-util-plugin/public';
import { FloatingActions } from './floating_actions';
import { DEFAULT_CONTROL_GROW, DEFAULT_CONTROL_WIDTH } from '../../../common';
import { ControlPanelProps, DefaultControlApi } from '../../controls/types';

View file

@ -12,16 +12,13 @@ import React, { FC, ReactElement, useEffect, useState } from 'react';
import { v4 } from 'uuid';
import { Subscription } from 'rxjs';
import {
PANEL_HOVER_TRIGGER,
panelHoverTrigger,
type ViewMode,
} from '@kbn/embeddable-plugin/public';
import { type ViewMode } from '@kbn/embeddable-plugin/public';
import { apiHasUniqueId } from '@kbn/presentation-publishing';
import { Action } from '@kbn/ui-actions-plugin/public';
import { AnyApiAction } from '@kbn/presentation-panel-plugin/public/panel_actions/types';
import { uiActionsService } from '../../services/kibana_services';
import './floating_actions.scss';
import { CONTROL_HOVER_TRIGGER, controlHoverTrigger } from '../../actions/controls_hover_trigger';
export interface FloatingActionsProps {
children: ReactElement;
@ -53,7 +50,7 @@ export const FloatingActions: FC<FloatingActionsProps> = ({
let canceled = false;
const context = {
embeddable: api,
trigger: panelHoverTrigger,
trigger: controlHoverTrigger,
};
const sortByOrder = (a: Action | FloatingActionItem, b: Action | FloatingActionItem) => {
@ -62,7 +59,7 @@ export const FloatingActions: FC<FloatingActionsProps> = ({
const getActions: () => Promise<FloatingActionItem[]> = async () => {
const actions = (
await uiActionsService.getTriggerCompatibleActions(PANEL_HOVER_TRIGGER, context)
await uiActionsService.getTriggerCompatibleActions(CONTROL_HOVER_TRIGGER, context)
)
.filter((action) => {
return action.MenuItem !== undefined && (disabledActions ?? []).indexOf(action.id) === -1;
@ -92,7 +89,10 @@ export const FloatingActions: FC<FloatingActionsProps> = ({
setFloatingActions(actions);
const frequentlyChangingActions =
await uiActionsService.getFrequentlyChangingActionsForTrigger(PANEL_HOVER_TRIGGER, context);
await uiActionsService.getFrequentlyChangingActionsForTrigger(
CONTROL_HOVER_TRIGGER,
context
);
if (canceled) return;
for (const action of frequentlyChangingActions) {

View file

@ -12,7 +12,7 @@ import { dynamic } from '@kbn/shared-ux-utility';
import type { ControlGroupRendererProps } from './control_group_renderer';
const Component = dynamic(async () => {
const { ControlGroupRenderer } = await import('./control_group_renderer');
const { ControlGroupRenderer } = await import('../../controls_module');
return {
default: ControlGroupRenderer,
};

View file

@ -14,7 +14,7 @@ import { untilPluginStartServicesReady } from '../services/kibana_services';
export function registerControlGroupEmbeddable(embeddableSetup: EmbeddableSetup) {
embeddableSetup.registerReactEmbeddableFactory(CONTROL_GROUP_TYPE, async () => {
const [{ getControlGroupEmbeddableFactory }] = await Promise.all([
import('./get_control_group_factory'),
import('../controls_module'),
untilPluginStartServicesReady(),
]);
return getControlGroupEmbeddableFactory();

View file

@ -14,7 +14,7 @@ import { registerControlFactory } from '../../../control_factory_registry';
export function registerOptionsListControl() {
registerControlFactory(OPTIONS_LIST_CONTROL, async () => {
const [{ getOptionsListControlFactory }] = await Promise.all([
import('./get_options_list_control_factory'),
import('../../../controls_module'),
untilPluginStartServicesReady(),
]);
return getOptionsListControlFactory();

View file

@ -14,7 +14,7 @@ import { registerControlFactory } from '../../../control_factory_registry';
export function registerRangeSliderControl() {
registerControlFactory(RANGE_SLIDER_CONTROL, async () => {
const [{ getRangesliderControlFactory }] = await Promise.all([
import('./get_range_slider_control_factory'),
import('../../../controls_module'),
untilPluginStartServicesReady(),
]);

View file

@ -14,7 +14,7 @@ import { registerControlFactory } from '../../control_factory_registry';
export function registerTimeSliderControl() {
registerControlFactory(TIME_SLIDER_CONTROL, async () => {
const [{ getTimesliderControlFactory }] = await Promise.all([
import('./get_timeslider_control_factory'),
import('../../controls_module'),
untilPluginStartServicesReady(),
]);
return getTimesliderControlFactory();

View file

@ -0,0 +1,20 @@
/*
* 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 { ClearControlAction } from './actions/clear_control_action';
export { DeleteControlAction } from './actions/delete_control_action';
export { EditControlAction } from './actions/edit_control_action';
export { getControlGroupEmbeddableFactory } from './control_group/get_control_group_factory';
export { getOptionsListControlFactory } from './controls/data_controls/options_list_control/get_options_list_control_factory';
export { getRangesliderControlFactory } from './controls/data_controls/range_slider/get_range_slider_control_factory';
export { getTimesliderControlFactory } from './controls/timeslider_control/get_timeslider_control_factory';
export { ControlGroupRenderer } from './control_group/control_group_renderer/control_group_renderer';

View file

@ -14,9 +14,13 @@ export {
type ControlGroupStateBuilder,
} from './control_group/utils/control_group_state_builder';
export type { ControlGroupApi, ControlStateTransform } from './control_group/types';
export {
ACTION_CLEAR_CONTROL,
ACTION_DELETE_CONTROL,
ACTION_EDIT_CONTROL,
} from './actions/constants';
export { ACTION_CLEAR_CONTROL, ACTION_DELETE_CONTROL, ACTION_EDIT_CONTROL } from './actions';
export type { ControlGroupApi, ControlStateTransform } from './control_group/types';
export type { DataControlApi, DataControlFactory } from './controls/data_controls/types';

View file

@ -8,17 +8,13 @@
*/
import type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public';
import { PANEL_HOVER_TRIGGER } from '@kbn/embeddable-plugin/public';
import { ClearControlAction } from './actions/clear_control_action';
import { DeleteControlAction } from './actions/delete_control_action';
import { EditControlAction } from './actions/edit_control_action';
import { registerControlGroupEmbeddable } from './control_group/register_control_group_embeddable';
import { registerOptionsListControl } from './controls/data_controls/options_list_control/register_options_list_control';
import { registerRangeSliderControl } from './controls/data_controls/range_slider/register_range_slider_control';
import { registerTimeSliderControl } from './controls/timeslider_control/register_timeslider_control';
import { setKibanaServices, untilPluginStartServicesReady } from './services/kibana_services';
import { setKibanaServices } from './services/kibana_services';
import type { ControlsPluginSetupDeps, ControlsPluginStartDeps } from './types';
import { registerActions } from './actions/register_actions';
export class ControlsPlugin
implements Plugin<void, void, ControlsPluginSetupDeps, ControlsPluginStartDeps>
@ -36,22 +32,9 @@ export class ControlsPlugin
}
public start(coreStart: CoreStart, startPlugins: ControlsPluginStartDeps) {
const { uiActions } = startPlugins;
setKibanaServices(coreStart, startPlugins);
untilPluginStartServicesReady().then(() => {
const deleteControlAction = new DeleteControlAction();
uiActions.registerAction(deleteControlAction);
uiActions.attachAction(PANEL_HOVER_TRIGGER, deleteControlAction.id);
const editControlAction = new EditControlAction();
uiActions.registerAction(editControlAction);
uiActions.attachAction(PANEL_HOVER_TRIGGER, editControlAction.id);
const clearControlAction = new ClearControlAction();
uiActions.registerAction(clearControlAction);
uiActions.attachAction(PANEL_HOVER_TRIGGER, clearControlAction.id);
});
registerActions(startPlugins.uiActions);
}
public stop() {}

View file

@ -12,12 +12,14 @@ import { BehaviorSubject } from 'rxjs';
import { CoreStart } from '@kbn/core/public';
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
import { UiActionsStart } from '@kbn/ui-actions-plugin/public';
import { ControlsPluginStartDeps } from '../types';
export let coreServices: CoreStart;
export let dataService: DataPublicPluginStart;
export let dataViewsService: DataViewsPublicPluginStart;
export let uiActionsService: UiActionsStart;
const servicesReady$ = new BehaviorSubject(false);
@ -25,6 +27,7 @@ export const setKibanaServices = (kibanaCore: CoreStart, deps: ControlsPluginSta
coreServices = kibanaCore;
dataService = deps.data;
dataViewsService = deps.dataViews;
uiActionsService = deps.uiActions;
servicesReady$.next(true);
};

View file

@ -25,10 +25,8 @@ export {
isValueClickTriggerContext,
MULTI_VALUE_CLICK_TRIGGER,
panelBadgeTrigger,
panelHoverTrigger,
panelNotificationTrigger,
PANEL_BADGE_TRIGGER,
PANEL_HOVER_TRIGGER,
PANEL_NOTIFICATION_TRIGGER,
SELECT_RANGE_TRIGGER,
VALUE_CLICK_TRIGGER,

View file

@ -16,12 +16,10 @@ import {
selectRangeTrigger,
valueClickTrigger,
cellValueTrigger,
panelHoverTrigger,
} from './triggers';
export const registerTriggers = (uiActions: UiActionsSetup) => {
uiActions.registerTrigger(contextMenuTrigger);
uiActions.registerTrigger(panelHoverTrigger);
uiActions.registerTrigger(panelBadgeTrigger);
uiActions.registerTrigger(panelNotificationTrigger);
uiActions.registerTrigger(selectRangeTrigger);

View file

@ -75,17 +75,6 @@ export const contextMenuTrigger: Trigger = {
}),
};
export const PANEL_HOVER_TRIGGER = 'PANEL_HOVER_TRIGGER';
export const panelHoverTrigger: Trigger = {
id: PANEL_HOVER_TRIGGER,
title: i18n.translate('embeddableApi.panelHoverTrigger.title', {
defaultMessage: 'Panel hover',
}),
description: i18n.translate('embeddableApi.panelHoverTrigger.description', {
defaultMessage: "A new action will be added to the panel's hover menu",
}),
};
export const PANEL_BADGE_TRIGGER = 'PANEL_BADGE_TRIGGER';
export const panelBadgeTrigger: Trigger = {
id: PANEL_BADGE_TRIGGER,

View file

@ -61,8 +61,6 @@ export {
DEFAULT_DASHBOARD_DRILLDOWN_OPTIONS,
} from './dashboard_drilldown_options/types';
export { FloatingActions } from './floating_actions/floating_actions';
/**
* A lazily-loaded ExpressionInput component.
*/

View file

@ -13,7 +13,7 @@ import type { CSSProperties, HTMLAttributes } from 'react';
import type { ExpressionFunction } from '@kbn/expressions-plugin/common';
import { OnSaveProps, SaveModalState } from '@kbn/saved-objects-plugin/public';
import type { OnSaveProps, SaveModalState } from '@kbn/saved-objects-plugin/public';
interface SaveModalDocumentInfo {
id?: string;

View file

@ -24,7 +24,6 @@ export {
withSuspense,
LazyDataViewPicker,
LazyFieldPicker,
FloatingActions,
type DashboardDrilldownOptions,
DashboardDrilldownOptionsComponent,
DEFAULT_DASHBOARD_DRILLDOWN_OPTIONS,

View file

@ -15,7 +15,6 @@
"kbn_references": [
"@kbn/core",
"@kbn/saved-objects-plugin",
"@kbn/embeddable-plugin",
"@kbn/kibana-react-plugin",
"@kbn/i18n",
"@kbn/expressions-plugin",
@ -34,9 +33,7 @@
"@kbn/code-editor",
"@kbn/calculate-width-from-char-count",
"@kbn/field-utils",
"@kbn/presentation-publishing",
"@kbn/core-ui-settings-browser",
"@kbn/presentation-panel-plugin",
],
"exclude": ["target/**/*"]
}

View file

@ -2826,8 +2826,6 @@
"embeddableApi.multiValueClickTrigger.title": "Clics multiples",
"embeddableApi.panelBadgeTrigger.description": "Des actions apparaissent dans la barre de titre lorsqu'un élément pouvant être intégré est chargé dans un panneau.",
"embeddableApi.panelBadgeTrigger.title": "Badges du panneau",
"embeddableApi.panelHoverTrigger.description": "Une nouvelle action sera ajoutée au menu flottant du panneau",
"embeddableApi.panelHoverTrigger.title": "Menu contextuel du panneau",
"embeddableApi.panelNotificationTrigger.description": "Les actions apparaissent dans langle supérieur droit des panneaux.",
"embeddableApi.panelNotificationTrigger.title": "Notifications du panneau",
"embeddableApi.reactEmbeddable.factoryAlreadyExistsError": "Une usine incorporable pour le type : {key} est déjà enregistrée.",
@ -6287,8 +6285,6 @@
"presentationPanel.filters.filtersTitle": "Filtres",
"presentationPanel.filters.queryTitle": "Recherche",
"presentationPanel.header.titleAriaLabel": "Cliquez pour modifier le titre : {title}",
"presentationPanel.hoverTrigger.description": "Une nouvelle action sera ajoutée au menu flottant du panneau",
"presentationPanel.hoverTrigger.title": "Menu contextuel du panneau",
"presentationPanel.notificationTrigger.description": "Les actions de notification apparaissent dans l'angle supérieur droit des panneaux.",
"presentationPanel.notificationTrigger.title": "Notifications du panneau",
"presentationPanel.placeholderTitle": "[Aucun titre]",

View file

@ -2820,8 +2820,6 @@
"embeddableApi.multiValueClickTrigger.title": "マルチクリック",
"embeddableApi.panelBadgeTrigger.description": "パネルに埋め込み可能なファイルが読み込まれるときに、アクションがタイトルバーに表示されます。",
"embeddableApi.panelBadgeTrigger.title": "パネルバッジ",
"embeddableApi.panelHoverTrigger.description": "新しいアクションがパネルのマウスオーバーメニューに追加されます",
"embeddableApi.panelHoverTrigger.title": "パネルマウスオーバー",
"embeddableApi.panelNotificationTrigger.description": "パネルの右上にアクションが表示されます。",
"embeddableApi.panelNotificationTrigger.title": "パネル通知",
"embeddableApi.reactEmbeddable.factoryAlreadyExistsError": "タイプ\"{key}\"の埋め込み可能ファクトリはすでに登録されています。",
@ -6280,8 +6278,6 @@
"presentationPanel.filters.filtersTitle": "フィルター",
"presentationPanel.filters.queryTitle": "クエリー",
"presentationPanel.header.titleAriaLabel": "クリックしてタイトルを編集:{title}",
"presentationPanel.hoverTrigger.description": "新しいアクションがパネルのマウスオーバーメニューに追加されます",
"presentationPanel.hoverTrigger.title": "パネルマウスオーバー",
"presentationPanel.notificationTrigger.description": "パネルの右上に通知アクションが表示されます。",
"presentationPanel.notificationTrigger.title": "パネル通知",
"presentationPanel.placeholderTitle": "[タイトルなし]",

View file

@ -2857,8 +2857,6 @@
"embeddableApi.multiValueClickTrigger.title": "多次单击",
"embeddableApi.panelBadgeTrigger.description": "可嵌入对象在面板加载后,操作便显示在标题栏中。",
"embeddableApi.panelBadgeTrigger.title": "面板徽章",
"embeddableApi.panelHoverTrigger.description": "会将一个新操作添加到该面板的悬停菜单",
"embeddableApi.panelHoverTrigger.title": "面板悬停",
"embeddableApi.panelNotificationTrigger.description": "操作显示在面板右上角。",
"embeddableApi.panelNotificationTrigger.title": "面板通知",
"embeddableApi.reactEmbeddable.factoryAlreadyExistsError": "已注册类型为 {key} 的可嵌入工厂。",
@ -6323,8 +6321,6 @@
"presentationPanel.filters.filtersTitle": "筛选",
"presentationPanel.filters.queryTitle": "查询",
"presentationPanel.header.titleAriaLabel": "单击可编辑标题:{title}",
"presentationPanel.hoverTrigger.description": "会将一个新操作添加到该面板的悬停菜单",
"presentationPanel.hoverTrigger.title": "面板悬停",
"presentationPanel.notificationTrigger.description": "通知操作显示在面板右上角。",
"presentationPanel.notificationTrigger.title": "面板通知",
"presentationPanel.placeholderTitle": "[无标题]",