[observability] avoid loading slo.chunk and synthetics.chunk on every page load (#209582)

Part of https://github.com/elastic/kibana/issues/194171 and
https://github.com/elastic/kibana/issues/191642

* [avoid async chunk loading during plugin setup and start
phase](https://github.com/elastic/kibana/issues/194171)
* Replace `addTriggerAction` with `addTriggerActionAsync` to [avoid
including action contents in page load
bundle](https://github.com/elastic/kibana/issues/191642)
* Immediately open flyout on action execution with loading state to
avoid UI lag when awaiting async chunks and then opening flyout.

### Test instructions
* Start kibana locally and start 30 day trial license.
* Open network tab in browser
* Open home page. Verify `slo.chunk` and `synthetics.chunk` are not
loaded. The screen shots show the behavior in main where `slo.chunk` and
`synthetics.chunk` are loaded on home page
<img width="600" alt="Screenshot 2025-02-03 at 1 02 13 PM"
src="https://github.com/user-attachments/assets/6dea7d62-0e8b-4c1f-a87c-f8e9d4b85c87"
/>
<img width="600" alt="Screenshot 2025-02-03 at 1 02 02 PM"
src="https://github.com/user-attachments/assets/0deb3c2a-d832-4d21-974d-0803b0984006"
/>

---------

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:
Nathan Reese 2025-02-05 11:24:59 -07:00 committed by GitHub
parent 37736a335b
commit 896ba294cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 235 additions and 200 deletions

View file

@ -19,9 +19,11 @@ export type Start = jest.Mocked<UiActionsPublicStart>;
const createSetupContract = (): Setup => {
const setupContract: Setup = {
addTriggerAction: jest.fn(),
addTriggerActionAsync: jest.fn(),
attachAction: jest.fn(),
detachAction: jest.fn(),
registerAction: jest.fn(),
registerActionAsync: jest.fn(),
registerTrigger: jest.fn(),
unregisterAction: jest.fn(),
};

View file

@ -21,9 +21,11 @@ import { setAnalytics, setI18n, setNotifications, setTheme, setUserProfile } fro
export type UiActionsPublicSetup = Pick<
UiActionsService,
| 'addTriggerAction'
| 'addTriggerActionAsync'
| 'attachAction'
| 'detachAction'
| 'registerAction'
| 'registerActionAsync'
| 'registerTrigger'
| 'unregisterAction'
>;

View file

@ -27,6 +27,7 @@ import { SLOPublicPluginsStart, SLORepositoryClient } from '../../../types';
import { SLO_ALERTS_EMBEDDABLE_ID } from './constants';
import { SloAlertsWrapper } from './slo_alerts_wrapper';
import { SloAlertsApi, SloAlertsEmbeddableState } from './types';
import { openSloConfiguration } from './slo_alerts_open_configuration';
const history = createBrowserHistory();
const queryClient = new QueryClient();
@ -59,8 +60,6 @@ export function getAlertsEmbeddableFactory({
const deps = { ...coreStart, ...pluginsStart };
async function onEdit() {
try {
const { openSloConfiguration } = await import('./slo_alerts_open_configuration');
const result = await openSloConfiguration(
coreStart,
pluginsStart,

View file

@ -8,11 +8,11 @@ import type { CoreStart } from '@kbn/core/public';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import React from 'react';
import React, { Suspense, lazy } from 'react';
import { EuiSkeletonText } from '@elastic/eui';
import { SLOPublicPluginsStart } from '../../..';
import { PluginContext } from '../../../context/plugin_context';
import { SLORepositoryClient } from '../../../types';
import { SloConfiguration } from './slo_configuration';
import type { EmbeddableSloProps } from './types';
export async function openSloConfiguration(
@ -25,6 +25,12 @@ export async function openSloConfiguration(
const queryClient = new QueryClient();
return new Promise(async (resolve, reject) => {
try {
const LazySloConfiguration = lazy(async () => {
const { SloConfiguration } = await import('./slo_configuration');
return {
default: SloConfiguration,
};
});
const flyoutSession = overlays.openFlyout(
toMountPoint(
<KibanaContextProvider
@ -42,17 +48,19 @@ export async function openSloConfiguration(
}}
>
<QueryClientProvider client={queryClient}>
<SloConfiguration
initialInput={initialState}
onCreate={(update: EmbeddableSloProps) => {
flyoutSession.close();
resolve(update);
}}
onCancel={() => {
flyoutSession.close();
reject();
}}
/>
<Suspense fallback={<EuiSkeletonText />}>
<LazySloConfiguration
initialInput={initialState}
onCreate={(update: EmbeddableSloProps) => {
flyoutSession.close();
resolve(update);
}}
onCancel={() => {
flyoutSession.close();
reject();
}}
/>
</Suspense>
</QueryClientProvider>
</PluginContext.Provider>
</KibanaContextProvider>,

View file

@ -8,23 +8,28 @@ import type { CoreStart } from '@kbn/core/public';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import React from 'react';
import React, { Suspense, lazy } from 'react';
import { EuiSkeletonText } from '@elastic/eui';
import { SLOPublicPluginsStart } from '../../..';
import { PluginContext } from '../../../context/plugin_context';
import { SloConfiguration } from './slo_configuration';
import type { EmbeddableSloProps, SloErrorBudgetEmbeddableState } from './types';
import type { EmbeddableSloProps } from './types';
import { SLORepositoryClient } from '../../../types';
export async function openSloConfiguration(
coreStart: CoreStart,
pluginsStart: SLOPublicPluginsStart,
sloClient: SLORepositoryClient,
initialState?: SloErrorBudgetEmbeddableState
sloClient: SLORepositoryClient
): Promise<EmbeddableSloProps> {
const { overlays } = coreStart;
const queryClient = new QueryClient();
return new Promise(async (resolve, reject) => {
try {
const LazySloConfiguration = lazy(async () => {
const { SloConfiguration } = await import('./slo_configuration');
return {
default: SloConfiguration,
};
});
const flyoutSession = overlays.openFlyout(
toMountPoint(
<KibanaContextProvider
@ -42,16 +47,18 @@ export async function openSloConfiguration(
}}
>
<QueryClientProvider client={queryClient}>
<SloConfiguration
onCreate={(update: EmbeddableSloProps) => {
flyoutSession.close();
resolve(update);
}}
onCancel={() => {
flyoutSession.close();
reject();
}}
/>
<Suspense fallback={<EuiSkeletonText />}>
<LazySloConfiguration
onCreate={(update: EmbeddableSloProps) => {
flyoutSession.close();
resolve(update);
}}
onCancel={() => {
flyoutSession.close();
reject();
}}
/>
</Suspense>
</QueryClientProvider>
</PluginContext.Provider>
</KibanaContextProvider>,

View file

@ -30,6 +30,7 @@ import { GroupSloView } from './group_view/group_view';
import { SloOverview } from './slo_overview';
import { SloCardChartList } from './slo_overview_grid';
import { GroupSloCustomInput, SloOverviewApi, SloOverviewEmbeddableState } from './types';
import { openSloConfiguration } from './slo_overview_open_configuration';
const getOverviewPanelTitle = () =>
i18n.translate('xpack.slo.sloEmbeddable.displayName', {
@ -87,8 +88,6 @@ export const getOverviewEmbeddableFactory = ({
isEditingEnabled: () => api.getSloGroupOverviewConfig().overviewMode === 'groups',
onEdit: async function onEdit() {
try {
const { openSloConfiguration } = await import('./slo_overview_open_configuration');
const result = await openSloConfiguration(
coreStart,
pluginsStart,

View file

@ -5,14 +5,14 @@
* 2.0.
*/
import React from 'react';
import React, { Suspense, lazy } from 'react';
import type { CoreStart } from '@kbn/core/public';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { EuiSkeletonText } from '@elastic/eui';
import type { GroupSloCustomInput, SingleSloCustomInput } from './types';
import { SLOPublicPluginsStart } from '../../..';
import { SloConfiguration } from './slo_configuration';
import { SLORepositoryClient } from '../../../types';
import { PluginContext } from '../../../context/plugin_context';
@ -28,6 +28,12 @@ export async function openSloConfiguration(
return new Promise(async (resolve, reject) => {
try {
const LazySloConfiguration = lazy(async () => {
const { SloConfiguration } = await import('./slo_configuration');
return {
default: SloConfiguration,
};
});
const flyoutSession = overlays.openFlyout(
toMountPoint(
<KibanaContextProvider
@ -45,17 +51,19 @@ export async function openSloConfiguration(
}}
>
<QueryClientProvider client={queryClient}>
<SloConfiguration
initialInput={initialState}
onCreate={(update: GroupSloCustomInput | SingleSloCustomInput) => {
flyoutSession.close();
resolve(update);
}}
onCancel={() => {
flyoutSession.close();
reject();
}}
/>
<Suspense fallback={<EuiSkeletonText />}>
<LazySloConfiguration
initialInput={initialState}
onCreate={(update: GroupSloCustomInput | SingleSloCustomInput) => {
flyoutSession.close();
resolve(update);
}}
onCancel={() => {
flyoutSession.close();
reject();
}}
/>
</Suspense>
</QueryClientProvider>
</PluginContext.Provider>
</KibanaContextProvider>,

View file

@ -37,6 +37,7 @@ import type {
SLOPublicStart,
} from './types';
import { getLazyWithContextProviders } from './utils/get_lazy_with_context_providers';
import { registerSloUiActions } from './ui_actions/register_ui_actions';
export class SLOPlugin
implements Plugin<SLOPublicSetup, SLOPublicStart, SLOPublicPluginsSetup, SLOPublicPluginsStart>
@ -177,14 +178,7 @@ export class SLOPlugin
});
});
const registerAsyncSloUiActions = async () => {
if (plugins.uiActions) {
const { registerSloUiActions } = await import('./ui_actions');
registerSloUiActions(plugins.uiActions, coreStart, pluginsStart, sloClient);
}
};
registerAsyncSloUiActions();
registerSloUiActions(plugins.uiActions, coreStart, pluginsStart, sloClient);
}
};
registerEmbeddables();

View file

@ -0,0 +1,11 @@
/*
* 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 { createAddAlertsPanelAction } from './create_alerts_panel_action';
export { createBurnRatePanelAction } from './create_burn_rate_panel_action';
export { createAddErrorBudgetPanelAction } from './create_error_budget_action';
export { createOverviewPanelAction } from './create_overview_panel_action';

View file

@ -19,6 +19,7 @@ import {
SLO_ALERTS_EMBEDDABLE_ID,
} from '../embeddable/slo/alerts/constants';
import { SLORepositoryClient } from '../types';
import { openSloConfiguration } from '../embeddable/slo/alerts/slo_alerts_open_configuration';
export function createAddAlertsPanelAction(
coreStart: CoreStart,
@ -37,9 +38,6 @@ export function createAddAlertsPanelAction(
if (!apiIsPresentationContainer(embeddable)) throw new IncompatibleActionError();
try {
const { openSloConfiguration } = await import(
'../embeddable/slo/alerts/slo_alerts_open_configuration'
);
const initialState = await openSloConfiguration(coreStart, pluginsStart, sloClient);
embeddable.addNewPanel(
{

View file

@ -19,6 +19,7 @@ import {
SLO_ERROR_BUDGET_ID,
} from '../embeddable/slo/error_budget/constants';
import { SLORepositoryClient } from '../types';
import { openSloConfiguration } from '../embeddable/slo/error_budget/error_budget_open_configuration';
export function createAddErrorBudgetPanelAction(
coreStart: CoreStart,
@ -36,9 +37,6 @@ export function createAddErrorBudgetPanelAction(
execute: async ({ embeddable }) => {
if (!apiIsPresentationContainer(embeddable)) throw new IncompatibleActionError();
try {
const { openSloConfiguration } = await import(
'../embeddable/slo/error_budget/error_budget_open_configuration'
);
const initialState = await openSloConfiguration(coreStart, pluginsStart, sloClient);
embeddable.addNewPanel(
{

View file

@ -19,6 +19,7 @@ import {
SLO_OVERVIEW_EMBEDDABLE_ID,
} from '../embeddable/slo/overview/constants';
import { SLORepositoryClient } from '../types';
import { openSloConfiguration } from '../embeddable/slo/overview/slo_overview_open_configuration';
export function createOverviewPanelAction(
coreStart: CoreStart,
@ -37,9 +38,6 @@ export function createOverviewPanelAction(
if (!apiIsPresentationContainer(embeddable)) throw new IncompatibleActionError();
try {
const { openSloConfiguration } = await import(
'../embeddable/slo/overview/slo_overview_open_configuration'
);
const initialState = await openSloConfiguration(coreStart, pluginsStart, sloClient);
embeddable.addNewPanel(
{

View file

@ -1,44 +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 type { CoreStart } from '@kbn/core/public';
import { ADD_PANEL_TRIGGER } from '@kbn/ui-actions-plugin/public';
import { UiActionsPublicSetup } from '@kbn/ui-actions-plugin/public/plugin';
import { SLOPublicPluginsStart } from '..';
import { SLORepositoryClient } from '../types';
import { createAddAlertsPanelAction } from './create_alerts_panel_action';
import { createBurnRatePanelAction } from './create_burn_rate_panel_action';
import { createAddErrorBudgetPanelAction } from './create_error_budget_action';
import { createOverviewPanelAction } from './create_overview_panel_action';
export function registerSloUiActions(
uiActions: UiActionsPublicSetup,
coreStart: CoreStart,
pluginsStart: SLOPublicPluginsStart,
sloClient: SLORepositoryClient
) {
const { serverless, cloud } = pluginsStart;
// Initialize actions
const addOverviewPanelAction = createOverviewPanelAction(coreStart, pluginsStart, sloClient);
const addErrorBudgetPanelAction = createAddErrorBudgetPanelAction(
coreStart,
pluginsStart,
sloClient
);
const addAlertsPanelAction = createAddAlertsPanelAction(coreStart, pluginsStart, sloClient);
const addBurnRatePanelAction = createBurnRatePanelAction(coreStart, pluginsStart, sloClient);
// Assign triggers
// Only register these actions in stateful kibana, and the serverless observability project
if (Boolean((serverless && cloud?.serverless.projectType === 'observability') || !serverless)) {
uiActions.addTriggerAction(ADD_PANEL_TRIGGER, addOverviewPanelAction);
uiActions.addTriggerAction(ADD_PANEL_TRIGGER, addErrorBudgetPanelAction);
uiActions.addTriggerAction(ADD_PANEL_TRIGGER, addAlertsPanelAction);
uiActions.addTriggerAction(ADD_PANEL_TRIGGER, addBurnRatePanelAction);
}
}

View file

@ -0,0 +1,46 @@
/*
* 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 type { CoreStart } from '@kbn/core/public';
import { ADD_PANEL_TRIGGER } from '@kbn/ui-actions-plugin/public';
import { UiActionsPublicSetup } from '@kbn/ui-actions-plugin/public/plugin';
import { ADD_SLO_ALERTS_ACTION_ID } from '../embeddable/slo/alerts/constants';
import { SLOPublicPluginsStart } from '..';
import { SLORepositoryClient } from '../types';
import { ADD_SLO_ERROR_BUDGET_ACTION_ID } from '../embeddable/slo/error_budget/constants';
import { ADD_SLO_OVERVIEW_ACTION_ID } from '../embeddable/slo/overview/constants';
import { ADD_BURN_RATE_ACTION_ID } from '../embeddable/slo/burn_rate/constants';
export function registerSloUiActions(
uiActions: UiActionsPublicSetup,
coreStart: CoreStart,
pluginsStart: SLOPublicPluginsStart,
sloClient: SLORepositoryClient
) {
const { serverless, cloud } = pluginsStart;
// Assign triggers
// Only register these actions in stateful kibana, and the serverless observability project
if (Boolean((serverless && cloud?.serverless.projectType === 'observability') || !serverless)) {
uiActions.addTriggerActionAsync(ADD_PANEL_TRIGGER, ADD_SLO_OVERVIEW_ACTION_ID, async () => {
const { createOverviewPanelAction } = await import('./add_panel_actions_module');
return createOverviewPanelAction(coreStart, pluginsStart, sloClient);
});
uiActions.addTriggerActionAsync(ADD_PANEL_TRIGGER, ADD_SLO_ERROR_BUDGET_ACTION_ID, async () => {
const { createAddErrorBudgetPanelAction } = await import('./add_panel_actions_module');
return createAddErrorBudgetPanelAction(coreStart, pluginsStart, sloClient);
});
uiActions.addTriggerActionAsync(ADD_PANEL_TRIGGER, ADD_SLO_ALERTS_ACTION_ID, async () => {
const { createAddAlertsPanelAction } = await import('./add_panel_actions_module');
return createAddAlertsPanelAction(coreStart, pluginsStart, sloClient);
});
uiActions.addTriggerActionAsync(ADD_PANEL_TRIGGER, ADD_BURN_RATE_ACTION_ID, async () => {
const { createBurnRatePanelAction } = await import('./add_panel_actions_module');
return createBurnRatePanelAction(coreStart, pluginsStart, sloClient);
});
}
}

View file

@ -5,14 +5,14 @@
* 2.0.
*/
import React from 'react';
import React, { Suspense, lazy } from 'react';
import type { CoreStart } from '@kbn/core/public';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { EuiSkeletonText } from '@elastic/eui';
import { MonitorFilters } from '../monitors_overview/types';
import { ClientPluginsStart } from '../../../plugin';
import { MonitorConfiguration } from './monitor_configuration';
export async function openMonitorConfiguration({
coreStart,
@ -29,6 +29,12 @@ export async function openMonitorConfiguration({
const queryClient = new QueryClient();
return new Promise(async (resolve, reject) => {
try {
const LazyMonitorConfiguration = lazy(async () => {
const { MonitorConfiguration } = await import('./monitor_configuration');
return {
default: MonitorConfiguration,
};
});
const flyoutSession = overlays.openFlyout(
toMountPoint(
<KibanaContextProvider
@ -38,18 +44,20 @@ export async function openMonitorConfiguration({
}}
>
<QueryClientProvider client={queryClient}>
<MonitorConfiguration
title={title}
initialInput={initialState}
onCreate={(update: { filters: MonitorFilters }) => {
flyoutSession.close();
resolve(update);
}}
onCancel={() => {
flyoutSession.close();
reject();
}}
/>
<Suspense fallback={<EuiSkeletonText />}>
<LazyMonitorConfiguration
title={title}
initialInput={initialState}
onCreate={(update: { filters: MonitorFilters }) => {
flyoutSession.close();
resolve(update);
}}
onCancel={() => {
flyoutSession.close();
reject();
}}
/>
</Suspense>
</QueryClientProvider>
</KibanaContextProvider>,
coreStart

View file

@ -23,6 +23,7 @@ import { MonitorFilters } from './types';
import { StatusGridComponent } from './monitors_grid_component';
import { SYNTHETICS_MONITORS_EMBEDDABLE } from '../constants';
import { ClientPluginsStart } from '../../../plugin';
import { openMonitorConfiguration } from '../common/monitors_open_configuration';
export const getOverviewPanelTitle = () =>
i18n.translate('xpack.synthetics.monitors.displayName', {
@ -77,10 +78,6 @@ export const getMonitorsEmbeddableFactory = (
},
onEdit: async () => {
try {
const { openMonitorConfiguration } = await import(
'../common/monitors_open_configuration'
);
const result = await openMonitorConfiguration({
coreStart,
pluginStart,

View file

@ -33,28 +33,4 @@ export const registerSyntheticsEmbeddables = (
return getMonitorsEmbeddableFactory(core.getStartServices);
}
);
core.getStartServices().then(([_, pluginsStart]) => {
pluginsStart.dashboard.registerDashboardPanelPlacementSetting(
SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE,
() => {
return { width: 10, height: 8 };
}
);
pluginsStart.dashboard.registerDashboardPanelPlacementSetting(
SYNTHETICS_MONITORS_EMBEDDABLE,
() => {
return { width: 30, height: 12 };
}
);
});
const registerAsyncUiActions = async () => {
if (pluginsSetup.uiActions) {
const { registerSyntheticsUiActions } = await import('./ui_actions/register_ui_actions');
registerSyntheticsUiActions(core, pluginsSetup);
}
};
// can be done async
registerAsyncUiActions();
};

View file

@ -24,6 +24,7 @@ import { MonitorFilters } from '../monitors_overview/types';
import { SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE } from '../constants';
import { ClientPluginsStart } from '../../../plugin';
import { StatsOverviewComponent } from './stats_overview_component';
import { openMonitorConfiguration } from '../common/monitors_open_configuration';
export const getOverviewPanelTitle = () =>
i18n.translate('xpack.synthetics.statusOverview.list.displayName', {
@ -71,10 +72,6 @@ export const getStatsOverviewEmbeddableFactory = (
isEditingEnabled: () => true,
onEdit: async () => {
try {
const { openMonitorConfiguration } = await import(
'../common/monitors_open_configuration'
);
const result = await openMonitorConfiguration({
coreStart,
pluginStart,

View file

@ -0,0 +1,9 @@
/*
* 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 { createStatusOverviewPanelAction } from './create_stats_overview_panel_action';
export { createMonitorsOverviewPanelAction } from './create_monitors_overview_panel_action';

View file

@ -1,15 +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 { apiIsPresentationContainer, PresentationContainer } from '@kbn/presentation-containers';
import { EmbeddableApiContext } from '@kbn/presentation-publishing';
export const compatibilityCheck = (
api: EmbeddableApiContext['embeddable']
): api is PresentationContainer => {
return apiIsPresentationContainer(api);
};

View file

@ -0,0 +1,10 @@
/*
* 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 const ADD_SYNTHETICS_MONITORS_OVERVIEW_ACTION_ID =
'CREATE_SYNTHETICS_MONITORS_OVERVIEW_EMBEDDABLE';
export const ADD_SYNTHETICS_OVERVIEW_ACTION_ID = 'CREATE_SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE';

View file

@ -11,16 +11,16 @@ import {
type UiActionsActionDefinition,
} from '@kbn/ui-actions-plugin/public';
import { EmbeddableApiContext } from '@kbn/presentation-publishing';
import type { StartServicesAccessor } from '@kbn/core-lifecycle-browser';
import { COMMON_OBSERVABILITY_GROUPING } from '@kbn/observability-shared-plugin/common';
import { CoreStart } from '@kbn/core/public';
import { ClientPluginsStart } from '../../../plugin';
import { SYNTHETICS_MONITORS_EMBEDDABLE } from '../constants';
export const ADD_SYNTHETICS_MONITORS_OVERVIEW_ACTION_ID =
'CREATE_SYNTHETICS_MONITORS_OVERVIEW_EMBEDDABLE';
import { ADD_SYNTHETICS_MONITORS_OVERVIEW_ACTION_ID } from './constants';
import { openMonitorConfiguration } from '../common/monitors_open_configuration';
export function createMonitorsOverviewPanelAction(
getStartServices: StartServicesAccessor<ClientPluginsStart>
coreStart: CoreStart,
pluginStart: ClientPluginsStart
): UiActionsActionDefinition<EmbeddableApiContext> {
return {
id: ADD_SYNTHETICS_MONITORS_OVERVIEW_ACTION_ID,
@ -32,9 +32,6 @@ export function createMonitorsOverviewPanelAction(
},
execute: async ({ embeddable }) => {
if (!apiIsPresentationContainer(embeddable)) throw new IncompatibleActionError();
const [coreStart, pluginStart] = await getStartServices();
const { openMonitorConfiguration } = await import('../common/monitors_open_configuration');
const initialState = await openMonitorConfiguration({
coreStart,
pluginStart,

View file

@ -10,15 +10,17 @@ import {
type UiActionsActionDefinition,
} from '@kbn/ui-actions-plugin/public';
import { EmbeddableApiContext } from '@kbn/presentation-publishing';
import type { StartServicesAccessor } from '@kbn/core-lifecycle-browser';
import { COMMON_OBSERVABILITY_GROUPING } from '@kbn/observability-shared-plugin/common';
import { apiIsPresentationContainer } from '@kbn/presentation-containers';
import { CoreStart } from '@kbn/core/public';
import { ClientPluginsStart } from '../../../plugin';
import { SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE } from '../constants';
export const ADD_SYNTHETICS_OVERVIEW_ACTION_ID = 'CREATE_SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE';
import { ADD_SYNTHETICS_OVERVIEW_ACTION_ID } from './constants';
import { openMonitorConfiguration } from '../common/monitors_open_configuration';
export function createStatusOverviewPanelAction(
getStartServices: StartServicesAccessor<ClientPluginsStart>
coreStart: CoreStart,
pluginStart: ClientPluginsStart
): UiActionsActionDefinition<EmbeddableApiContext> {
return {
id: ADD_SYNTHETICS_OVERVIEW_ACTION_ID,
@ -26,16 +28,11 @@ export function createStatusOverviewPanelAction(
order: 5,
getIconType: () => 'online',
isCompatible: async ({ embeddable }) => {
const { compatibilityCheck } = await import('./compatibility_check');
return compatibilityCheck(embeddable);
return apiIsPresentationContainer(embeddable);
},
execute: async ({ embeddable }) => {
const { compatibilityCheck } = await import('./compatibility_check');
if (!compatibilityCheck(embeddable)) throw new IncompatibleActionError();
if (!apiIsPresentationContainer(embeddable)) throw new IncompatibleActionError();
try {
const { openMonitorConfiguration } = await import('../common/monitors_open_configuration');
const [coreStart, pluginStart] = await getStartServices();
const initialState = await openMonitorConfiguration({
coreStart,
pluginStart,

View file

@ -6,25 +6,37 @@
*/
import { ADD_PANEL_TRIGGER } from '@kbn/ui-actions-browser/src';
import { CoreSetup } from '@kbn/core-lifecycle-browser';
import { createStatusOverviewPanelAction } from './create_stats_overview_panel_action';
import { createMonitorsOverviewPanelAction } from './create_monitors_overview_panel_action';
import { ClientPluginsSetup, ClientPluginsStart } from '../../../plugin';
import { CoreStart } from '@kbn/core/public';
import { ClientPluginsStart } from '../../../plugin';
import {
ADD_SYNTHETICS_MONITORS_OVERVIEW_ACTION_ID,
ADD_SYNTHETICS_OVERVIEW_ACTION_ID,
} from './constants';
export const registerSyntheticsUiActions = async (
core: CoreSetup<ClientPluginsStart, unknown>,
pluginsSetup: ClientPluginsSetup
coreStart: CoreStart,
pluginsStart: ClientPluginsStart
) => {
const { uiActions, cloud, serverless } = pluginsSetup;
// Initialize actions
const addStatsOverviewPanelAction = createStatusOverviewPanelAction(core.getStartServices);
const addMonitorsOverviewPanelAction = createMonitorsOverviewPanelAction(core.getStartServices);
const { uiActions, cloud, serverless } = pluginsStart;
// Assign triggers
// Only register these actions in stateful kibana, and the serverless observability project
if (Boolean((serverless && cloud?.serverless.projectType === 'observability') || !serverless)) {
uiActions.addTriggerAction(ADD_PANEL_TRIGGER, addStatsOverviewPanelAction);
uiActions.addTriggerAction(ADD_PANEL_TRIGGER, addMonitorsOverviewPanelAction);
uiActions.addTriggerActionAsync(
ADD_PANEL_TRIGGER,
ADD_SYNTHETICS_OVERVIEW_ACTION_ID,
async () => {
const { createStatusOverviewPanelAction } = await import('./add_panel_actions_module');
return createStatusOverviewPanelAction(coreStart, pluginsStart);
}
);
uiActions.addTriggerActionAsync(
ADD_PANEL_TRIGGER,
ADD_SYNTHETICS_MONITORS_OVERVIEW_ACTION_ID,
async () => {
const { createMonitorsOverviewPanelAction } = await import('./add_panel_actions_module');
return createMonitorsOverviewPanelAction(coreStart, pluginsStart);
}
);
}
};

View file

@ -57,7 +57,7 @@ import {
ObservabilityAIAssistantPublicStart,
} from '@kbn/observability-ai-assistant-plugin/public';
import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public';
import type { UiActionsSetup } from '@kbn/ui-actions-plugin/public';
import type { UiActionsSetup, UiActionsStart } from '@kbn/ui-actions-plugin/public';
import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public';
import { DashboardStart, DashboardSetup } from '@kbn/dashboard-plugin/public';
import { SLOPublicStart } from '@kbn/slo-plugin/public';
@ -68,6 +68,11 @@ import { PLUGIN } from '../common/constants/plugin';
import { OVERVIEW_ROUTE } from '../common/constants/ui';
import { locators } from './apps/locators';
import { syntheticsAlertTypeInitializers } from './apps/synthetics/lib/alert_types';
import {
SYNTHETICS_MONITORS_EMBEDDABLE,
SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE,
} from './apps/embeddables/constants';
import { registerSyntheticsUiActions } from './apps/embeddables/ui_actions/register_ui_actions';
export interface ClientPluginsSetup {
home?: HomePublicPluginSetup;
@ -116,6 +121,7 @@ export interface ClientPluginsStart {
presentationUtil: PresentationUtilPluginStart;
dashboard: DashboardStart;
charts: ChartsPluginStart;
uiActions: UiActionsStart;
}
export interface SyntheticsPluginServices extends Partial<CoreStart> {
@ -218,6 +224,21 @@ export class SyntheticsPlugin
public start(coreStart: CoreStart, pluginsStart: ClientPluginsStart): void {
const { triggersActionsUi } = pluginsStart;
pluginsStart.dashboard.registerDashboardPanelPlacementSetting(
SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE,
() => {
return { width: 10, height: 8 };
}
);
pluginsStart.dashboard.registerDashboardPanelPlacementSetting(
SYNTHETICS_MONITORS_EMBEDDABLE,
() => {
return { width: 30, height: 12 };
}
);
registerSyntheticsUiActions(coreStart, pluginsStart);
syntheticsAlertTypeInitializers.forEach((init) => {
const { observabilityRuleTypeRegistry } = pluginsStart.observability;