From 5da91f91871b69d5d0bdf1c1b49ad6ad957db57b Mon Sep 17 00:00:00 2001 From: mgiota Date: Thu, 26 Oct 2023 09:28:21 +0200 Subject: [PATCH 01/85] Create a dummy SLO alerts embeddable --- .../public/embeddable/slo/alerts/index.ts | 8 ++ .../slo/alerts/slo_alerts_embeddable.tsx | 93 +++++++++++++++++++ .../alerts/slo_alerts_embeddable_factory.ts | 73 +++++++++++++++ x-pack/plugins/observability/public/plugin.ts | 9 ++ 4 files changed, 183 insertions(+) create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/index.ts create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/index.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/index.ts new file mode 100644 index 0000000000000..9c4ec3cc57d71 --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/index.ts @@ -0,0 +1,8 @@ +/* + * 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 { SloAlertsEmbeddableFactoryDefinition } from './slo_alerts_embeddable_factory'; diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx new file mode 100644 index 0000000000000..b492bfbc5422e --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -0,0 +1,93 @@ +/* + * 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 React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import ReactDOM from 'react-dom'; +import { Subscription } from 'rxjs'; +import { i18n } from '@kbn/i18n'; +import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; + +import { + Embeddable as AbstractEmbeddable, + EmbeddableOutput, + IContainer, +} from '@kbn/embeddable-plugin/public'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; + +import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/public'; + +export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; + +interface SloEmbeddableDeps { + uiSettings: IUiSettingsClient; + http: CoreStart['http']; + i18n: CoreStart['i18n']; + application: ApplicationStart; +} + +export class SLOAlertsEmbeddable extends AbstractEmbeddable { + public readonly type = SLO_ALERTS_EMBEDDABLE; + private subscription: Subscription; + private node?: HTMLElement; + + constructor( + private readonly deps: SloEmbeddableDeps, + initialInput: EmbeddableInput, + parent?: IContainer + ) { + super(initialInput, {}, parent); + + this.subscription = new Subscription(); + this.subscription.add(this.getInput$().subscribe(() => this.reload())); + } + + setTitle(title: string) { + this.updateInput({ title }); + } + + public render(node: HTMLElement) { + this.node = node; + this.setTitle( + this.input.title || + i18n.translate('xpack.observability.sloEmbeddable.displayTitle', { + defaultMessage: 'SLO Alerts', + }) + ); + this.input.lastReloadRequestTime = Date.now(); + + // const { sloId, sloInstanceId } = this.getInput(); + + const I18nContext = this.deps.i18n.Context; + ReactDOM.render( + + +

+ +

+
+
, + node + ); + } + + public reload() { + if (this.node) { + this.render(this.node); + } + } + + public destroy() { + super.destroy(); + this.subscription.unsubscribe(); + if (this.node) { + ReactDOM.unmountComponentAtNode(this.node); + } + } +} diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts new file mode 100644 index 0000000000000..793b958aecec9 --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -0,0 +1,73 @@ +/* + * 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 type { CoreSetup } from '@kbn/core/public'; +import { + IContainer, + EmbeddableFactoryDefinition, + EmbeddableFactory, + ErrorEmbeddable, +} from '@kbn/embeddable-plugin/public'; +import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; +import { SLOAlertsEmbeddable, SLO_ALERTS_EMBEDDABLE } from './slo_alerts_embeddable'; +import { ObservabilityPublicPluginsStart, ObservabilityPublicStart } from '../../..'; + +export type SloAlertsEmbeddableFactory = EmbeddableFactory; +export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDefinition { + public readonly type = SLO_ALERTS_EMBEDDABLE; + + constructor( + private getStartServices: CoreSetup< + ObservabilityPublicPluginsStart, + ObservabilityPublicStart + >['getStartServices'] + ) {} + + public async isEditable() { + return true; + } + + // public async getExplicitInput(): Promise> { + // const [coreStart, pluginStart] = await this.getStartServices(); + // try { + // const { resolveEmbeddableSloUserInput } = await import('./handle_explicit_input'); + // return await resolveEmbeddableSloUserInput(coreStart, pluginStart); + // } catch (e) { + // return Promise.reject(); + // } + // } + + public async create(initialInput: EmbeddableInput, parent?: IContainer) { + try { + const [{ uiSettings, application, http, i18n: i18nService }] = await this.getStartServices(); + return new SLOAlertsEmbeddable( + { uiSettings, application, http, i18n: i18nService }, + initialInput, + parent + ); + } catch (e) { + return new ErrorEmbeddable(e, initialInput, parent); + } + } + + public getDescription() { + return i18n.translate('xpack.observability.sloAlertsEmbeddable.description', { + defaultMessage: 'Get SLO alerts', + }); + } + + public getDisplayName() { + return i18n.translate('xpack.observability.sloAlertsEmbeddable.displayName', { + defaultMessage: 'SLO Alerts', + }); + } + + public getIconType() { + return 'visGauge'; + } +} diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts index 87fc2a2a94365..eb75c462682a4 100644 --- a/x-pack/plugins/observability/public/plugin.ts +++ b/x-pack/plugins/observability/public/plugin.ts @@ -297,6 +297,15 @@ export class Plugin }; registerSloEmbeddableFactory(); + const registerSloAlertsEmbeddableFactory = async () => { + const { SloAlertsEmbeddableFactoryDefinition } = await import( + './embeddable/slo/alerts/slo_alerts_embeddable_factory' + ); + const factory = new SloAlertsEmbeddableFactoryDefinition(coreSetup.getStartServices); + pluginsSetup.embeddable.registerEmbeddableFactory(factory.type, factory); + }; + registerSloAlertsEmbeddableFactory(); + if (pluginsSetup.home) { pluginsSetup.home.featureCatalogue.registerSolution({ id: observabilityFeatureId, From 81c9252d33c44b4cd20539c1816896fd43042a3d Mon Sep 17 00:00:00 2001 From: mgiota Date: Thu, 26 Oct 2023 09:48:58 +0200 Subject: [PATCH 02/85] group slo embeddables --- .../embeddable/slo/alerts/slo_alerts_embeddable_factory.ts | 7 +++++++ .../embeddable/slo/overview/slo_embeddable_factory.ts | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index 793b958aecec9..4ec50792308cf 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -21,6 +21,13 @@ export type SloAlertsEmbeddableFactory = EmbeddableFactory; export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDefinition { public readonly type = SLO_ALERTS_EMBEDDABLE; + public readonly grouping = [ + { + id: 'slos', + getDisplayName: () => 'SLOs', + }, + ]; + constructor( private getStartServices: CoreSetup< ObservabilityPublicPluginsStart, diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts index 7adb76eb9acfe..a6930e5732eee 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts @@ -21,6 +21,13 @@ export type SloOverviewEmbeddableFactory = EmbeddableFactory; export class SloOverviewEmbeddableFactoryDefinition implements EmbeddableFactoryDefinition { public readonly type = SLO_EMBEDDABLE; + public readonly grouping = [ + { + id: 'slos', + getDisplayName: () => 'SLOs', + }, + ]; + constructor( private getStartServices: CoreSetup< ObservabilityPublicPluginsStart, From f18370276621709cb3d1af0856b494b7f21436f9 Mon Sep 17 00:00:00 2001 From: mgiota Date: Thu, 26 Oct 2023 23:13:31 +0200 Subject: [PATCH 03/85] pass triggersActionsUi as a dependency --- .../slo/alerts/slo_alerts_embeddable.tsx | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index b492bfbc5422e..97fd7b54feaea 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -65,12 +65,24 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable -

- -

+
, node From aa15c7003b565a9a8c7fbb1183fe6bb11740af2d Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 26 Oct 2023 22:46:03 +0000 Subject: [PATCH 04/85] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../public/embeddable/slo/alerts/slo_alerts_embeddable.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 97fd7b54feaea..a9ccea2f92099 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -5,7 +5,6 @@ * 2.0. */ import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; import ReactDOM from 'react-dom'; import { Subscription } from 'rxjs'; import { i18n } from '@kbn/i18n'; From 4f6dbe7abce181550c05b81b31498cbee5c04ac5 Mon Sep 17 00:00:00 2001 From: mgiota Date: Fri, 27 Oct 2023 09:22:51 +0200 Subject: [PATCH 05/85] attempt to use AlertsStateTable from triggersActionsUI (temp) --- .../slo/alerts/slo_alerts_embeddable.tsx | 37 ++++++++++++++----- .../alerts/slo_alerts_embeddable_factory.ts | 7 +++- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index a9ccea2f92099..4e17a9e89a31f 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -5,6 +5,8 @@ * 2.0. */ import React from 'react'; +import { AlertConsumers } from '@kbn/rule-data-utils'; + import ReactDOM from 'react-dom'; import { Subscription } from 'rxjs'; import { i18n } from '@kbn/i18n'; @@ -18,6 +20,8 @@ import { import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/public'; +import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; +import { ALL_VALUE } from '@kbn/slo-schema'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; @@ -26,8 +30,12 @@ interface SloEmbeddableDeps { http: CoreStart['http']; i18n: CoreStart['i18n']; application: ApplicationStart; + triggersActionsUi: TriggersAndActionsUIPublicPluginStart; } +const ALERTS_PER_PAGE = 10; +const ALERTS_TABLE_ID = 'xpack.observability.sloEmbeddable.alert.table'; + export class SLOAlertsEmbeddable extends AbstractEmbeddable { public readonly type = SLO_ALERTS_EMBEDDABLE; private subscription: Subscription; @@ -39,6 +47,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable this.reload())); @@ -58,29 +67,37 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable , diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index 4ec50792308cf..6f4680229c65f 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -51,9 +51,12 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe public async create(initialInput: EmbeddableInput, parent?: IContainer) { try { - const [{ uiSettings, application, http, i18n: i18nService }] = await this.getStartServices(); + const [ + { uiSettings, application, http, i18n: i18nService, notifications }, + { triggersActionsUi }, + ] = await this.getStartServices(); return new SLOAlertsEmbeddable( - { uiSettings, application, http, i18n: i18nService }, + { uiSettings, application, http, i18n: i18nService, triggersActionsUi, notifications }, initialInput, parent ); From 056ab9198666b3d445f9726b5c515468a7df9198 Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 6 Nov 2023 00:49:40 +0100 Subject: [PATCH 06/85] pass required deps and context --- .../slo/alerts/slo_alerts_embeddable.tsx | 48 +++++++++++-------- .../alerts/slo_alerts_embeddable_factory.ts | 13 ++++- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 4e17a9e89a31f..db9c2d0280bf2 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -9,8 +9,11 @@ import { AlertConsumers } from '@kbn/rule-data-utils'; import ReactDOM from 'react-dom'; import { Subscription } from 'rxjs'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; + import { i18n } from '@kbn/i18n'; import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; +import { Storage } from '@kbn/kibana-utils-plugin/public'; import { Embeddable as AbstractEmbeddable, @@ -22,6 +25,7 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/public'; import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; import { ALL_VALUE } from '@kbn/slo-schema'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; @@ -31,6 +35,7 @@ interface SloEmbeddableDeps { i18n: CoreStart['i18n']; application: ApplicationStart; triggersActionsUi: TriggersAndActionsUIPublicPluginStart; + data: DataPublicPluginStart; } const ALERTS_PER_PAGE = 10; @@ -66,6 +71,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable - - + + + + , node diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index 6f4680229c65f..3deb2beafa7da 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -53,10 +53,19 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe try { const [ { uiSettings, application, http, i18n: i18nService, notifications }, - { triggersActionsUi }, + { triggersActionsUi, cases, data }, ] = await this.getStartServices(); return new SLOAlertsEmbeddable( - { uiSettings, application, http, i18n: i18nService, triggersActionsUi, notifications }, + { + uiSettings, + application, + http, + i18n: i18nService, + triggersActionsUi, + notifications, + cases, + data, + }, initialInput, parent ); From 65fe769fef7b0a577a9d7b911ccefd6259913d14 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Sun, 5 Nov 2023 23:54:20 +0000 Subject: [PATCH 07/85] [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' --- .../public/embeddable/slo/alerts/slo_alerts_embeddable.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index db9c2d0280bf2..4b7f88e9e9f64 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -24,7 +24,6 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/public'; import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; -import { ALL_VALUE } from '@kbn/slo-schema'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; From 8c3c95cda0c29bf50c001368dc80ec730ae11b87 Mon Sep 17 00:00:00 2001 From: mgiota Date: Fri, 10 Nov 2023 10:13:35 +0100 Subject: [PATCH 08/85] select multiple slos & calculate active alerts --- .../slo/alerts/handle_explicit_input.tsx | 55 +++++++++ .../slo/alerts/slo_alerts_embeddable.tsx | 9 +- .../alerts/slo_alerts_embeddable_factory.ts | 20 ++-- .../slo/alerts/slo_configuration.tsx | 89 +++++++++++++++ .../embeddable/slo/alerts/slo_selector.tsx | 107 ++++++++++++++++++ .../embeddable/slo/alerts/slo_summary.tsx | 37 ++++++ .../public/embeddable/slo/alerts/types.ts | 19 ++++ 7 files changed, 323 insertions(+), 13 deletions(-) create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx new file mode 100644 index 0000000000000..0c36b4e915c6c --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx @@ -0,0 +1,55 @@ +/* + * 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 React from 'react'; +import { toMountPoint } from '@kbn/react-kibana-mount'; + +import type { CoreStart } from '@kbn/core/public'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import type { EmbeddableSloProps, SloEmbeddableInput } from './types'; + +import { ObservabilityPublicPluginsStart } from '../../..'; +import { SloConfiguration } from './slo_configuration'; +export async function resolveEmbeddableSloUserInput( + coreStart: CoreStart, + pluginStart: ObservabilityPublicPluginsStart, + input?: SloEmbeddableInput +): Promise { + const { overlays } = coreStart; + const queryClient = new QueryClient(); + return new Promise(async (resolve, reject) => { + try { + const modalSession = overlays.openModal( + toMountPoint( + + + { + modalSession.close(); + resolve(update); + }} + onCancel={() => { + modalSession.close(); + reject(); + }} + /> + + , + { i18n: coreStart.i18n, theme: coreStart.theme } + ) + ); + } catch (error) { + reject(error); + } + }); +} diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 4b7f88e9e9f64..25f600f9e46bc 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -25,6 +25,7 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/public'; import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { SloSummary } from './slo_summary'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; @@ -81,12 +82,13 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable - + /> */} + , diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index 3deb2beafa7da..e0a84d7b94f90 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -39,15 +39,15 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe return true; } - // public async getExplicitInput(): Promise> { - // const [coreStart, pluginStart] = await this.getStartServices(); - // try { - // const { resolveEmbeddableSloUserInput } = await import('./handle_explicit_input'); - // return await resolveEmbeddableSloUserInput(coreStart, pluginStart); - // } catch (e) { - // return Promise.reject(); - // } - // } + public async getExplicitInput(): Promise> { + const [coreStart, pluginStart] = await this.getStartServices(); + try { + const { resolveEmbeddableSloUserInput } = await import('./handle_explicit_input'); + return await resolveEmbeddableSloUserInput(coreStart, pluginStart); + } catch (e) { + return Promise.reject(); + } + } public async create(initialInput: EmbeddableInput, parent?: IContainer) { try { @@ -87,6 +87,6 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe } public getIconType() { - return 'visGauge'; + return 'alert'; } } diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx new file mode 100644 index 0000000000000..a808354e087c0 --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx @@ -0,0 +1,89 @@ +/* + * 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 React, { useState } from 'react'; +import { + EuiModal, + EuiModalHeader, + EuiModalHeaderTitle, + EuiModalBody, + EuiModalFooter, + EuiButton, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { SloSelector } from './slo_selector'; + +import type { EmbeddableSloProps } from './types'; + +interface SloConfigurationProps { + onCreate: (props: EmbeddableSloProps) => void; // TODO check change point detection + onCancel: () => void; +} + +export function SloConfiguration({ onCreate, onCancel }: SloConfigurationProps) { + const [selectedSlos, setSelectedSlos] = useState(); + const onConfirmClick = () => onCreate({ slos: selectedSlos }); + const [hasError, setHasError] = useState(false); + + return ( + + + + {i18n.translate('xpack.observability.sloEmbeddable.config.sloSelector.headerTitle', { + defaultMessage: 'SLO configuration', + })} + + + + + + { + if (slos === undefined) { + setHasError(true); + } else { + setHasError(false); + } + setSelectedSlos( + slos?.map((slo) => ({ + id: slo?.id, + instanceId: slo?.instanceId, + })) + ); + }} + /> + + + + + + + + + + + + + + ); +} diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx new file mode 100644 index 0000000000000..17c65b1b7b681 --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx @@ -0,0 +1,107 @@ +/* + * 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 React, { useEffect, useMemo, useState } from 'react'; +import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { debounce } from 'lodash'; +import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; +import { useFetchSloList } from '../../../hooks/slo/use_fetch_slo_list'; + +interface Props { + initialSlo?: SLOWithSummaryResponse; + onSelected: (slos: SLOWithSummaryResponse[] | undefined) => void; + hasError?: boolean; +} + +const SLO_REQUIRED = i18n.translate('xpack.observability.sloEmbeddable.config.errors.sloRequired', { + defaultMessage: 'SLO is required.', +}); + +export function SloSelector({ initialSlo, onSelected, hasError }: Props) { + const [options, setOptions] = useState>>([]); + const [selectedOptions, setSelectedOptions] = useState>>(); + const [searchValue, setSearchValue] = useState(''); + const { + isInitialLoading, + isLoading, + data: sloList, + } = useFetchSloList({ + kqlQuery: `slo.name: ${searchValue.replaceAll(' ', '*')}*`, + }); + + useEffect(() => { + const isLoadedWithData = !isLoading && sloList!.results !== undefined; + const opts: Array> = isLoadedWithData + ? sloList!.results!.map((slo) => { + const label = + slo.instanceId !== ALL_VALUE + ? `${slo.name} (${slo.groupBy}: ${slo.instanceId})` + : slo.name; + return { + value: `${slo.id}-${slo.instanceId}`, + label, + instanceId: slo.instanceId, + }; + }) + : []; + setOptions(opts); + }, [isLoading, sloList]); + + const onChange = (opts: Array>) => { + console.log(opts, '!!opts'); + setSelectedOptions(opts); + const selectedSlos = + opts.length >= 1 + ? sloList!.results?.filter((slo) => + opts.find((opt) => opt.value === `${slo.id}-${slo.instanceId}`) + ) + : undefined; + console.log(selectedSlos, '!!selectdSlo'); + onSelected(selectedSlos); + }; + + const onSearchChange = useMemo( + () => + debounce((value: string) => { + setSearchValue(value); + }, 300), + [] + ); + + if (isInitialLoading) { + return null; + } + + return ( + + + + ); +} diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx new file mode 100644 index 0000000000000..8184ef175556e --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx @@ -0,0 +1,37 @@ +/* + * 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 React, { useEffect } from 'react'; +import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; + +import { EmbeddableSloProps } from './types'; + +export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) { + // const { data: activeAlerts } = useFetchActiveAlerts({ + // sloIdsAndInstanceIds: [ + // // ['2f3f52a0-7b60-11ee-8f2d-95d71754a584', '*'], + // // ['4776bb30-7bb3-11ee-8f2d-95d71754a584', '*'], + // ['9270f550-7b5f-11ee-8f2d-95d71754a584', '*'], + // ], + // }); + const { data: activeAlerts } = useFetchActiveAlerts({ + sloIdsAndInstanceIds: slos.map(Object.values), + }); + console.log(activeAlerts, '!!activeAlerts'); + console.log(slos.map(Object.values)); + const y = slos.map(Object.values); + // useEffect(() => { + // refetch(); + // }, [lastReloadRequestTime, refetch]); + let numOfAlerts = 0; + slos.forEach((slo) => { + if (activeAlerts.get(slo)) { + numOfAlerts = numOfAlerts + activeAlerts.get(slo); + } + }); + return

{numOfAlerts}

; +} diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts new file mode 100644 index 0000000000000..c10827d9a337a --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts @@ -0,0 +1,19 @@ +/* + * 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 { EmbeddableInput } from '@kbn/embeddable-plugin/public'; + +interface SloItem { + id: string | undefined; + instanceId: string | undefined; +} + +export interface EmbeddableSloProps { + slos: SloItem[]; + lastReloadRequestTime?: number | undefined; +} + +export type SloEmbeddableInput = EmbeddableInput & EmbeddableSloProps; From 7fb4777341b5d79c0ced9afbba1c826cc05bfe04 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 10 Nov 2023 09:22:47 +0000 Subject: [PATCH 09/85] [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' --- .../public/embeddable/slo/alerts/slo_alerts_embeddable.tsx | 1 - .../observability/public/embeddable/slo/alerts/slo_summary.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 25f600f9e46bc..454cb67efce2c 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -5,7 +5,6 @@ * 2.0. */ import React from 'react'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import ReactDOM from 'react-dom'; import { Subscription } from 'rxjs'; diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx index 8184ef175556e..ebe7b61f0286e 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useEffect } from 'react'; +import React from 'react'; import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; import { EmbeddableSloProps } from './types'; From c723f2d7c7234db3e01d65375cec9a7c74271394 Mon Sep 17 00:00:00 2001 From: mgiota Date: Fri, 10 Nov 2023 12:21:05 +0100 Subject: [PATCH 10/85] style embeddable alert --- .../embeddable/slo/alerts/slo_summary.tsx | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx index ebe7b61f0286e..09cb1113d6bf7 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx @@ -6,6 +6,8 @@ */ import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiFlexGroup, EuiText, EuiFlexItem, EuiPanel, EuiStat } from '@elastic/eui'; import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; import { EmbeddableSloProps } from './types'; @@ -33,5 +35,44 @@ export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) numOfAlerts = numOfAlerts + activeAlerts.get(slo); } }); - return

{numOfAlerts}

; + return ( + + + + + +

+ {i18n.translate('xpack.observability.sloSummary.h5.activeAlertsLabel', { + defaultMessage: 'Active Alerts', + })} +

+
+
+ + {/* + + + + */} +
+ + + + + + +
+
+ ); } From 5a59d64b8573b09a68995f38c6dbe60ca28cdf45 Mon Sep 17 00:00:00 2001 From: mgiota Date: Fri, 10 Nov 2023 12:59:03 +0100 Subject: [PATCH 11/85] set initial dimensions to the alerts panel --- .../slo/alerts/slo_alerts_embeddable_factory.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index e0a84d7b94f90..30026f3bda27f 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -14,11 +14,14 @@ import { ErrorEmbeddable, } from '@kbn/embeddable-plugin/public'; import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; +import { IProvidesPanelPlacementSettings } from '@kbn/dashboard-plugin/public/dashboard_container/component/panel_placement/types'; import { SLOAlertsEmbeddable, SLO_ALERTS_EMBEDDABLE } from './slo_alerts_embeddable'; import { ObservabilityPublicPluginsStart, ObservabilityPublicStart } from '../../..'; export type SloAlertsEmbeddableFactory = EmbeddableFactory; -export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDefinition { +export class SloAlertsEmbeddableFactoryDefinition + implements EmbeddableFactoryDefinition, IProvidesPanelPlacementSettings +{ public readonly type = SLO_ALERTS_EMBEDDABLE; public readonly grouping = [ @@ -39,6 +42,15 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe return true; } + public getPanelPlacementSettings: IProvidesPanelPlacementSettings< + SloEmbeddableInput, + unknown + >['getPanelPlacementSettings'] = () => { + const width = 8; + const height = 7; + return { width, height }; + }; + public async getExplicitInput(): Promise> { const [coreStart, pluginStart] = await this.getStartServices(); try { From 854f76f5ae5989f24831f7f674ad61b9d5733f86 Mon Sep 17 00:00:00 2001 From: mgiota Date: Fri, 10 Nov 2023 14:47:16 +0100 Subject: [PATCH 12/85] add badges (need styling) --- .../slo/alerts/slo_configuration.tsx | 1 + .../embeddable/slo/alerts/slo_summary.tsx | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx index a808354e087c0..d5b5f0309883f 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx @@ -57,6 +57,7 @@ export function SloConfiguration({ onCreate, onCancel }: SloConfigurationProps) slos?.map((slo) => ({ id: slo?.id, instanceId: slo?.instanceId, + name: slo?.name, })) ); }} diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx index 09cb1113d6bf7..130b0bbe3fc6b 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx @@ -6,8 +6,9 @@ */ import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; -import { EuiFlexGroup, EuiText, EuiFlexItem, EuiPanel, EuiStat } from '@elastic/eui'; +import { EuiFlexGroup, EuiText, EuiFlexItem, EuiPanel, EuiStat, EuiBadge } from '@elastic/eui'; import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; import { EmbeddableSloProps } from './types'; @@ -20,6 +21,9 @@ export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) // ['9270f550-7b5f-11ee-8f2d-95d71754a584', '*'], // ], // }); + const sloNames = slos.map((slo) => `${slo.name}(${slo.instanceId})`); // TODO hide * + console.log(sloNames, '!!names'); + const more = sloNames.length - 1; const { data: activeAlerts } = useFetchActiveAlerts({ sloIdsAndInstanceIds: slos.map(Object.values), }); @@ -49,14 +53,10 @@ export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) - {/* - - - - */} + + {sloNames[0]} + {`+${more} more`} + From 9d0487d32c7776c7363d18050f43638cfa39e232 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 10 Nov 2023 14:22:32 +0000 Subject: [PATCH 13/85] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../observability/public/embeddable/slo/alerts/slo_summary.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx index 130b0bbe3fc6b..a050f130efac8 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiText, EuiFlexItem, EuiPanel, EuiStat, EuiBadge } from '@elastic/eui'; import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; From 87faa7fa70f5525b59c200336c60421de6b04a6c Mon Sep 17 00:00:00 2001 From: mgiota Date: Sun, 12 Nov 2023 22:22:19 +0100 Subject: [PATCH 14/85] unit tests for slo summary --- .../slo/alerts/slo_summary.test.tsx | 48 +++++++++++++++++++ .../embeddable/slo/alerts/slo_summary.tsx | 31 +++++++----- 2 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx new file mode 100644 index 0000000000000..7cf0e33e95b9a --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx @@ -0,0 +1,48 @@ +/* + * 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 { screen } from '@testing-library/react'; +import React from 'react'; + +import { sloList } from '../../../data/slo/slo'; +import { render } from '../../../utils/test_helper'; +import { SloSummary } from './slo_summary'; +import { ActiveAlerts, useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; +import { ALL_VALUE } from '@kbn/slo-schema'; + +jest.mock('../../../hooks/slo/use_fetch_active_alerts'); +const useFetchActiveAlertsMock = useFetchActiveAlerts as jest.Mock; + +describe('SLO Alert Summary', () => { + describe('Multiple selected SLOs', () => { + it('displays 0 alerts when there are no active alerts', async () => { + const { results } = sloList; + const slos = results.map((slo) => ({ + id: slo.id, + instanceId: slo.instanceId, + name: slo.name, + })); + const activeAlerts = new Map(); + activeAlerts.set('1f1c6ee7-433f-4b56-b727-5682262e0d7d|*', 1); + jest + .spyOn(ActiveAlerts.prototype, 'get') + .mockImplementation((slo) => activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`)); + + useFetchActiveAlertsMock.mockReturnValue({ + isLoading: false, + data: new ActiveAlerts({ '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1 }), + }); + + render(); + expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('1'); + }); + + describe('Partition by SLOs', () => {}); + }); + + describe('One selected SLO', () => {}); +}); diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx index a050f130efac8..abc1e1bcf88cd 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx @@ -28,12 +28,11 @@ export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) }); console.log(activeAlerts, '!!activeAlerts'); console.log(slos.map(Object.values)); - const y = slos.map(Object.values); - // useEffect(() => { - // refetch(); - // }, [lastReloadRequestTime, refetch]); + let numOfAlerts = 0; slos.forEach((slo) => { + console.log(slo, '!!slo'); + console.log(activeAlerts.get(slo), '!!activeAlerts.get(slo)'); if (activeAlerts.get(slo)) { numOfAlerts = numOfAlerts + activeAlerts.get(slo); } @@ -41,8 +40,8 @@ export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) return ( - - + +

{i18n.translate('xpack.observability.sloSummary.h5.activeAlertsLabel', { @@ -51,11 +50,19 @@ export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps)

- - - {sloNames[0]} - {`+${more} more`} - + + + {sloNames[0]} + + + {`+${more} more`} + +
@@ -66,7 +73,7 @@ export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) titleSize="l" textAlign="right" isLoading={false} - data-test-subj="sloDetailsBurnRateStat" + data-test-subj="sloAlertsSummaryStat" description="" />
From b3ad6519603f9744ab60d96ae457d5f57f4bc922 Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 13 Nov 2023 10:16:37 +0100 Subject: [PATCH 15/85] more unit test scenarios --- .../slo/alerts/slo_summary.test.tsx | 153 +++++++++++++++++- 1 file changed, 145 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx index 7cf0e33e95b9a..9eb088f350c93 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx @@ -16,9 +16,14 @@ import { ALL_VALUE } from '@kbn/slo-schema'; jest.mock('../../../hooks/slo/use_fetch_active_alerts'); const useFetchActiveAlertsMock = useFetchActiveAlerts as jest.Mock; - describe('SLO Alert Summary', () => { describe('Multiple selected SLOs', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + afterAll(() => { + jest.clearAllMocks(); + }); it('displays 0 alerts when there are no active alerts', async () => { const { results } = sloList; const slos = results.map((slo) => ({ @@ -26,23 +31,155 @@ describe('SLO Alert Summary', () => { instanceId: slo.instanceId, name: slo.name, })); + + useFetchActiveAlertsMock.mockReturnValue({ + isLoading: false, + data: new ActiveAlerts(), + }); + + render(); + expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('0'); + }); + + describe('only 1 selected SLO has active alerts', () => { + it('displays total alerts when there are alerts from one SLO', async () => { + const { results } = sloList; + const slos = results.map((slo) => ({ + id: slo.id, + instanceId: slo.instanceId, + name: slo.name, + })); + const activeAlerts = new Map(); + const activeAlertsData = { + '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, + }; + Object.keys(activeAlertsData).forEach((key) => + activeAlerts.set(key, activeAlertsData[key]) + ); + jest + .spyOn(ActiveAlerts.prototype, 'get') + .mockImplementation((slo) => + activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`) + ); + + useFetchActiveAlertsMock.mockReturnValue({ + isLoading: false, + data: new ActiveAlerts(activeAlertsData), + }); + + render(); + expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('1'); + }); + }); + + describe('multiple SLOs have active alerts', () => { + it('displays total alerts when multiple selected SLOs have 1 active alert', async () => { + const { results } = sloList; + const slos = results.map((slo) => ({ + id: slo.id, + instanceId: slo.instanceId, + name: slo.name, + })); + const activeAlerts = new Map(); + const activeAlertsData = { + '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, + 'c0f8d669-9177-4706-9098-f397a88173a6|*': 1, + }; + Object.keys(activeAlertsData).forEach((key) => + activeAlerts.set(key, activeAlertsData[key]) + ); + jest + .spyOn(ActiveAlerts.prototype, 'get') + .mockImplementation((slo) => + activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`) + ); + + useFetchActiveAlertsMock.mockReturnValue({ + isLoading: false, + data: new ActiveAlerts(activeAlertsData), + }); + + render(); + expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('2'); + }); + + it('displays total alerts when multiple selected SLOs have multiple active alerts', async () => { + const { results } = sloList; + const slos = results.map((slo) => ({ + id: slo.id, + instanceId: slo.instanceId, + name: slo.name, + })); + const activeAlerts = new Map(); + const activeAlertsData = { + '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 3, + 'c0f8d669-9177-4706-9098-f397a88173a6|*': 2, + }; + Object.keys(activeAlertsData).forEach((key) => + activeAlerts.set(key, activeAlertsData[key]) + ); + jest + .spyOn(ActiveAlerts.prototype, 'get') + .mockImplementation((slo) => + activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`) + ); + + useFetchActiveAlertsMock.mockReturnValue({ + isLoading: false, + data: new ActiveAlerts(activeAlertsData), + }); + + render(); + expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('5'); + }); + }); + }); + + describe('One selected SLO', () => { + it('displays 0 alerts when there are no active alerts', async () => { + const { results } = sloList; + const slos = results.map((slo) => ({ + id: slo.id, + instanceId: slo.instanceId, + name: slo.name, + })); + const selectedSlo = [slos[0]]; const activeAlerts = new Map(); - activeAlerts.set('1f1c6ee7-433f-4b56-b727-5682262e0d7d|*', 1); jest .spyOn(ActiveAlerts.prototype, 'get') .mockImplementation((slo) => activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`)); + useFetchActiveAlertsMock.mockReturnValue({ + isLoading: false, + data: new ActiveAlerts(), + }); + render(); + expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('0'); + }); + + it('displays total number of alerts when there are active alerts', async () => { + const { results } = sloList; + const slos = results.map((slo) => ({ + id: slo.id, + instanceId: slo.instanceId, + name: slo.name, + })); + const selectedSlo = [slos[0]]; + const activeAlerts = new Map(); + const activeAlertsData = { + '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, + }; + Object.keys(activeAlertsData).forEach((key) => activeAlerts.set(key, activeAlertsData[key])); + jest + .spyOn(ActiveAlerts.prototype, 'get') + .mockImplementation((slo) => activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`)); useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlerts({ '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1 }), + data: new ActiveAlerts(activeAlertsData), }); + render(); - render(); expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('1'); }); - - describe('Partition by SLOs', () => {}); }); - - describe('One selected SLO', () => {}); }); From f27a8f66e04ad4e22d2eb14b458bf9ed3ef30925 Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 13 Nov 2023 11:21:50 +0100 Subject: [PATCH 16/85] refactor unit tests active alerts mocking --- .../slo/alerts/slo_summary.test.tsx | 54 ++++++++----------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx index 9eb088f350c93..78d6e7886cc61 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx @@ -16,14 +16,24 @@ import { ALL_VALUE } from '@kbn/slo-schema'; jest.mock('../../../hooks/slo/use_fetch_active_alerts'); const useFetchActiveAlertsMock = useFetchActiveAlerts as jest.Mock; + +const mockActiveAlertsGet = (activeAlerts) => { + jest + .spyOn(ActiveAlerts.prototype, 'get') + .mockImplementation((slo) => activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`)); +}; describe('SLO Alert Summary', () => { + const activeAlerts = new Map(); + afterEach(() => { + jest.clearAllMocks(); + activeAlerts.clear(); + }); + afterAll(() => { + jest.clearAllMocks(); + activeAlerts.clear(); + }); + describe('Multiple selected SLOs', () => { - afterEach(() => { - jest.clearAllMocks(); - }); - afterAll(() => { - jest.clearAllMocks(); - }); it('displays 0 alerts when there are no active alerts', async () => { const { results } = sloList; const slos = results.map((slo) => ({ @@ -49,18 +59,13 @@ describe('SLO Alert Summary', () => { instanceId: slo.instanceId, name: slo.name, })); - const activeAlerts = new Map(); const activeAlertsData = { '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, }; Object.keys(activeAlertsData).forEach((key) => activeAlerts.set(key, activeAlertsData[key]) ); - jest - .spyOn(ActiveAlerts.prototype, 'get') - .mockImplementation((slo) => - activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`) - ); + mockActiveAlertsGet(activeAlerts); useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, @@ -80,7 +85,6 @@ describe('SLO Alert Summary', () => { instanceId: slo.instanceId, name: slo.name, })); - const activeAlerts = new Map(); const activeAlertsData = { '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, 'c0f8d669-9177-4706-9098-f397a88173a6|*': 1, @@ -88,12 +92,7 @@ describe('SLO Alert Summary', () => { Object.keys(activeAlertsData).forEach((key) => activeAlerts.set(key, activeAlertsData[key]) ); - jest - .spyOn(ActiveAlerts.prototype, 'get') - .mockImplementation((slo) => - activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`) - ); - + mockActiveAlertsGet(activeAlerts); useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, data: new ActiveAlerts(activeAlertsData), @@ -110,7 +109,6 @@ describe('SLO Alert Summary', () => { instanceId: slo.instanceId, name: slo.name, })); - const activeAlerts = new Map(); const activeAlertsData = { '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 3, 'c0f8d669-9177-4706-9098-f397a88173a6|*': 2, @@ -118,11 +116,7 @@ describe('SLO Alert Summary', () => { Object.keys(activeAlertsData).forEach((key) => activeAlerts.set(key, activeAlertsData[key]) ); - jest - .spyOn(ActiveAlerts.prototype, 'get') - .mockImplementation((slo) => - activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`) - ); + mockActiveAlertsGet(activeAlerts); useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, @@ -144,10 +138,7 @@ describe('SLO Alert Summary', () => { name: slo.name, })); const selectedSlo = [slos[0]]; - const activeAlerts = new Map(); - jest - .spyOn(ActiveAlerts.prototype, 'get') - .mockImplementation((slo) => activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`)); + mockActiveAlertsGet(activeAlerts); useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, data: new ActiveAlerts(), @@ -165,14 +156,11 @@ describe('SLO Alert Summary', () => { name: slo.name, })); const selectedSlo = [slos[0]]; - const activeAlerts = new Map(); const activeAlertsData = { '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, }; Object.keys(activeAlertsData).forEach((key) => activeAlerts.set(key, activeAlertsData[key])); - jest - .spyOn(ActiveAlerts.prototype, 'get') - .mockImplementation((slo) => activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`)); + mockActiveAlertsGet(activeAlerts); useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, data: new ActiveAlerts(activeAlertsData), From 62d906a6f813a1732b2cc10d097008e034aeafb5 Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 13 Nov 2023 11:29:26 +0100 Subject: [PATCH 17/85] refactor active alerts unit tests to use an ActiveAlertsMock class --- .../slo/alerts/slo_summary.test.tsx | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx index 78d6e7886cc61..01a3063f74d59 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx @@ -11,19 +11,33 @@ import React from 'react'; import { sloList } from '../../../data/slo/slo'; import { render } from '../../../utils/test_helper'; import { SloSummary } from './slo_summary'; -import { ActiveAlerts, useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; -import { ALL_VALUE } from '@kbn/slo-schema'; +import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; +import { ALL_VALUE, SLOResponse } from '@kbn/slo-schema'; +type SLO = Pick; jest.mock('../../../hooks/slo/use_fetch_active_alerts'); const useFetchActiveAlertsMock = useFetchActiveAlerts as jest.Mock; -const mockActiveAlertsGet = (activeAlerts) => { - jest - .spyOn(ActiveAlerts.prototype, 'get') - .mockImplementation((slo) => activeAlerts.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`)); -}; +class ActiveAlertsMock { + private data: Map = new Map(); + + constructor(initialData?: Record) { + if (initialData) { + Object.keys(initialData).forEach((key) => this.data.set(key, initialData[key])); + } + } + + get(slo: SLO) { + return this.data.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`); + } + + clear() { + return this.data.clear(); + } +} + describe('SLO Alert Summary', () => { - const activeAlerts = new Map(); + const activeAlerts = new ActiveAlertsMock(); afterEach(() => { jest.clearAllMocks(); activeAlerts.clear(); @@ -44,7 +58,7 @@ describe('SLO Alert Summary', () => { useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlerts(), + data: new ActiveAlertsMock(), }); render(); @@ -62,14 +76,10 @@ describe('SLO Alert Summary', () => { const activeAlertsData = { '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, }; - Object.keys(activeAlertsData).forEach((key) => - activeAlerts.set(key, activeAlertsData[key]) - ); - mockActiveAlertsGet(activeAlerts); useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlerts(activeAlertsData), + data: new ActiveAlertsMock(activeAlertsData), }); render(); @@ -89,13 +99,10 @@ describe('SLO Alert Summary', () => { '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, 'c0f8d669-9177-4706-9098-f397a88173a6|*': 1, }; - Object.keys(activeAlertsData).forEach((key) => - activeAlerts.set(key, activeAlertsData[key]) - ); - mockActiveAlertsGet(activeAlerts); + useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlerts(activeAlertsData), + data: new ActiveAlertsMock(activeAlertsData), }); render(); @@ -113,14 +120,10 @@ describe('SLO Alert Summary', () => { '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 3, 'c0f8d669-9177-4706-9098-f397a88173a6|*': 2, }; - Object.keys(activeAlertsData).forEach((key) => - activeAlerts.set(key, activeAlertsData[key]) - ); - mockActiveAlertsGet(activeAlerts); useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlerts(activeAlertsData), + data: new ActiveAlertsMock(activeAlertsData), }); render(); @@ -138,10 +141,10 @@ describe('SLO Alert Summary', () => { name: slo.name, })); const selectedSlo = [slos[0]]; - mockActiveAlertsGet(activeAlerts); + useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlerts(), + data: new ActiveAlertsMock(), }); render(); @@ -159,11 +162,9 @@ describe('SLO Alert Summary', () => { const activeAlertsData = { '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, }; - Object.keys(activeAlertsData).forEach((key) => activeAlerts.set(key, activeAlertsData[key])); - mockActiveAlertsGet(activeAlerts); useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlerts(activeAlertsData), + data: new ActiveAlertsMock(activeAlertsData), }); render(); From 2b692847810b65ddcaa4b6a789ae4301fd9d9e34 Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 13 Nov 2023 13:33:15 +0100 Subject: [PATCH 18/85] move ActiveAlerts in a separate file (is place ok?) so that I do not have to mock it in my tests --- .../slo/alerts/slo_summary.test.tsx | 44 ++++--------------- .../use_fetch_active_alerts.ts | 3 +- .../public/hooks/slo/active_alerts.ts | 39 ++++++++++++++++ .../hooks/slo/use_fetch_active_alerts.ts | 34 +------------- .../pages/slo_details/slo_details.test.tsx | 3 +- 5 files changed, 52 insertions(+), 71 deletions(-) create mode 100644 x-pack/plugins/observability/public/hooks/slo/active_alerts.ts diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx index 01a3063f74d59..0727fffba5c1e 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx @@ -12,41 +12,12 @@ import { sloList } from '../../../data/slo/slo'; import { render } from '../../../utils/test_helper'; import { SloSummary } from './slo_summary'; import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; -import { ALL_VALUE, SLOResponse } from '@kbn/slo-schema'; -type SLO = Pick; +import { ActiveAlerts } from '../../../hooks/slo/active_alerts'; jest.mock('../../../hooks/slo/use_fetch_active_alerts'); const useFetchActiveAlertsMock = useFetchActiveAlerts as jest.Mock; -class ActiveAlertsMock { - private data: Map = new Map(); - - constructor(initialData?: Record) { - if (initialData) { - Object.keys(initialData).forEach((key) => this.data.set(key, initialData[key])); - } - } - - get(slo: SLO) { - return this.data.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`); - } - - clear() { - return this.data.clear(); - } -} - describe('SLO Alert Summary', () => { - const activeAlerts = new ActiveAlertsMock(); - afterEach(() => { - jest.clearAllMocks(); - activeAlerts.clear(); - }); - afterAll(() => { - jest.clearAllMocks(); - activeAlerts.clear(); - }); - describe('Multiple selected SLOs', () => { it('displays 0 alerts when there are no active alerts', async () => { const { results } = sloList; @@ -58,7 +29,7 @@ describe('SLO Alert Summary', () => { useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlertsMock(), + data: new ActiveAlerts(), }); render(); @@ -79,7 +50,7 @@ describe('SLO Alert Summary', () => { useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlertsMock(activeAlertsData), + data: new ActiveAlerts(activeAlertsData), }); render(); @@ -102,7 +73,7 @@ describe('SLO Alert Summary', () => { useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlertsMock(activeAlertsData), + data: new ActiveAlerts(activeAlertsData), }); render(); @@ -123,7 +94,7 @@ describe('SLO Alert Summary', () => { useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlertsMock(activeAlertsData), + data: new ActiveAlerts(activeAlertsData), }); render(); @@ -144,7 +115,7 @@ describe('SLO Alert Summary', () => { useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlertsMock(), + data: new ActiveAlerts(), }); render(); @@ -164,8 +135,9 @@ describe('SLO Alert Summary', () => { }; useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, - data: new ActiveAlertsMock(activeAlertsData), + data: new ActiveAlerts(activeAlertsData), }); + render(); expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('1'); diff --git a/x-pack/plugins/observability/public/hooks/slo/__storybook_mocks__/use_fetch_active_alerts.ts b/x-pack/plugins/observability/public/hooks/slo/__storybook_mocks__/use_fetch_active_alerts.ts index 5eaee397b9ab7..8642cda0669c1 100644 --- a/x-pack/plugins/observability/public/hooks/slo/__storybook_mocks__/use_fetch_active_alerts.ts +++ b/x-pack/plugins/observability/public/hooks/slo/__storybook_mocks__/use_fetch_active_alerts.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { ActiveAlerts, UseFetchActiveAlerts } from '../use_fetch_active_alerts'; +import { UseFetchActiveAlerts } from '../use_fetch_active_alerts'; +import { ActiveAlerts } from '../active_alerts'; export const useFetchActiveAlerts = ({ sloIdsAndInstanceIds = [], diff --git a/x-pack/plugins/observability/public/hooks/slo/active_alerts.ts b/x-pack/plugins/observability/public/hooks/slo/active_alerts.ts new file mode 100644 index 0000000000000..2a4b387df32a0 --- /dev/null +++ b/x-pack/plugins/observability/public/hooks/slo/active_alerts.ts @@ -0,0 +1,39 @@ +/* + * 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 { ALL_VALUE, SLOResponse } from '@kbn/slo-schema'; + +type SLO = Pick; +export class ActiveAlerts { + private data: Map = new Map(); + + constructor(initialData?: Record) { + if (initialData) { + Object.keys(initialData).forEach((key) => this.data.set(key, initialData[key])); + } + } + + set(slo: SLO, value: number) { + this.data.set(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`, value); + } + + get(slo: SLO) { + return this.data.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`); + } + + has(slo: SLO) { + return this.data.has(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`); + } + + delete(slo: SLO) { + return this.data.delete(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`); + } + + clear() { + return this.data.clear(); + } +} diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts index 2d234b57ab8ed..49a75f41799a0 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_active_alerts.ts @@ -8,42 +8,10 @@ import { useQuery } from '@tanstack/react-query'; import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; -import { ALL_VALUE, SLOResponse } from '@kbn/slo-schema'; import { AlertConsumers } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; - -type SLO = Pick; - -export class ActiveAlerts { - private data: Map = new Map(); - - constructor(initialData?: Record) { - if (initialData) { - Object.keys(initialData).forEach((key) => this.data.set(key, initialData[key])); - } - } - - set(slo: SLO, value: number) { - this.data.set(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`, value); - } - - get(slo: SLO) { - return this.data.get(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`); - } - - has(slo: SLO) { - return this.data.has(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`); - } - - delete(slo: SLO) { - return this.data.delete(`${slo.id}|${slo.instanceId ?? ALL_VALUE}`); - } - - clear() { - return this.data.clear(); - } -} +import { ActiveAlerts } from './active_alerts'; type SloIdAndInstanceId = [string, string]; diff --git a/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx b/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx index f31d36c822264..cdc08520cf826 100644 --- a/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx +++ b/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx @@ -14,7 +14,8 @@ import { useLicense } from '../../hooks/use_license'; import { useCapabilities } from '../../hooks/slo/use_capabilities'; import { useFetchSloDetails } from '../../hooks/slo/use_fetch_slo_details'; import { useFetchHistoricalSummary } from '../../hooks/slo/use_fetch_historical_summary'; -import { ActiveAlerts, useFetchActiveAlerts } from '../../hooks/slo/use_fetch_active_alerts'; +import { useFetchActiveAlerts } from '../../hooks/slo/use_fetch_active_alerts'; +import { ActiveAlerts } from '../../hooks/slo/active_alerts'; import { useCloneSlo } from '../../hooks/slo/use_clone_slo'; import { useDeleteSlo } from '../../hooks/slo/use_delete_slo'; import { render } from '../../utils/test_helper'; From 70b0f21601bb8ec96f784d6182e9a069eed3c6b8 Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 13 Nov 2023 13:41:10 +0100 Subject: [PATCH 19/85] TODO, more unit tests to be added --- .../public/embeddable/slo/alerts/slo_summary.test.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx index 0727fffba5c1e..44327bfcd1a2d 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx @@ -17,6 +17,12 @@ import { ActiveAlerts } from '../../../hooks/slo/active_alerts'; jest.mock('../../../hooks/slo/use_fetch_active_alerts'); const useFetchActiveAlertsMock = useFetchActiveAlerts as jest.Mock; +// TODO write a few more scenarios that cover +/** + * a) display title + * b) color of the panel + * c) use group by SLOs and verify number of alerts is correct + */ describe('SLO Alert Summary', () => { describe('Multiple selected SLOs', () => { it('displays 0 alerts when there are no active alerts', async () => { From ecc91f9e68156557114b571374f9aa74ee29e2d6 Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 13 Nov 2023 14:19:49 +0100 Subject: [PATCH 20/85] clean up --- .../slo/alerts/slo_alerts_embeddable.tsx | 1 - .../embeddable/slo/alerts/slo_selector.tsx | 2 -- .../embeddable/slo/alerts/slo_summary.tsx | 25 +++++-------------- .../public/embeddable/slo/alerts/types.ts | 1 + 4 files changed, 7 insertions(+), 22 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 454cb67efce2c..cdf709d978a78 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -82,7 +82,6 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx index 17c65b1b7b681..e08f7325e54d0 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx @@ -53,7 +53,6 @@ export function SloSelector({ initialSlo, onSelected, hasError }: Props) { }, [isLoading, sloList]); const onChange = (opts: Array>) => { - console.log(opts, '!!opts'); setSelectedOptions(opts); const selectedSlos = opts.length >= 1 @@ -61,7 +60,6 @@ export function SloSelector({ initialSlo, onSelected, hasError }: Props) { opts.find((opt) => opt.value === `${slo.id}-${slo.instanceId}`) ) : undefined; - console.log(selectedSlos, '!!selectdSlo'); onSelected(selectedSlos); }; diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx index abc1e1bcf88cd..3bf9683371af3 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx @@ -13,30 +13,17 @@ import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts import { EmbeddableSloProps } from './types'; export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) { - // const { data: activeAlerts } = useFetchActiveAlerts({ - // sloIdsAndInstanceIds: [ - // // ['2f3f52a0-7b60-11ee-8f2d-95d71754a584', '*'], - // // ['4776bb30-7bb3-11ee-8f2d-95d71754a584', '*'], - // ['9270f550-7b5f-11ee-8f2d-95d71754a584', '*'], - // ], - // }); - const sloNames = slos.map((slo) => `${slo.name}(${slo.instanceId})`); // TODO hide * - console.log(sloNames, '!!names'); + const sloNames = slos.map((slo) => `${slo.name}(${slo.instanceId})`); const more = sloNames.length - 1; const { data: activeAlerts } = useFetchActiveAlerts({ sloIdsAndInstanceIds: slos.map(Object.values), }); - console.log(activeAlerts, '!!activeAlerts'); - console.log(slos.map(Object.values)); - - let numOfAlerts = 0; - slos.forEach((slo) => { - console.log(slo, '!!slo'); - console.log(activeAlerts.get(slo), '!!activeAlerts.get(slo)'); + const totalActiveAlerts = slos.reduce((total, slo) => { if (activeAlerts.get(slo)) { - numOfAlerts = numOfAlerts + activeAlerts.get(slo); + total += activeAlerts.get(slo); } - }); + return total; + }, 0); return ( @@ -68,7 +55,7 @@ export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) Date: Tue, 14 Nov 2023 00:21:12 +0100 Subject: [PATCH 21/85] pass missing deps to embeddable in order for alerts table to be rendered properly --- .../slo/alerts/slo_alerts_embeddable.tsx | 57 ++++++++++++------- .../alerts/slo_alerts_embeddable_factory.ts | 26 +++++---- .../embeddable/slo/alerts/slo_summary.tsx | 14 +++-- x-pack/plugins/observability/public/plugin.ts | 2 + 4 files changed, 63 insertions(+), 36 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index cdf709d978a78..7269fff8a3b29 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -5,6 +5,8 @@ * 2.0. */ import React from 'react'; +import { AlertConsumers } from '@kbn/rule-data-utils'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import ReactDOM from 'react-dom'; import { Subscription } from 'rxjs'; @@ -13,7 +15,9 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; +import { createBrowserHistory } from 'history'; +const history = createBrowserHistory(); import { Embeddable as AbstractEmbeddable, EmbeddableOutput, @@ -24,6 +28,7 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/public'; import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { Router } from '@kbn/shared-ux-router'; import { SloSummary } from './slo_summary'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; @@ -85,28 +90,36 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable - - {/* */} - - + + + + {/* + + */} + + + + + + , node diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index 30026f3bda27f..1f05c78723b04 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -42,14 +42,14 @@ export class SloAlertsEmbeddableFactoryDefinition return true; } - public getPanelPlacementSettings: IProvidesPanelPlacementSettings< - SloEmbeddableInput, - unknown - >['getPanelPlacementSettings'] = () => { - const width = 8; - const height = 7; - return { width, height }; - }; + // public getPanelPlacementSettings: IProvidesPanelPlacementSettings< + // SloEmbeddableInput, + // unknown + // >['getPanelPlacementSettings'] = () => { + // const width = 8; + // const height = 7; + // return { width, height }; + // }; public async getExplicitInput(): Promise> { const [coreStart, pluginStart] = await this.getStartServices(); @@ -63,10 +63,14 @@ export class SloAlertsEmbeddableFactoryDefinition public async create(initialInput: EmbeddableInput, parent?: IContainer) { try { + const [coreStart, pluginsStart] = await this.getStartServices(); + console.log(coreStart, pluginsStart, '!!coreStart'); + const [ - { uiSettings, application, http, i18n: i18nService, notifications }, - { triggersActionsUi, cases, data }, + { uiSettings, application, http, i18n: i18nService, notifications, settings }, + { triggersActionsUi, cases, data, security }, ] = await this.getStartServices(); + // const [coreStart, pluginsStart] = await this.getStartServices(); return new SLOAlertsEmbeddable( { uiSettings, @@ -77,6 +81,8 @@ export class SloAlertsEmbeddableFactoryDefinition notifications, cases, data, + settings, + security, }, initialInput, parent diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx index 3bf9683371af3..d311d14f89344 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx @@ -8,15 +8,21 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiText, EuiFlexItem, EuiPanel, EuiStat, EuiBadge } from '@elastic/eui'; +import { euiLightVars } from '@kbn/ui-theme'; import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; import { EmbeddableSloProps } from './types'; +type SloIdAndInstanceId = [string, string]; export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) { - const sloNames = slos.map((slo) => `${slo.name}(${slo.instanceId})`); + const sloNames = slos.map((slo) => `${slo.name}(${slo.instanceId})`); // TODO remove * if no partition const more = sloNames.length - 1; + const slosWithoutName = slos.map((slo) => ({ + id: slo.id, + instanceId: slo.instanceId, + })); const { data: activeAlerts } = useFetchActiveAlerts({ - sloIdsAndInstanceIds: slos.map(Object.values), + sloIdsAndInstanceIds: slosWithoutName.map(Object.values) as SloIdAndInstanceId[], }); const totalActiveAlerts = slos.reduce((total, slo) => { if (activeAlerts.get(slo)) { @@ -44,10 +50,10 @@ export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) responsive={false} > - {sloNames[0]} + {sloNames[0]} - {`+${more} more`} + {`+${more} more`} diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts index fd7160f7452ea..050ac3b207431 100644 --- a/x-pack/plugins/observability/public/plugin.ts +++ b/x-pack/plugins/observability/public/plugin.ts @@ -8,6 +8,7 @@ import { CasesDeepLinkId, CasesUiStart, getCasesDeepLinks } from '@kbn/cases-plugin/public'; import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; import type { CloudStart } from '@kbn/cloud-plugin/public'; +import type { IUiSettingsClient } from '@kbn/core/public'; import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { AppDeepLink, @@ -143,6 +144,7 @@ export interface ObservabilityPublicPluginsStart { cloud?: CloudStart; aiops: AiopsPluginStart; serverless?: ServerlessPluginStart; + uiSettings: IUiSettingsClient; } export type ObservabilityPublicStart = ReturnType; From 385bd0889ae1159710036706aee13379f9edbd4b Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 14 Nov 2023 00:05:02 +0000 Subject: [PATCH 22/85] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../public/embeddable/slo/alerts/slo_alerts_embeddable.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 7269fff8a3b29..72fe058d3407f 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -29,7 +29,6 @@ import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/p import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { Router } from '@kbn/shared-ux-router'; -import { SloSummary } from './slo_summary'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; From 68d66ad2ca7275a2637d2f8204a370973b0e8d81 Mon Sep 17 00:00:00 2001 From: mgiota Date: Tue, 14 Nov 2023 16:12:39 +0100 Subject: [PATCH 23/85] use shareable alerts summary widget and try to render selected slos in the alerts table --- .../slo/alerts/slo_alerts_embeddable.tsx | 173 +++++++++++++++++- .../alerts/slo_alerts_embeddable_factory.ts | 3 +- 2 files changed, 169 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 72fe058d3407f..3e97b72b5297f 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -29,6 +29,9 @@ import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/p import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { Router } from '@kbn/shared-ux-router'; +import { SloSummary } from './slo_summary'; +import { AlertSummary } from './alert_summary'; +import { observabilityAlertFeatureIds } from '../../../../common/constants'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; @@ -43,6 +46,7 @@ interface SloEmbeddableDeps { const ALERTS_PER_PAGE = 10; const ALERTS_TABLE_ID = 'xpack.observability.sloEmbeddable.alert.table'; +type SloIdAndInstanceId = [string, string]; export class SLOAlertsEmbeddable extends AbstractEmbeddable { public readonly type = SLO_ALERTS_EMBEDDABLE; @@ -80,12 +84,84 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable ({ + id: slo.id, + instanceId: slo.instanceId, + })); + const sloIdsAndInstanceIds = slosWithoutName.map(Object.values) as SloIdAndInstanceId[]; + console.log(sloIdsAndInstanceIds, '!!sloIdsAndInstanceIds'); + const chartProps = { + theme: 'light', + baseTheme: 'light', + onBrushEnd: () => {}, + }; + + const alertSummaryTimeRange = { + utcFrom: '2023-11-10T15:00:00.000Z', + utcTo: '2023-11-15T15:00:00.000Z', + fixedInterval: '60s', + }; + const esQuery = { + bool: { + filter: [ + { + range: { + '@timestamp': { + gte: 'now-5m/m', + }, + }, + }, + { + term: { + 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', + }, + }, + { + term: { + 'kibana.alert.status': 'active', + }, + }, + ], + should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ + bool: { + filter: [{ term: { 'slo.id': sloId } }, { term: { 'slo.instanceId': instanceId } }], + }, + })), + minimum_should_match: 1, + }, + }; + // const esQuery = { + // bool: { + // // should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ + // // bool: { + // // filter: [ + // // { term: { 'slo.id': sloId } }, + // // { term: { 'slo.instanceId': instanceId } }, + // // ], + // // }, + // // })), + // minimum_should_match: 1, + // }, + // }; + + console.log( + sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ + bool: { + filter: [{ term: { 'slo.id': sloId } }, { term: { 'slo.instanceId': instanceId } }], + }, + })), + '!!aaaa' + ); + ReactDOM.render( @@ -95,16 +171,101 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable */} + + + {/* */} + ({ + bool: { + filter: [ + { term: { 'slo.id': sloId } }, + { term: { 'slo.instanceId': instanceId } }, + ], + }, + })), + minimum_should_match: 1, }, }} alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index 1f05c78723b04..a9b7f7c28a909 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -68,7 +68,7 @@ export class SloAlertsEmbeddableFactoryDefinition const [ { uiSettings, application, http, i18n: i18nService, notifications, settings }, - { triggersActionsUi, cases, data, security }, + { triggersActionsUi, cases, data, security, charts }, ] = await this.getStartServices(); // const [coreStart, pluginsStart] = await this.getStartServices(); return new SLOAlertsEmbeddable( @@ -83,6 +83,7 @@ export class SloAlertsEmbeddableFactoryDefinition data, settings, security, + charts, }, initialInput, parent From dfc055df1ad68ba5d28f9639c719820bf3c783b2 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 14 Nov 2023 16:00:43 +0000 Subject: [PATCH 24/85] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../public/embeddable/slo/alerts/slo_alerts_embeddable.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 3e97b72b5297f..7c62e2975a798 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -29,8 +29,6 @@ import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/p import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { Router } from '@kbn/shared-ux-router'; -import { SloSummary } from './slo_summary'; -import { AlertSummary } from './alert_summary'; import { observabilityAlertFeatureIds } from '../../../../common/constants'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; From 7d32548f40ca4021ccbdfef7ec4227866325e2b7 Mon Sep 17 00:00:00 2001 From: mgiota Date: Tue, 14 Nov 2023 20:41:34 +0100 Subject: [PATCH 25/85] render activity chart in the alerts embeddable --- .../embeddable/slo/alerts/alert_summary.tsx | 69 +++++++++++++++++++ .../slo/alerts/slo_alerts_embeddable.tsx | 10 +-- 2 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx new file mode 100644 index 0000000000000..dd01eeea00c0d --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx @@ -0,0 +1,69 @@ +/* + * 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 React, { useEffect } from 'react'; +import { observabilityAlertFeatureIds } from '../../../../common/constants'; +type SloIdAndInstanceId = [string, string]; + +export function AlertSummary({ slos, deps }) { + const { + charts, + triggersActionsUi: { getAlertSummaryWidget: AlertSummaryWidget }, + } = deps; + console.log(deps, '!!deps'); + const slosWithoutName = slos.map((slo) => ({ + id: slo.id, + instanceId: slo.instanceId, + })); + const sloIdsAndInstanceIds = slosWithoutName.map(Object.values) as SloIdAndInstanceId[]; + const esQuery = { + bool: { + filter: [ + { + range: { + '@timestamp': { + gte: 'now-5m/m', + }, + }, + }, + { + term: { + 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', + }, + }, + { + term: { + 'kibana.alert.status': 'active', + }, + }, + ], + should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ + bool: { + filter: [{ term: { 'slo.id': sloId } }, { term: { 'slo.instanceId': instanceId } }], + }, + })), + minimum_should_match: 1, + }, + }; + const alertSummaryTimeRange = { + utcFrom: '2023-11-10T15:00:00.000Z', + utcTo: '2023-11-15T15:00:00.000Z', + fixedInterval: '60s', + }; + const chartProps = { + theme: charts.theme.useChartsTheme(), + baseTheme: charts.theme.useChartsBaseTheme(), + onBrushEnd: () => {}, + }; + return ( + + ); +} diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 7c62e2975a798..4b0f4d813637e 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -159,7 +159,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable @@ -170,13 +170,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable */} - - {/* */} + Date: Wed, 15 Nov 2023 11:32:39 +0100 Subject: [PATCH 26/85] proper filter selected SLOs in the alerts table --- .../slo/alerts/slo_alerts_embeddable.tsx | 180 ++++-------------- 1 file changed, 32 insertions(+), 148 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 4b0f4d813637e..adbff512d28b7 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -30,7 +30,7 @@ import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui- import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { Router } from '@kbn/shared-ux-router'; import { observabilityAlertFeatureIds } from '../../../../common/constants'; - +import { AlertSummary } from './alert_summary'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; interface SloEmbeddableDeps { @@ -82,83 +82,18 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable ({ id: slo.id, instanceId: slo.instanceId, })); const sloIdsAndInstanceIds = slosWithoutName.map(Object.values) as SloIdAndInstanceId[]; - console.log(sloIdsAndInstanceIds, '!!sloIdsAndInstanceIds'); - const chartProps = { - theme: 'light', - baseTheme: 'light', - onBrushEnd: () => {}, - }; - - const alertSummaryTimeRange = { - utcFrom: '2023-11-10T15:00:00.000Z', - utcTo: '2023-11-15T15:00:00.000Z', - fixedInterval: '60s', - }; - const esQuery = { - bool: { - filter: [ - { - range: { - '@timestamp': { - gte: 'now-5m/m', - }, - }, - }, - { - term: { - 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', - }, - }, - { - term: { - 'kibana.alert.status': 'active', - }, - }, - ], - should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ - bool: { - filter: [{ term: { 'slo.id': sloId } }, { term: { 'slo.instanceId': instanceId } }], - }, - })), - minimum_should_match: 1, - }, - }; - // const esQuery = { - // bool: { - // // should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ - // // bool: { - // // filter: [ - // // { term: { 'slo.id': sloId } }, - // // { term: { 'slo.instanceId': instanceId } }, - // // ], - // // }, - // // })), - // minimum_should_match: 1, - // }, - // }; - console.log( - sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ - bool: { - filter: [{ term: { 'slo.id': sloId } }, { term: { 'slo.instanceId': instanceId } }], - }, - })), - '!!aaaa' - ); const deps = this.deps; ReactDOM.render( @@ -175,94 +110,43 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable ({ - bool: { - filter: [ - { term: { 'slo.id': sloId } }, - { term: { 'slo.instanceId': instanceId } }, - ], + filter: [ + { + term: { + 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', + }, + }, + // { + // term: { + // 'kibana.alert.status': 'active', + // }, + // }, + { + range: { + '@timestamp': { + gte: 'now-5m/m', // TODO read from datepicker + }, + }, + }, + { + bool: { + should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ + bool: { + filter: [ + { term: { 'slo.id': sloId } }, + { term: { 'slo.instanceId': instanceId } }, + ], + }, + })), + }, }, - })), - minimum_should_match: 1, + ], }, }} alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} configurationId={AlertConsumers.OBSERVABILITY} - featureIds={[AlertConsumers.SLO]} + featureIds={[AlertConsumers.SLO, AlertConsumers.OBSERVABILITY]} hideLazyLoader id={ALERTS_TABLE_ID} pageSize={ALERTS_PER_PAGE} From d04762365c3149d73d0ee1177b958da2f00702c7 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:08:10 +0000 Subject: [PATCH 27/85] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../public/embeddable/slo/alerts/alert_summary.tsx | 2 +- .../public/embeddable/slo/alerts/slo_alerts_embeddable.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx index dd01eeea00c0d..b63cc81e30414 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useEffect } from 'react'; +import React from 'react'; import { observabilityAlertFeatureIds } from '../../../../common/constants'; type SloIdAndInstanceId = [string, string]; diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index adbff512d28b7..9f842f26033c9 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -29,7 +29,6 @@ import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/p import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { Router } from '@kbn/shared-ux-router'; -import { observabilityAlertFeatureIds } from '../../../../common/constants'; import { AlertSummary } from './alert_summary'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; From 80995f25bbee45bfb9daf44834230db111496b98 Mon Sep 17 00:00:00 2001 From: mgiota Date: Wed, 15 Nov 2023 13:06:55 +0100 Subject: [PATCH 28/85] edit slo alerts --- x-pack/plugins/observability/kibana.jsonc | 1 + .../embeddable/slo/alerts/alert_summary.tsx | 1 - .../slo/alerts/handle_explicit_input.tsx | 5 +- .../alerts/slo_alerts_embeddable_factory.ts | 17 +---- .../public/embeddable/slo/alerts/types.ts | 2 +- .../public/embeddable/slo/constants.ts | 7 ++ x-pack/plugins/observability/public/plugin.ts | 11 ++++ .../ui_actions/edit_slo_alerts_panel.tsx | 66 +++++++++++++++++++ .../observability/public/ui_actions/index.ts | 24 +++++++ 9 files changed, 116 insertions(+), 18 deletions(-) create mode 100644 x-pack/plugins/observability/public/embeddable/slo/constants.ts create mode 100644 x-pack/plugins/observability/public/ui_actions/edit_slo_alerts_panel.tsx create mode 100644 x-pack/plugins/observability/public/ui_actions/index.ts diff --git a/x-pack/plugins/observability/kibana.jsonc b/x-pack/plugins/observability/kibana.jsonc index c03e0b499d424..6ba107b8a0876 100644 --- a/x-pack/plugins/observability/kibana.jsonc +++ b/x-pack/plugins/observability/kibana.jsonc @@ -20,6 +20,7 @@ "dataViews", "dataViewEditor", "embeddable", + "uiActions", "exploratoryView", "features", "files", diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx index b63cc81e30414..707012efa9314 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx @@ -13,7 +13,6 @@ export function AlertSummary({ slos, deps }) { charts, triggersActionsUi: { getAlertSummaryWidget: AlertSummaryWidget }, } = deps; - console.log(deps, '!!deps'); const slosWithoutName = slos.map((slo) => ({ id: slo.id, instanceId: slo.instanceId, diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx index 0c36b4e915c6c..55542475f8ec5 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx @@ -11,17 +11,18 @@ import { toMountPoint } from '@kbn/react-kibana-mount'; import type { CoreStart } from '@kbn/core/public'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import type { EmbeddableSloProps, SloEmbeddableInput } from './types'; +import type { EmbeddableSloProps, SloAlertsEmbeddableInput } from './types'; import { ObservabilityPublicPluginsStart } from '../../..'; import { SloConfiguration } from './slo_configuration'; export async function resolveEmbeddableSloUserInput( coreStart: CoreStart, pluginStart: ObservabilityPublicPluginsStart, - input?: SloEmbeddableInput + input?: SloAlertsEmbeddableInput ): Promise { const { overlays } = coreStart; const queryClient = new QueryClient(); + console.log('!!here'); return new Promise(async (resolve, reject) => { try { const modalSession = overlays.openModal( diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index a9b7f7c28a909..05756069cce1c 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -14,14 +14,12 @@ import { ErrorEmbeddable, } from '@kbn/embeddable-plugin/public'; import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; -import { IProvidesPanelPlacementSettings } from '@kbn/dashboard-plugin/public/dashboard_container/component/panel_placement/types'; import { SLOAlertsEmbeddable, SLO_ALERTS_EMBEDDABLE } from './slo_alerts_embeddable'; import { ObservabilityPublicPluginsStart, ObservabilityPublicStart } from '../../..'; +import { SloAlertsEmbeddableInput } from './types'; export type SloAlertsEmbeddableFactory = EmbeddableFactory; -export class SloAlertsEmbeddableFactoryDefinition - implements EmbeddableFactoryDefinition, IProvidesPanelPlacementSettings -{ +export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDefinition { public readonly type = SLO_ALERTS_EMBEDDABLE; public readonly grouping = [ @@ -42,16 +40,7 @@ export class SloAlertsEmbeddableFactoryDefinition return true; } - // public getPanelPlacementSettings: IProvidesPanelPlacementSettings< - // SloEmbeddableInput, - // unknown - // >['getPanelPlacementSettings'] = () => { - // const width = 8; - // const height = 7; - // return { width, height }; - // }; - - public async getExplicitInput(): Promise> { + public async getExplicitInput(): Promise> { const [coreStart, pluginStart] = await this.getStartServices(); try { const { resolveEmbeddableSloUserInput } = await import('./handle_explicit_input'); diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts index 84df69bf8fb54..efbf7c4d0d69c 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts @@ -17,4 +17,4 @@ export interface EmbeddableSloProps { lastReloadRequestTime?: number | undefined; } -export type SloEmbeddableInput = EmbeddableInput & EmbeddableSloProps; +export type SloAlertsEmbeddableInput = EmbeddableInput & EmbeddableSloProps; diff --git a/x-pack/plugins/observability/public/embeddable/slo/constants.ts b/x-pack/plugins/observability/public/embeddable/slo/constants.ts new file mode 100644 index 0000000000000..31298a375caaa --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/constants.ts @@ -0,0 +1,7 @@ +/* + * 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 SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts index 050ac3b207431..c33b696b5dd95 100644 --- a/x-pack/plugins/observability/public/plugin.ts +++ b/x-pack/plugins/observability/public/plugin.ts @@ -60,6 +60,7 @@ import { import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import { ServerlessPluginStart } from '@kbn/serverless/public'; +import type { UiActionsStart, UiActionsSetup } from '@kbn/ui-actions-plugin/public'; import { observabilityAppId, observabilityFeatureId } from '../common'; import { ALERTS_PATH, @@ -115,6 +116,7 @@ export interface ObservabilityPublicPluginsSetup { home?: HomePublicPluginSetup; usageCollection: UsageCollectionSetup; embeddable: EmbeddableSetup; + uiActions: UiActionsSetup; } export interface ObservabilityPublicPluginsStart { @@ -145,6 +147,7 @@ export interface ObservabilityPublicPluginsStart { aiops: AiopsPluginStart; serverless?: ServerlessPluginStart; uiSettings: IUiSettingsClient; + uiActions: UiActionsStart; } export type ObservabilityPublicStart = ReturnType; @@ -311,6 +314,14 @@ export class Plugin }; registerSloAlertsEmbeddableFactory(); + const registerAsyncSloAlertsUiActions = async () => { + if (pluginsSetup.uiActions) { + const { registerSloAlertsUiActions } = await import('./ui_actions'); + registerSloAlertsUiActions(pluginsSetup.uiActions, coreSetup); + } + }; + registerAsyncSloAlertsUiActions(); + if (pluginsSetup.home) { pluginsSetup.home.featureCatalogue.registerSolution({ id: observabilityFeatureId, diff --git a/x-pack/plugins/observability/public/ui_actions/edit_slo_alerts_panel.tsx b/x-pack/plugins/observability/public/ui_actions/edit_slo_alerts_panel.tsx new file mode 100644 index 0000000000000..659531158ffbe --- /dev/null +++ b/x-pack/plugins/observability/public/ui_actions/edit_slo_alerts_panel.tsx @@ -0,0 +1,66 @@ +/* + * 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 { UiActionsActionDefinition } from '@kbn/ui-actions-plugin/public'; +import { i18n } from '@kbn/i18n'; +import { ViewMode } from '@kbn/embeddable-plugin/common'; +import type { CoreSetup } from '@kbn/core/public'; +import { IEmbeddable, EmbeddableOutput } from '@kbn/embeddable-plugin/public'; +import { SLO_ALERTS_EMBEDDABLE } from '../embeddable/slo/constants'; +import { ObservabilityPublicPluginsStart, ObservabilityPublicStart } from '..'; +import { SloAlertsEmbeddableInput } from '../embeddable/slo/alerts/types'; + +export const EDIT_SLO_ALERTS_ACTION = 'editSloAlertsPanelAction'; +export interface EditSloAlertsPanelContext { + embeddable: IEmbeddable; +} +export function createEditSloAlertsPanelAction( + getStartServices: CoreSetup< + ObservabilityPublicPluginsStart, + ObservabilityPublicStart + >['getStartServices'] +): UiActionsActionDefinition { + return { + id: 'edit-slo-alerts', + type: EDIT_SLO_ALERTS_ACTION, + getIconType(context): string { + return 'pencil'; + }, + getDisplayName: () => + i18n.translate('xpack.observability.actions.editSloAlertsEmbeddableTitle', { + defaultMessage: 'Edit SLOs', + }), + async execute({ embeddable }) { + if (!embeddable) { + throw new Error('Not possible to execute an action without the embeddable context'); + } + + const [coreStart, pluginStart] = await getStartServices(); + + try { + const { resolveEmbeddableSloUserInput } = await import( + '../embeddable/slo/alerts/handle_explicit_input' + ); + + const result = await resolveEmbeddableSloUserInput( + coreStart, + pluginStart, + embeddable.getInput() + ); + embeddable.updateInput(result); + } catch (e) { + return Promise.reject(); + } + }, + async isCompatible({ embeddable }) { + return ( + embeddable.type === SLO_ALERTS_EMBEDDABLE && + embeddable.getInput().viewMode === ViewMode.EDIT + ); + }, + }; +} diff --git a/x-pack/plugins/observability/public/ui_actions/index.ts b/x-pack/plugins/observability/public/ui_actions/index.ts new file mode 100644 index 0000000000000..59929b54f597f --- /dev/null +++ b/x-pack/plugins/observability/public/ui_actions/index.ts @@ -0,0 +1,24 @@ +/* + * 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 { UiActionsSetup } from '@kbn/ui-actions-plugin/public'; +import { CONTEXT_MENU_TRIGGER } from '@kbn/embeddable-plugin/public'; +import type { CoreSetup } from '@kbn/core/public'; +import { createEditSloAlertsPanelAction } from './edit_slo_alerts_panel'; +import { ObservabilityPublicPluginsStart, ObservabilityPublicStart } from '..'; + +export function registerSloAlertsUiActions( + uiActions: UiActionsSetup, + core: CoreSetup +) { + // Initialize actions + const editSloAlertsPanelAction = createEditSloAlertsPanelAction(core.getStartServices); + // Register actions + uiActions.registerAction(editSloAlertsPanelAction); + // Assign and register triggers + uiActions.attachAction(CONTEXT_MENU_TRIGGER, editSloAlertsPanelAction.id); +} From 8d1953471617cbb38fb0df9155a2e6a277a6b6a7 Mon Sep 17 00:00:00 2001 From: mgiota Date: Wed, 15 Nov 2023 14:50:24 +0100 Subject: [PATCH 29/85] show selected slos in the slo configuration modal --- .../slo/alerts/handle_explicit_input.tsx | 1 + .../slo/alerts/slo_configuration.tsx | 11 ++++++--- .../embeddable/slo/alerts/slo_selector.tsx | 23 +++++++++++++++---- .../ui_actions/edit_slo_alerts_panel.tsx | 2 +- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx index 55542475f8ec5..45a664194ed1a 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx @@ -35,6 +35,7 @@ export async function resolveEmbeddableSloUserInput( > { modalSession.close(); resolve(update); diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx index d5b5f0309883f..fedcaa9c0ee7b 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx @@ -21,15 +21,19 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { SloSelector } from './slo_selector'; -import type { EmbeddableSloProps } from './types'; +import type { EmbeddableSloProps, SloAlertsEmbeddableInput } from './types'; interface SloConfigurationProps { + initialInput?: Partial; onCreate: (props: EmbeddableSloProps) => void; // TODO check change point detection onCancel: () => void; } -export function SloConfiguration({ onCreate, onCancel }: SloConfigurationProps) { - const [selectedSlos, setSelectedSlos] = useState(); +export function SloConfiguration({ initialInput, onCreate, onCancel }: SloConfigurationProps) { + console.log(initialInput, '!!initialInput'); + const slos = initialInput?.slos; + console.log(slos, '!!slos'); + const [selectedSlos, setSelectedSlos] = useState(slos); const onConfirmClick = () => onCreate({ slos: selectedSlos }); const [hasError, setHasError] = useState(false); @@ -46,6 +50,7 @@ export function SloConfiguration({ onCreate, onCancel }: SloConfigurationProps) { if (slos === undefined) { diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx index e08f7325e54d0..d9a4eb86b11c9 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx @@ -11,9 +11,14 @@ import { i18n } from '@kbn/i18n'; import { debounce } from 'lodash'; import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; import { useFetchSloList } from '../../../hooks/slo/use_fetch_slo_list'; +interface SloItem { + id: string | undefined; + instanceId: string | undefined; + name: string; +} interface Props { - initialSlo?: SLOWithSummaryResponse; + initialSlos?: SloItem[]; onSelected: (slos: SLOWithSummaryResponse[] | undefined) => void; hasError?: boolean; } @@ -22,9 +27,19 @@ const SLO_REQUIRED = i18n.translate('xpack.observability.sloEmbeddable.config.er defaultMessage: 'SLO is required.', }); -export function SloSelector({ initialSlo, onSelected, hasError }: Props) { - const [options, setOptions] = useState>>([]); - const [selectedOptions, setSelectedOptions] = useState>>(); +export function SloSelector({ initialSlos, onSelected, hasError }: Props) { + const initialSelectedOptions = initialSlos?.map((slo) => { + const label = slo.instanceId !== ALL_VALUE ? `${slo.name} (: ${slo.instanceId})` : slo.name; + return { + label, + value: `${slo.id}-${slo.instanceId}`, + instanceId: slo.instanceId, + }; + }); + const [options, setOptions] = useState>>(); + const [selectedOptions, setSelectedOptions] = useState>>( + initialSelectedOptions ?? [] + ); const [searchValue, setSearchValue] = useState(''); const { isInitialLoading, diff --git a/x-pack/plugins/observability/public/ui_actions/edit_slo_alerts_panel.tsx b/x-pack/plugins/observability/public/ui_actions/edit_slo_alerts_panel.tsx index 659531158ffbe..7368f898c05a0 100644 --- a/x-pack/plugins/observability/public/ui_actions/edit_slo_alerts_panel.tsx +++ b/x-pack/plugins/observability/public/ui_actions/edit_slo_alerts_panel.tsx @@ -32,7 +32,7 @@ export function createEditSloAlertsPanelAction( }, getDisplayName: () => i18n.translate('xpack.observability.actions.editSloAlertsEmbeddableTitle', { - defaultMessage: 'Edit SLOs', + defaultMessage: 'Edit configuration', }), async execute({ embeddable }) { if (!embeddable) { From 2ee36aa78bbab3bfdda7f82921d6d232446b473f Mon Sep 17 00:00:00 2001 From: mgiota Date: Wed, 15 Nov 2023 22:13:04 +0100 Subject: [PATCH 30/85] hide last updated column passing a custom configuration --- .../alerts_table/slo/default_columns.tsx | 49 +++++++++++++ .../get_slo_alerts_table_configuration.tsx | 73 +++++++++++++++++++ .../slo/alerts/slo_alerts_embeddable.tsx | 2 +- x-pack/plugins/observability/public/plugin.ts | 11 +++ 4 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx create mode 100644 x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx diff --git a/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx b/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx new file mode 100644 index 0000000000000..27d1c02e5ab8f --- /dev/null +++ b/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx @@ -0,0 +1,49 @@ +/* + * 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. + */ + +/** + * We need to produce types and code transpilation at different folders during the build of the package. + * We have types and code at different imports because we don't want to import the whole package in the resulting webpack bundle for the plugin. + * This way plugins can do targeted imports to reduce the final code bundle + */ +import { ALERT_DURATION, ALERT_REASON, ALERT_STATUS, TIMESTAMP } from '@kbn/rule-data-utils'; +import { EuiDataGridColumn } from '@elastic/eui'; +import type { ColumnHeaderOptions } from '@kbn/timelines-plugin/common'; +import { i18n } from '@kbn/i18n'; + +/** + * columns implements a subset of `EuiDataGrid`'s `EuiDataGridColumn` interface, + * plus additional TGrid column properties + */ +export const columns: Array< + Pick & ColumnHeaderOptions +> = [ + { + columnHeaderType: 'not-filtered', + displayAsText: i18n.translate('xpack.observability.alertsTGrid.statusColumnDescription', { + defaultMessage: 'Alert Status', + }), + id: ALERT_STATUS, + initialWidth: 110, + }, + { + columnHeaderType: 'not-filtered', + displayAsText: i18n.translate('xpack.observability.alertsTGrid.durationColumnDescription', { + defaultMessage: 'Duration', + }), + id: ALERT_DURATION, + initialWidth: 116, + }, + { + columnHeaderType: 'not-filtered', + displayAsText: i18n.translate('xpack.observability.alertsTGrid.reasonColumnDescription', { + defaultMessage: 'Reason', + }), + id: ALERT_REASON, + linkField: '*', + }, +]; diff --git a/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx b/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx new file mode 100644 index 0000000000000..71db30c2f2b29 --- /dev/null +++ b/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx @@ -0,0 +1,73 @@ +/* + * 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 React from 'react'; +import type { GetRenderCellValue } from '@kbn/triggers-actions-ui-plugin/public'; +import { TIMESTAMP } from '@kbn/rule-data-utils'; +import { SortOrder } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { + AlertsTableConfigurationRegistry, + RenderCustomActionsRowArgs, +} from '@kbn/triggers-actions-ui-plugin/public/types'; +import { AlertConsumers } from '@kbn/rule-data-utils'; +import { casesFeatureId, observabilityFeatureId } from '../../../../common'; +import { getRenderCellValue } from '../render_cell_value'; +import { columns } from './default_columns'; +import { + AlertActions, + Props as AlertActionsProps, +} from '../../../pages/alerts/components/alert_actions'; +import { useGetAlertFlyoutComponents } from '../../alerts_flyout/use_get_alert_flyout_components'; +import type { ObservabilityRuleTypeRegistry } from '../../../rules/create_observability_rule_type_registry'; +import type { ConfigSchema } from '../../../plugin'; +import type { TopAlert } from '../../../typings/alerts'; + +export const getSloAlertsTableConfiguration = ( + observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry, + config: ConfigSchema +): AlertsTableConfigurationRegistry => ({ + id: AlertConsumers.SLO, + cases: { featureId: casesFeatureId, owner: [observabilityFeatureId] }, + columns, + getRenderCellValue: (({ setFlyoutAlert }: { setFlyoutAlert: (data: TopAlert) => void }) => { + return getRenderCellValue({ observabilityRuleTypeRegistry, setFlyoutAlert }); + }) as unknown as GetRenderCellValue, + sort: [ + { + [TIMESTAMP]: { + order: 'desc' as SortOrder, + }, + }, + ], + useActionsColumn: () => ({ + renderCustomActionsRow: ({ + alert, + id, + setFlyoutAlert, + refresh, + }: RenderCustomActionsRowArgs) => { + return ( + ( + (acc, [field, value]) => [...acc, { field, value: value as string[] }], + [] + )} + ecsData={{ _id: alert._id, _index: alert._index }} + id={id} + observabilityRuleTypeRegistry={observabilityRuleTypeRegistry} + setFlyoutAlert={setFlyoutAlert} + refresh={refresh} + /> + ); + }, + }), + useInternalFlyout: () => { + const { header, body, footer } = useGetAlertFlyoutComponents(observabilityRuleTypeRegistry); + return { header, body, footer }; + }, +}); diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 9f842f26033c9..eb73baa2b3c95 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -144,7 +144,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable { + const { getSloAlertsTableConfiguration } = await import( + './components/alerts_table/slo/get_slo_alerts_table_configuration' + ); + return getSloAlertsTableConfiguration(this.observabilityRuleTypeRegistry, config); + }; + + getAsyncSloEmbeddableAlertsTableConfiguration().then((alertsTableConfig) => { + alertsTableConfigurationRegistry.register(alertsTableConfig); + }); + return { observabilityRuleTypeRegistry: this.observabilityRuleTypeRegistry, useRulesLink: createUseRulesLink(), From e5e5c0cf5d9d108b4736b28e2d22f7c741e0f23d Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 15 Nov 2023 21:48:07 +0000 Subject: [PATCH 31/85] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../public/components/alerts_table/slo/default_columns.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx b/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx index 27d1c02e5ab8f..7f86269b385cc 100644 --- a/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx +++ b/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx @@ -10,7 +10,7 @@ * We have types and code at different imports because we don't want to import the whole package in the resulting webpack bundle for the plugin. * This way plugins can do targeted imports to reduce the final code bundle */ -import { ALERT_DURATION, ALERT_REASON, ALERT_STATUS, TIMESTAMP } from '@kbn/rule-data-utils'; +import { ALERT_DURATION, ALERT_REASON, ALERT_STATUS } from '@kbn/rule-data-utils'; import { EuiDataGridColumn } from '@elastic/eui'; import type { ColumnHeaderOptions } from '@kbn/timelines-plugin/common'; import { i18n } from '@kbn/i18n'; From 9f97e96911771f8034d14ba76b803456fb38b4f0 Mon Sep 17 00:00:00 2001 From: mgiota Date: Wed, 15 Nov 2023 23:01:04 +0100 Subject: [PATCH 32/85] fix the loading state in the slo embeddable alerts table --- .../sections/alerts_table/hooks/use_fetch_alerts.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_fetch_alerts.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_fetch_alerts.tsx index acf00da71b5f7..d4de3eb4b8c84 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_fetch_alerts.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_fetch_alerts.tsx @@ -258,6 +258,8 @@ const useFetchAlerts = ({ ecsAlertsData, totalAlerts, }); + dispatch({ type: 'loading', loading: false }); + searchSubscription$.current.unsubscribe(); } }, From 899ff79725baffb1180026af2d5f3475a1127135 Mon Sep 17 00:00:00 2001 From: mgiota Date: Thu, 16 Nov 2023 00:01:36 +0100 Subject: [PATCH 33/85] display rule name in the alerts table --- .../alerts_table/slo/default_columns.tsx | 12 +- .../get_slo_alerts_table_configuration.tsx | 26 +--- .../alerts_table/slo/render_cell_value.tsx | 111 ++++++++++++++++++ 3 files changed, 123 insertions(+), 26 deletions(-) create mode 100644 x-pack/plugins/observability/public/components/alerts_table/slo/render_cell_value.tsx diff --git a/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx b/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx index 7f86269b385cc..ed00c86b6d3e7 100644 --- a/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx +++ b/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx @@ -10,7 +10,7 @@ * We have types and code at different imports because we don't want to import the whole package in the resulting webpack bundle for the plugin. * This way plugins can do targeted imports to reduce the final code bundle */ -import { ALERT_DURATION, ALERT_REASON, ALERT_STATUS } from '@kbn/rule-data-utils'; +import { ALERT_DURATION, ALERT_REASON, ALERT_STATUS, ALERT_RULE_NAME } from '@kbn/rule-data-utils'; import { EuiDataGridColumn } from '@elastic/eui'; import type { ColumnHeaderOptions } from '@kbn/timelines-plugin/common'; import { i18n } from '@kbn/i18n'; @@ -25,7 +25,7 @@ export const columns: Array< { columnHeaderType: 'not-filtered', displayAsText: i18n.translate('xpack.observability.alertsTGrid.statusColumnDescription', { - defaultMessage: 'Alert Status', + defaultMessage: 'Status', }), id: ALERT_STATUS, initialWidth: 110, @@ -38,6 +38,14 @@ export const columns: Array< id: ALERT_DURATION, initialWidth: 116, }, + { + columnHeaderType: 'not-filtered', + displayAsText: i18n.translate('xpack.observability.alertsTGrid.sloColumnDescription', { + defaultMessage: 'Rule name', + }), + id: ALERT_RULE_NAME, + initialWidth: 110, + }, { columnHeaderType: 'not-filtered', displayAsText: i18n.translate('xpack.observability.alertsTGrid.reasonColumnDescription', { diff --git a/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx b/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx index 71db30c2f2b29..58afc21e31651 100644 --- a/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx +++ b/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx @@ -15,7 +15,7 @@ import { } from '@kbn/triggers-actions-ui-plugin/public/types'; import { AlertConsumers } from '@kbn/rule-data-utils'; import { casesFeatureId, observabilityFeatureId } from '../../../../common'; -import { getRenderCellValue } from '../render_cell_value'; +import { getRenderCellValue } from './render_cell_value'; import { columns } from './default_columns'; import { AlertActions, @@ -43,29 +43,7 @@ export const getSloAlertsTableConfiguration = ( }, }, ], - useActionsColumn: () => ({ - renderCustomActionsRow: ({ - alert, - id, - setFlyoutAlert, - refresh, - }: RenderCustomActionsRowArgs) => { - return ( - ( - (acc, [field, value]) => [...acc, { field, value: value as string[] }], - [] - )} - ecsData={{ _id: alert._id, _index: alert._index }} - id={id} - observabilityRuleTypeRegistry={observabilityRuleTypeRegistry} - setFlyoutAlert={setFlyoutAlert} - refresh={refresh} - /> - ); - }, - }), + useInternalFlyout: () => { const { header, body, footer } = useGetAlertFlyoutComponents(observabilityRuleTypeRegistry); return { header, body, footer }; diff --git a/x-pack/plugins/observability/public/components/alerts_table/slo/render_cell_value.tsx b/x-pack/plugins/observability/public/components/alerts_table/slo/render_cell_value.tsx new file mode 100644 index 0000000000000..a7c5f7c71d535 --- /dev/null +++ b/x-pack/plugins/observability/public/components/alerts_table/slo/render_cell_value.tsx @@ -0,0 +1,111 @@ +/* + * 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 { EuiLink } from '@elastic/eui'; +import React from 'react'; +import { + ALERT_DURATION, + ALERT_RULE_NAME, + ALERT_STATUS, + ALERT_STATUS_ACTIVE, + ALERT_STATUS_RECOVERED, + ALERT_REASON, + TIMESTAMP, +} from '@kbn/rule-data-utils'; +import { isEmpty } from 'lodash'; +import type { + DeprecatedCellValueElementProps, + TimelineNonEcsData, +} from '@kbn/timelines-plugin/common'; + +import { asDuration } from '../../../../common/utils/formatters'; +import { AlertStatusIndicator } from '../../alert_status_indicator'; +import { TimestampTooltip } from '../timestamp_tooltip'; +import { parseAlert } from '../../../pages/alerts/helpers/parse_alert'; +import type { ObservabilityRuleTypeRegistry } from '../../../rules/create_observability_rule_type_registry'; +import type { TopAlert } from '../../../typings/alerts'; + +export const getMappedNonEcsValue = ({ + data, + fieldName, +}: { + data: TimelineNonEcsData[]; + fieldName: string; +}): string[] | undefined => { + const item = data.find((d) => d.field === fieldName); + if (item != null && item.value != null) { + return item.value; + } + return undefined; +}; + +const getRenderValue = (mappedNonEcsValue: any) => { + // can be updated when working on https://github.com/elastic/kibana/issues/140819 + const value = Array.isArray(mappedNonEcsValue) ? mappedNonEcsValue.join() : mappedNonEcsValue; + + if (!isEmpty(value)) { + if (typeof value === 'object') { + return JSON.stringify(value); + } + return value; + } + + return '—'; +}; + +/** + * This implementation of `EuiDataGrid`'s `renderCellValue` + * accepts `EuiDataGridCellValueElementProps`, plus `data` + * from the TGrid + */ + +export const getRenderCellValue = ({ + setFlyoutAlert, + observabilityRuleTypeRegistry, +}: { + setFlyoutAlert: (data: TopAlert) => void; + observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry; +}) => { + return ({ columnId, data }: DeprecatedCellValueElementProps) => { + if (!data) return null; + const mappedNonEcsValue = getMappedNonEcsValue({ + data, + fieldName: columnId, + }); + const value = getRenderValue(mappedNonEcsValue); + + switch (columnId) { + case ALERT_STATUS: + if (value !== ALERT_STATUS_ACTIVE && value !== ALERT_STATUS_RECOVERED) { + // NOTE: This should only be needed to narrow down the type. + // Status should be either "active" or "recovered". + return null; + } + return ; + case TIMESTAMP: + return ; + case ALERT_DURATION: + return asDuration(Number(value)); + case ALERT_RULE_NAME: + return value; + case ALERT_REASON: + const dataFieldEs = data.reduce((acc, d) => ({ ...acc, [d.field]: d.value }), {}); + const alert = parseAlert(observabilityRuleTypeRegistry)(dataFieldEs); + + return ( + setFlyoutAlert && setFlyoutAlert(alert)} + > + {alert.reason} + + ); + default: + return <>{value}; + } + }; +}; From 2320c545e0601cb96b7bfe66553e1251fb23efd3 Mon Sep 17 00:00:00 2001 From: mgiota Date: Thu, 16 Nov 2023 00:30:09 +0100 Subject: [PATCH 34/85] honor date picker --- .../public/embeddable/slo/alerts/alert_summary.tsx | 14 +++++++------- .../slo/alerts/slo_alerts_embeddable.tsx | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx index 707012efa9314..41b173dd80cb3 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { observabilityAlertFeatureIds } from '../../../../common/constants'; type SloIdAndInstanceId = [string, string]; -export function AlertSummary({ slos, deps }) { +export function AlertSummary({ slos, deps, timeRange }) { const { charts, triggersActionsUi: { getAlertSummaryWidget: AlertSummaryWidget }, @@ -24,7 +24,7 @@ export function AlertSummary({ slos, deps }) { { range: { '@timestamp': { - gte: 'now-5m/m', + gte: timeRange.from, }, }, }, @@ -33,11 +33,11 @@ export function AlertSummary({ slos, deps }) { 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', }, }, - { - term: { - 'kibana.alert.status': 'active', - }, - }, + // { + // term: { + // 'kibana.alert.status': 'active', + // }, + // }, ], should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ bool: { diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index eb73baa2b3c95..52bdcd41a3fa5 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -86,7 +86,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable ({ id: slo.id, instanceId: slo.instanceId, @@ -104,7 +104,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable */} - + Date: Thu, 16 Nov 2023 00:04:12 +0000 Subject: [PATCH 35/85] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../slo/get_slo_alerts_table_configuration.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx b/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx index 58afc21e31651..28ace3961c02c 100644 --- a/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx +++ b/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx @@ -5,22 +5,14 @@ * 2.0. */ -import React from 'react'; import type { GetRenderCellValue } from '@kbn/triggers-actions-ui-plugin/public'; import { TIMESTAMP } from '@kbn/rule-data-utils'; import { SortOrder } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { - AlertsTableConfigurationRegistry, - RenderCustomActionsRowArgs, -} from '@kbn/triggers-actions-ui-plugin/public/types'; +import { AlertsTableConfigurationRegistry } from '@kbn/triggers-actions-ui-plugin/public/types'; import { AlertConsumers } from '@kbn/rule-data-utils'; import { casesFeatureId, observabilityFeatureId } from '../../../../common'; import { getRenderCellValue } from './render_cell_value'; import { columns } from './default_columns'; -import { - AlertActions, - Props as AlertActionsProps, -} from '../../../pages/alerts/components/alert_actions'; import { useGetAlertFlyoutComponents } from '../../alerts_flyout/use_get_alert_flyout_components'; import type { ObservabilityRuleTypeRegistry } from '../../../rules/create_observability_rule_type_registry'; import type { ConfigSchema } from '../../../plugin'; From cb49f89077b5e16948424eec40713591092dbd19 Mon Sep 17 00:00:00 2001 From: mgiota Date: Thu, 16 Nov 2023 09:53:39 +0100 Subject: [PATCH 36/85] calculate alertSummaryTimeRange --- .../embeddable/slo/alerts/alert_summary.tsx | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx index 41b173dd80cb3..a4a830c16b094 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx @@ -4,10 +4,15 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; +import { getAlertSummaryTimeRange } from '../../../utils/alert_summary_widget'; import { observabilityAlertFeatureIds } from '../../../../common/constants'; -type SloIdAndInstanceId = [string, string]; +import { useTimeBuckets } from '../../../hooks/use_time_buckets'; +import { calculateTimeRangeBucketSize } from '../../../pages/overview/helpers/calculate_bucket_size'; +type SloIdAndInstanceId = [string, string]; +const DEFAULT_INTERVAL = '60s'; +const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm'; export function AlertSummary({ slos, deps, timeRange }) { const { charts, @@ -33,11 +38,6 @@ export function AlertSummary({ slos, deps, timeRange }) { 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', }, }, - // { - // term: { - // 'kibana.alert.status': 'active', - // }, - // }, ], should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ bool: { @@ -47,11 +47,31 @@ export function AlertSummary({ slos, deps, timeRange }) { minimum_should_match: 1, }, }; - const alertSummaryTimeRange = { - utcFrom: '2023-11-10T15:00:00.000Z', - utcTo: '2023-11-15T15:00:00.000Z', - fixedInterval: '60s', - }; + const timeBuckets = useTimeBuckets(); + const bucketSize = useMemo( + () => + calculateTimeRangeBucketSize( + { + from: timeRange.from, + to: timeRange.to, + }, + timeBuckets + ), + [timeRange.from, timeRange.to, timeBuckets] + ); + const alertSummaryTimeRange = useMemo( + () => + getAlertSummaryTimeRange( + { + from: timeRange.from, + to: timeRange.to, + }, + bucketSize?.intervalString || DEFAULT_INTERVAL, + bucketSize?.dateFormat || DEFAULT_DATE_FORMAT + ), + [timeRange.from, timeRange.to, bucketSize] + ); + const chartProps = { theme: charts.theme.useChartsTheme(), baseTheme: charts.theme.useChartsBaseTheme(), @@ -63,6 +83,7 @@ export function AlertSummary({ slos, deps, timeRange }) { filter={esQuery} timeRange={alertSummaryTimeRange} chartProps={chartProps} + fullSize /> ); } From 2623b680fa8308bab7d830750d1c811ecad6d0f4 Mon Sep 17 00:00:00 2001 From: mgiota Date: Thu, 16 Nov 2023 11:38:46 +0100 Subject: [PATCH 37/85] Restructure --- .../alerts/components/slo_alerts_summary.tsx | 90 +++++++++++++++++++ .../alerts/components/slo_alerts_table.tsx | 68 ++++++++++++++ .../slo/alerts/slo_alerts_embeddable.tsx | 78 +--------------- .../slo/alerts/slo_alerts_wrapper.tsx | 23 +++++ 4 files changed, 183 insertions(+), 76 deletions(-) create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx create mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx new file mode 100644 index 0000000000000..7c655a0dba9de --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx @@ -0,0 +1,90 @@ +/* + * 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 React, { useMemo } from 'react'; +import { getAlertSummaryTimeRange } from '../../../../utils/alert_summary_widget'; +import { observabilityAlertFeatureIds } from '../../../../../common/constants'; +import { useTimeBuckets } from '../../../../hooks/use_time_buckets'; +import { calculateTimeRangeBucketSize } from '../../../../pages/overview/helpers/calculate_bucket_size'; + +type SloIdAndInstanceId = [string, string]; +const DEFAULT_INTERVAL = '60s'; +const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm'; + +export function SloAlertsSummary({ slos, deps, timeRange }) { + const { + charts, + triggersActionsUi: { getAlertSummaryWidget: AlertSummaryWidget }, + } = deps; + const slosWithoutName = slos.map((slo) => ({ + id: slo.id, + instanceId: slo.instanceId, + })); + const sloIdsAndInstanceIds = slosWithoutName.map(Object.values) as SloIdAndInstanceId[]; + const esQuery = { + bool: { + filter: [ + { + range: { + '@timestamp': { + gte: timeRange.from, + }, + }, + }, + { + term: { + 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', + }, + }, + ], + should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ + bool: { + filter: [{ term: { 'slo.id': sloId } }, { term: { 'slo.instanceId': instanceId } }], + }, + })), + minimum_should_match: 1, + }, + }; + const timeBuckets = useTimeBuckets(); + const bucketSize = useMemo( + () => + calculateTimeRangeBucketSize( + { + from: timeRange.from, + to: timeRange.to, + }, + timeBuckets + ), + [timeRange.from, timeRange.to, timeBuckets] + ); + const alertSummaryTimeRange = useMemo( + () => + getAlertSummaryTimeRange( + { + from: timeRange.from, + to: timeRange.to, + }, + bucketSize?.intervalString || DEFAULT_INTERVAL, + bucketSize?.dateFormat || DEFAULT_DATE_FORMAT + ), + [timeRange.from, timeRange.to, bucketSize] + ); + + const chartProps = { + theme: charts.theme.useChartsTheme(), + baseTheme: charts.theme.useChartsBaseTheme(), + onBrushEnd: () => {}, + }; + return ( + + ); +} diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx new file mode 100644 index 0000000000000..ad82642a31d35 --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -0,0 +1,68 @@ +/* + * 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 React from 'react'; +import { AlertConsumers } from '@kbn/rule-data-utils'; + +type SloIdAndInstanceId = [string, string]; +const ALERTS_PER_PAGE = 10; +const ALERTS_TABLE_ID = 'xpack.observability.sloEmbeddable.alert.table'; + +export function SloAlertsTable({ slos, deps, timeRange }) { + const { + triggersActionsUi: { alertsTableConfigurationRegistry, getAlertsStateTable: AlertsStateTable }, + } = deps; + const slosWithoutName = slos.map((slo) => ({ + id: slo.id, + instanceId: slo.instanceId, + })); + const sloIdsAndInstanceIds = slosWithoutName.map(Object.values) as SloIdAndInstanceId[]; + + return ( + ({ + bool: { + filter: [ + { term: { 'slo.id': sloId } }, + { term: { 'slo.instanceId': instanceId } }, + ], + }, + })), + }, + }, + ], + }, + }} + alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} + configurationId={AlertConsumers.SLO} + featureIds={[AlertConsumers.SLO, AlertConsumers.OBSERVABILITY]} + hideLazyLoader + id={ALERTS_TABLE_ID} + pageSize={ALERTS_PER_PAGE} + showAlertStatusWithFlapping + onUpdate={() => { + console.log('!!update the table'); + }} + /> + ); +} diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 52bdcd41a3fa5..74f47d2a161b2 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -5,9 +5,6 @@ * 2.0. */ import React from 'react'; -import { AlertConsumers } from '@kbn/rule-data-utils'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - import ReactDOM from 'react-dom'; import { Subscription } from 'rxjs'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; @@ -16,7 +13,6 @@ import { i18n } from '@kbn/i18n'; import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { createBrowserHistory } from 'history'; - const history = createBrowserHistory(); import { Embeddable as AbstractEmbeddable, @@ -29,7 +25,7 @@ import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/p import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { Router } from '@kbn/shared-ux-router'; -import { AlertSummary } from './alert_summary'; +import { SloAlertsWrapper } from './slo_alerts_wrapper'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; interface SloEmbeddableDeps { @@ -41,8 +37,6 @@ interface SloEmbeddableDeps { data: DataPublicPluginStart; } -const ALERTS_PER_PAGE = 10; -const ALERTS_TABLE_ID = 'xpack.observability.sloEmbeddable.alert.table'; type SloIdAndInstanceId = [string, string]; export class SLOAlertsEmbeddable extends AbstractEmbeddable { @@ -74,85 +68,17 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable ({ - id: slo.id, - instanceId: slo.instanceId, - })); - const sloIdsAndInstanceIds = slosWithoutName.map(Object.values) as SloIdAndInstanceId[]; - const deps = this.deps; ReactDOM.render( - - {/* - - */} - - - - - ({ - bool: { - filter: [ - { term: { 'slo.id': sloId } }, - { term: { 'slo.instanceId': instanceId } }, - ], - }, - })), - }, - }, - ], - }, - }} - alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} - configurationId={AlertConsumers.SLO} - featureIds={[AlertConsumers.SLO, AlertConsumers.OBSERVABILITY]} - hideLazyLoader - id={ALERTS_TABLE_ID} - pageSize={ALERTS_PER_PAGE} - showAlertStatusWithFlapping - /> - - + diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx new file mode 100644 index 0000000000000..584063ae1ddf3 --- /dev/null +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -0,0 +1,23 @@ +/* + * 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 React, { useEffect } from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { SloAlertsSummary } from './components/slo_alerts_summary'; +import { SloAlertsTable } from './components/slo_alerts_table'; + +export function SloAlertsWrapper({ slos, deps, timeRange }) { + return ( + + + + + + + + + ); +} From 90d96d47ecec94cc556e8f5b0455f0ad0cbb84df Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:12:07 +0000 Subject: [PATCH 38/85] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../public/embeddable/slo/alerts/slo_alerts_wrapper.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index 584063ae1ddf3..f349b319db29f 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useEffect } from 'react'; +import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { SloAlertsSummary } from './components/slo_alerts_summary'; import { SloAlertsTable } from './components/slo_alerts_table'; From 9606eb57da06f617b8e6b5712ebe9840c3d8d72b Mon Sep 17 00:00:00 2001 From: mgiota Date: Fri, 17 Nov 2023 01:03:10 +0100 Subject: [PATCH 39/85] clean up and fix types --- .../alerts/components/slo_alerts_summary.tsx | 11 ++++++- .../alerts/components/slo_alerts_table.tsx | 14 +++++--- .../slo/alerts/slo_alerts_embeddable.tsx | 33 ++++++++++++++----- .../alerts/slo_alerts_embeddable_factory.ts | 7 +--- .../slo/alerts/slo_alerts_wrapper.tsx | 11 ++++++- .../slo/alerts/slo_configuration.tsx | 12 +++---- .../embeddable/slo/alerts/slo_selector.tsx | 29 +++++----------- .../public/embeddable/slo/alerts/types.ts | 5 ++- 8 files changed, 73 insertions(+), 49 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx index 7c655a0dba9de..bcad606d053c9 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx @@ -5,16 +5,25 @@ * 2.0. */ import React, { useMemo } from 'react'; +import type { TimeRange } from '@kbn/es-query'; import { getAlertSummaryTimeRange } from '../../../../utils/alert_summary_widget'; import { observabilityAlertFeatureIds } from '../../../../../common/constants'; import { useTimeBuckets } from '../../../../hooks/use_time_buckets'; import { calculateTimeRangeBucketSize } from '../../../../pages/overview/helpers/calculate_bucket_size'; +import { SloEmbeddableDeps } from '../slo_alerts_embeddable'; +import { SloItem } from '../types'; type SloIdAndInstanceId = [string, string]; const DEFAULT_INTERVAL = '60s'; const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm'; -export function SloAlertsSummary({ slos, deps, timeRange }) { +interface Props { + deps: SloEmbeddableDeps; + slos: SloItem[]; + timeRange: TimeRange; +} + +export function SloAlertsSummary({ slos, deps, timeRange }: Props) { const { charts, triggersActionsUi: { getAlertSummaryWidget: AlertSummaryWidget }, diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index ad82642a31d35..3cf502f4b2a05 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -6,12 +6,21 @@ */ import React from 'react'; import { AlertConsumers } from '@kbn/rule-data-utils'; +import type { TimeRange } from '@kbn/es-query'; +import { SloEmbeddableDeps } from '../slo_alerts_embeddable'; +import type { SloItem } from '../types'; type SloIdAndInstanceId = [string, string]; const ALERTS_PER_PAGE = 10; const ALERTS_TABLE_ID = 'xpack.observability.sloEmbeddable.alert.table'; -export function SloAlertsTable({ slos, deps, timeRange }) { +interface Props { + deps: SloEmbeddableDeps; + slos: SloItem[]; + timeRange: TimeRange; +} + +export function SloAlertsTable({ slos, deps, timeRange }: Props) { const { triggersActionsUi: { alertsTableConfigurationRegistry, getAlertsStateTable: AlertsStateTable }, } = deps; @@ -60,9 +69,6 @@ export function SloAlertsTable({ slos, deps, timeRange }) { id={ALERTS_TABLE_ID} pageSize={ALERTS_PER_PAGE} showAlertStatusWithFlapping - onUpdate={() => { - console.log('!!update the table'); - }} /> ); } diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 74f47d2a161b2..6c4bb4e579bec 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -10,43 +10,58 @@ import { Subscription } from 'rxjs'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; -import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { createBrowserHistory } from 'history'; -const history = createBrowserHistory(); import { Embeddable as AbstractEmbeddable, EmbeddableOutput, IContainer, } from '@kbn/embeddable-plugin/public'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { CasesUiStart } from '@kbn/cases-plugin/public'; -import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/public'; +import { + type CoreStart, + IUiSettingsClient, + ApplicationStart, + NotificationsStart, +} from '@kbn/core/public'; import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { Router } from '@kbn/shared-ux-router'; +import { SettingsStart } from '@kbn/core-ui-settings-browser'; +import { SecurityPluginStart } from '@kbn/security-plugin/public'; +import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; import { SloAlertsWrapper } from './slo_alerts_wrapper'; +import type { SloAlertsEmbeddableInput } from './types'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; +const history = createBrowserHistory(); -interface SloEmbeddableDeps { +export interface SloEmbeddableDeps { uiSettings: IUiSettingsClient; http: CoreStart['http']; i18n: CoreStart['i18n']; application: ApplicationStart; triggersActionsUi: TriggersAndActionsUIPublicPluginStart; data: DataPublicPluginStart; + notifications: NotificationsStart; + cases: CasesUiStart; + settings: SettingsStart; + security: SecurityPluginStart; + charts: ChartsPluginStart; } -type SloIdAndInstanceId = [string, string]; - -export class SLOAlertsEmbeddable extends AbstractEmbeddable { +export class SLOAlertsEmbeddable extends AbstractEmbeddable< + SloAlertsEmbeddableInput, + EmbeddableOutput +> { public readonly type = SLO_ALERTS_EMBEDDABLE; private subscription: Subscription; private node?: HTMLElement; constructor( private readonly deps: SloEmbeddableDeps, - initialInput: EmbeddableInput, + initialInput: SloAlertsEmbeddableInput, parent?: IContainer ) { super(initialInput, {}, parent); @@ -71,7 +86,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index 05756069cce1c..2c9621ba7ac0e 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -13,7 +13,6 @@ import { EmbeddableFactory, ErrorEmbeddable, } from '@kbn/embeddable-plugin/public'; -import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; import { SLOAlertsEmbeddable, SLO_ALERTS_EMBEDDABLE } from './slo_alerts_embeddable'; import { ObservabilityPublicPluginsStart, ObservabilityPublicStart } from '../../..'; import { SloAlertsEmbeddableInput } from './types'; @@ -50,16 +49,12 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe } } - public async create(initialInput: EmbeddableInput, parent?: IContainer) { + public async create(initialInput: SloAlertsEmbeddableInput, parent?: IContainer) { try { - const [coreStart, pluginsStart] = await this.getStartServices(); - console.log(coreStart, pluginsStart, '!!coreStart'); - const [ { uiSettings, application, http, i18n: i18nService, notifications, settings }, { triggersActionsUi, cases, data, security, charts }, ] = await this.getStartServices(); - // const [coreStart, pluginsStart] = await this.getStartServices(); return new SLOAlertsEmbeddable( { uiSettings, diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index f349b319db29f..ebfd3c57ea134 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -6,10 +6,19 @@ */ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import type { TimeRange } from '@kbn/es-query'; import { SloAlertsSummary } from './components/slo_alerts_summary'; import { SloAlertsTable } from './components/slo_alerts_table'; +import type { SloItem } from './types'; +import { SloEmbeddableDeps } from './slo_alerts_embeddable'; -export function SloAlertsWrapper({ slos, deps, timeRange }) { +interface Props { + deps: SloEmbeddableDeps; + slos: SloItem[]; + timeRange?: TimeRange | undefined; +} + +export function SloAlertsWrapper({ slos, deps, timeRange }: Props) { return ( diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx index fedcaa9c0ee7b..b8655f3163aea 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx @@ -21,7 +21,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { SloSelector } from './slo_selector'; -import type { EmbeddableSloProps, SloAlertsEmbeddableInput } from './types'; +import type { EmbeddableSloProps, SloAlertsEmbeddableInput, SloItem } from './types'; interface SloConfigurationProps { initialInput?: Partial; @@ -30,12 +30,9 @@ interface SloConfigurationProps { } export function SloConfiguration({ initialInput, onCreate, onCancel }: SloConfigurationProps) { - console.log(initialInput, '!!initialInput'); - const slos = initialInput?.slos; - console.log(slos, '!!slos'); - const [selectedSlos, setSelectedSlos] = useState(slos); - const onConfirmClick = () => onCreate({ slos: selectedSlos }); + const [selectedSlos, setSelectedSlos] = useState(initialInput?.slos ?? []); const [hasError, setHasError] = useState(false); + const onConfirmClick = () => onCreate({ slos: selectedSlos }); return ( @@ -63,7 +60,8 @@ export function SloConfiguration({ initialInput, onCreate, onCancel }: SloConfig id: slo?.id, instanceId: slo?.instanceId, name: slo?.name, - })) + groupBy: slo?.groupBy, + })) as SloItem[] ); }} /> diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx index d9a4eb86b11c9..5ee81cac5367e 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx @@ -15,6 +15,7 @@ interface SloItem { id: string | undefined; instanceId: string | undefined; name: string; + groupBy: string; } interface Props { @@ -28,17 +29,15 @@ const SLO_REQUIRED = i18n.translate('xpack.observability.sloEmbeddable.config.er }); export function SloSelector({ initialSlos, onSelected, hasError }: Props) { - const initialSelectedOptions = initialSlos?.map((slo) => { - const label = slo.instanceId !== ALL_VALUE ? `${slo.name} (: ${slo.instanceId})` : slo.name; - return { - label, + const mapSlosToOptions = (slos: SloItem[] | SLOWithSummaryResponse[] | undefined) => + slos?.map((slo) => ({ + label: + slo.instanceId !== ALL_VALUE ? `${slo.name} (${slo.groupBy}: ${slo.instanceId})` : slo.name, value: `${slo.id}-${slo.instanceId}`, - instanceId: slo.instanceId, - }; - }); - const [options, setOptions] = useState>>(); + })) ?? []; + const [options, setOptions] = useState>>([]); const [selectedOptions, setSelectedOptions] = useState>>( - initialSelectedOptions ?? [] + mapSlosToOptions(initialSlos) ); const [searchValue, setSearchValue] = useState(''); const { @@ -52,17 +51,7 @@ export function SloSelector({ initialSlos, onSelected, hasError }: Props) { useEffect(() => { const isLoadedWithData = !isLoading && sloList!.results !== undefined; const opts: Array> = isLoadedWithData - ? sloList!.results!.map((slo) => { - const label = - slo.instanceId !== ALL_VALUE - ? `${slo.name} (${slo.groupBy}: ${slo.instanceId})` - : slo.name; - return { - value: `${slo.id}-${slo.instanceId}`, - label, - instanceId: slo.instanceId, - }; - }) + ? mapSlosToOptions(sloList!.results!) : []; setOptions(opts); }, [isLoading, sloList]); diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts index efbf7c4d0d69c..c200aa8dd5d10 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts @@ -5,15 +5,18 @@ * 2.0. */ import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; +import type { TimeRange } from '@kbn/es-query'; -interface SloItem { +export interface SloItem { id: string | undefined; instanceId: string | undefined; name: string; + groupBy: string; } export interface EmbeddableSloProps { slos: SloItem[]; + timeRange?: TimeRange; lastReloadRequestTime?: number | undefined; } From feabba9ea26ef4101bb57a4bf554b8bec1dd94f0 Mon Sep 17 00:00:00 2001 From: mgiota Date: Fri, 17 Nov 2023 15:13:38 +0100 Subject: [PATCH 40/85] fix types --- .../embeddable/slo/alerts/alert_summary.tsx | 89 ------------------- .../alerts/components/slo_alerts_summary.tsx | 2 +- .../slo/alerts/slo_alerts_embeddable.tsx | 2 +- .../slo/alerts/slo_alerts_wrapper.tsx | 2 +- .../embeddable/slo/alerts/slo_selector.tsx | 7 +- .../slo/alerts/slo_summary.test.tsx | 22 +++-- .../embeddable/slo/alerts/slo_summary.tsx | 35 ++++---- .../public/embeddable/slo/alerts/types.ts | 4 +- 8 files changed, 39 insertions(+), 124 deletions(-) delete mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx deleted file mode 100644 index a4a830c16b094..0000000000000 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/alert_summary.tsx +++ /dev/null @@ -1,89 +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 React, { useMemo } from 'react'; -import { getAlertSummaryTimeRange } from '../../../utils/alert_summary_widget'; -import { observabilityAlertFeatureIds } from '../../../../common/constants'; -import { useTimeBuckets } from '../../../hooks/use_time_buckets'; -import { calculateTimeRangeBucketSize } from '../../../pages/overview/helpers/calculate_bucket_size'; - -type SloIdAndInstanceId = [string, string]; -const DEFAULT_INTERVAL = '60s'; -const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm'; -export function AlertSummary({ slos, deps, timeRange }) { - const { - charts, - triggersActionsUi: { getAlertSummaryWidget: AlertSummaryWidget }, - } = deps; - const slosWithoutName = slos.map((slo) => ({ - id: slo.id, - instanceId: slo.instanceId, - })); - const sloIdsAndInstanceIds = slosWithoutName.map(Object.values) as SloIdAndInstanceId[]; - const esQuery = { - bool: { - filter: [ - { - range: { - '@timestamp': { - gte: timeRange.from, - }, - }, - }, - { - term: { - 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', - }, - }, - ], - should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ - bool: { - filter: [{ term: { 'slo.id': sloId } }, { term: { 'slo.instanceId': instanceId } }], - }, - })), - minimum_should_match: 1, - }, - }; - const timeBuckets = useTimeBuckets(); - const bucketSize = useMemo( - () => - calculateTimeRangeBucketSize( - { - from: timeRange.from, - to: timeRange.to, - }, - timeBuckets - ), - [timeRange.from, timeRange.to, timeBuckets] - ); - const alertSummaryTimeRange = useMemo( - () => - getAlertSummaryTimeRange( - { - from: timeRange.from, - to: timeRange.to, - }, - bucketSize?.intervalString || DEFAULT_INTERVAL, - bucketSize?.dateFormat || DEFAULT_DATE_FORMAT - ), - [timeRange.from, timeRange.to, bucketSize] - ); - - const chartProps = { - theme: charts.theme.useChartsTheme(), - baseTheme: charts.theme.useChartsBaseTheme(), - onBrushEnd: () => {}, - }; - return ( - - ); -} diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx index bcad606d053c9..9c03a4dddb37a 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx @@ -85,7 +85,7 @@ export function SloAlertsSummary({ slos, deps, timeRange }: Props) { const chartProps = { theme: charts.theme.useChartsTheme(), baseTheme: charts.theme.useChartsBaseTheme(), - onBrushEnd: () => {}, + onBrushEnd: () => {}, // TODO }; return ( diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index ebfd3c57ea134..24e5cb0aca481 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -15,7 +15,7 @@ import { SloEmbeddableDeps } from './slo_alerts_embeddable'; interface Props { deps: SloEmbeddableDeps; slos: SloItem[]; - timeRange?: TimeRange | undefined; + timeRange: TimeRange; } export function SloAlertsWrapper({ slos, deps, timeRange }: Props) { diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx index 5ee81cac5367e..ddc47b91a5ca3 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx @@ -11,12 +11,7 @@ import { i18n } from '@kbn/i18n'; import { debounce } from 'lodash'; import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; import { useFetchSloList } from '../../../hooks/slo/use_fetch_slo_list'; -interface SloItem { - id: string | undefined; - instanceId: string | undefined; - name: string; - groupBy: string; -} +import { SloItem } from './types'; interface Props { initialSlos?: SloItem[]; diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx index 44327bfcd1a2d..d6b42ffb03b41 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx @@ -13,7 +13,7 @@ import { render } from '../../../utils/test_helper'; import { SloSummary } from './slo_summary'; import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; import { ActiveAlerts } from '../../../hooks/slo/active_alerts'; - +import { SloItem } from './types'; jest.mock('../../../hooks/slo/use_fetch_active_alerts'); const useFetchActiveAlertsMock = useFetchActiveAlerts as jest.Mock; @@ -31,7 +31,8 @@ describe('SLO Alert Summary', () => { id: slo.id, instanceId: slo.instanceId, name: slo.name, - })); + groupBy: slo.groupBy, + })) as SloItem[]; useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, @@ -49,7 +50,8 @@ describe('SLO Alert Summary', () => { id: slo.id, instanceId: slo.instanceId, name: slo.name, - })); + groupBy: slo.groupBy, + })) as SloItem[]; const activeAlertsData = { '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, }; @@ -71,7 +73,8 @@ describe('SLO Alert Summary', () => { id: slo.id, instanceId: slo.instanceId, name: slo.name, - })); + groupBy: slo.groupBy, + })) as SloItem[]; const activeAlertsData = { '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, 'c0f8d669-9177-4706-9098-f397a88173a6|*': 1, @@ -92,7 +95,8 @@ describe('SLO Alert Summary', () => { id: slo.id, instanceId: slo.instanceId, name: slo.name, - })); + groupBy: slo.groupBy, + })) as SloItem[]; const activeAlertsData = { '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 3, 'c0f8d669-9177-4706-9098-f397a88173a6|*': 2, @@ -115,8 +119,8 @@ describe('SLO Alert Summary', () => { const slos = results.map((slo) => ({ id: slo.id, instanceId: slo.instanceId, - name: slo.name, - })); + groupBy: slo.groupBy, + })) as SloItem[]; const selectedSlo = [slos[0]]; useFetchActiveAlertsMock.mockReturnValue({ @@ -133,8 +137,8 @@ describe('SLO Alert Summary', () => { const slos = results.map((slo) => ({ id: slo.id, instanceId: slo.instanceId, - name: slo.name, - })); + groupBy: slo.groupBy, + })) as SloItem[]; const selectedSlo = [slos[0]]; const activeAlertsData = { '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx index d311d14f89344..988ce4edcc7ae 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx @@ -9,24 +9,27 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiText, EuiFlexItem, EuiPanel, EuiStat, EuiBadge } from '@elastic/eui'; import { euiLightVars } from '@kbn/ui-theme'; +import { ALL_VALUE } from '@kbn/slo-schema'; import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; - import { EmbeddableSloProps } from './types'; type SloIdAndInstanceId = [string, string]; -export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) { - const sloNames = slos.map((slo) => `${slo.name}(${slo.instanceId})`); // TODO remove * if no partition - const more = sloNames.length - 1; - const slosWithoutName = slos.map((slo) => ({ - id: slo.id, - instanceId: slo.instanceId, - })); +export function SloSummary({ slos }: EmbeddableSloProps) { + const sloBadges = slos.map((slo) => + slo.instanceId !== ALL_VALUE ? `${slo.name} (${slo.instanceId})` : slo.name + ); + const more = sloBadges.length - 1; const { data: activeAlerts } = useFetchActiveAlerts({ - sloIdsAndInstanceIds: slosWithoutName.map(Object.values) as SloIdAndInstanceId[], + sloIdsAndInstanceIds: slos + .map((slo) => ({ + id: slo.id, + instanceId: slo.instanceId, + })) + .map(Object.values) as SloIdAndInstanceId[], }); const totalActiveAlerts = slos.reduce((total, slo) => { - if (activeAlerts.get(slo)) { - total += activeAlerts.get(slo); + if (activeAlerts && activeAlerts.get(slo)) { + total += activeAlerts.get(slo)!; } return total; }, 0); @@ -50,11 +53,13 @@ export function SloSummary({ slos, lastReloadRequestTime }: EmbeddableSloProps) responsive={false} > - {sloNames[0]} - - - {`+${more} more`} + {sloBadges[0]} + {more > 0 && ( + + {`+${more} more`} + + )} diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts index c200aa8dd5d10..02480110560a5 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/types.ts @@ -8,8 +8,8 @@ import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; import type { TimeRange } from '@kbn/es-query'; export interface SloItem { - id: string | undefined; - instanceId: string | undefined; + id: string; + instanceId: string; name: string; groupBy: string; } From 1a29174304d1aee49895a381f00a79c313f25928 Mon Sep 17 00:00:00 2001 From: mgiota Date: Sun, 19 Nov 2023 22:29:35 +0100 Subject: [PATCH 41/85] alerts header (slos included & go to alerts) --- .../slo/alerts/handle_explicit_input.tsx | 4 +- .../slo/alerts/slo_alerts_embeddable.tsx | 6 +- .../alerts/slo_alerts_embeddable_factory.ts | 3 +- .../slo/alerts/slo_alerts_wrapper.tsx | 93 +++++++++++++++++-- .../ui_actions/edit_slo_alerts_panel.tsx | 2 +- 5 files changed, 93 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx index 45a664194ed1a..7f246adf679aa 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/handle_explicit_input.tsx @@ -22,7 +22,6 @@ export async function resolveEmbeddableSloUserInput( ): Promise { const { overlays } = coreStart; const queryClient = new QueryClient(); - console.log('!!here'); return new Promise(async (resolve, reject) => { try { const modalSession = overlays.openModal( @@ -42,7 +41,8 @@ export async function resolveEmbeddableSloUserInput( }} onCancel={() => { modalSession.close(); - reject(); + // @ts-expect-error + resolve(undefined); }} /> diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 3901cb7ff8539..4b1f18d5b5b57 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -32,9 +32,12 @@ import { Router } from '@kbn/shared-ux-router'; import { SettingsStart } from '@kbn/core-ui-settings-browser'; import { SecurityPluginStart } from '@kbn/security-plugin/public'; import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; +import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; + import { SloAlertsWrapper } from './slo_alerts_wrapper'; import type { SloAlertsEmbeddableInput } from './types'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; + const history = createBrowserHistory(); export interface SloEmbeddableDeps { @@ -49,6 +52,7 @@ export interface SloEmbeddableDeps { settings: SettingsStart; security: SecurityPluginStart; charts: ChartsPluginStart; + uiActions: UiActionsStart; } export class SLOAlertsEmbeddable extends AbstractEmbeddable< @@ -93,7 +97,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< - + diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index 2c9621ba7ac0e..5b2727ab71c07 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -53,7 +53,7 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe try { const [ { uiSettings, application, http, i18n: i18nService, notifications, settings }, - { triggersActionsUi, cases, data, security, charts }, + { triggersActionsUi, cases, data, security, charts, uiActions }, ] = await this.getStartServices(); return new SLOAlertsEmbeddable( { @@ -68,6 +68,7 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe settings, security, charts, + uiActions, }, initialInput, parent diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index 24e5cb0aca481..081962cdede25 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -5,28 +5,101 @@ * 2.0. */ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; import type { TimeRange } from '@kbn/es-query'; +import { CONTEXT_MENU_TRIGGER } from '@kbn/embeddable-plugin/public'; +import { IEmbeddable, EmbeddableOutput } from '@kbn/embeddable-plugin/public'; +import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; import { SloAlertsSummary } from './components/slo_alerts_summary'; import { SloAlertsTable } from './components/slo_alerts_table'; import type { SloItem } from './types'; import { SloEmbeddableDeps } from './slo_alerts_embeddable'; +import { SloAlertsEmbeddableInput } from './types'; +import { EDIT_SLO_ALERTS_ACTION } from '../../../ui_actions/edit_slo_alerts_panel'; +import { paths } from '../../../../common/locators/paths'; interface Props { deps: SloEmbeddableDeps; slos: SloItem[]; timeRange: TimeRange; + embeddable: IEmbeddable; } -export function SloAlertsWrapper({ slos, deps, timeRange }: Props) { +export function SloAlertsWrapper({ embeddable, slos, deps, timeRange }: Props) { + const { + application: { navigateToUrl }, + http: { basePath }, + } = deps; + + const handleGoToAlertsClick = () => { + let kuery = ''; + slos.map((slo, index) => { + const shouldAddOr = index < slos.length - 1; + kuery += `slo.id:"${slo.id}" and slo.instanceId:"${slo.instanceId}"`; + if (shouldAddOr) { + kuery += ' or '; + } + }); + navigateToUrl( + `${basePath.prepend(paths.observability.alerts)}?_a=(kuery:'${kuery}',rangeFrom:${ + timeRange.from + },rangeTo:${timeRange.to})` + ); + }; return ( - - - - - - - - + <> + + + + + { + const trigger = deps.uiActions.getTrigger(CONTEXT_MENU_TRIGGER); + deps.uiActions.getAction(EDIT_SLO_ALERTS_ACTION).execute({ + trigger, + embeddable, + } as ActionExecutionContext); + }} + data-test-subj="o11ySloAlertsWrapperSlOsIncludedLink" + > + {i18n.translate('xpack.observability.sloAlertsWrapper.sLOsIncludedFlexItemLabel', { + defaultMessage: '{numOfSlos} SLOs included', + values: { numOfSlos: slos.length }, + })} + + + + + {' '} + + + + + + + + + + + + + + + + + + ); } diff --git a/x-pack/plugins/observability/public/ui_actions/edit_slo_alerts_panel.tsx b/x-pack/plugins/observability/public/ui_actions/edit_slo_alerts_panel.tsx index 7368f898c05a0..b920c47caa352 100644 --- a/x-pack/plugins/observability/public/ui_actions/edit_slo_alerts_panel.tsx +++ b/x-pack/plugins/observability/public/ui_actions/edit_slo_alerts_panel.tsx @@ -25,7 +25,7 @@ export function createEditSloAlertsPanelAction( >['getStartServices'] ): UiActionsActionDefinition { return { - id: 'edit-slo-alerts', + id: EDIT_SLO_ALERTS_ACTION, type: EDIT_SLO_ALERTS_ACTION, getIconType(context): string { return 'pencil'; From b7cc03a9304000c32d732f7fb556784208f356df Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 20 Nov 2023 11:13:29 +0100 Subject: [PATCH 42/85] fix CI issues --- .../components/alerts_table/slo/default_columns.tsx | 9 ++++++--- .../embeddable/slo/alerts/slo_alerts_embeddable.tsx | 2 +- .../slo/alerts/slo_alerts_embeddable_factory.ts | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx b/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx index ed00c86b6d3e7..4872070a6c39c 100644 --- a/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx +++ b/x-pack/plugins/observability/public/components/alerts_table/slo/default_columns.tsx @@ -24,9 +24,12 @@ export const columns: Array< > = [ { columnHeaderType: 'not-filtered', - displayAsText: i18n.translate('xpack.observability.alertsTGrid.statusColumnDescription', { - defaultMessage: 'Status', - }), + displayAsText: i18n.translate( + 'xpack.observability.sloAlertsEmbeddable.alertsTGrid.statusColumnDescription', + { + defaultMessage: 'Status', + } + ), id: ALERT_STATUS, initialWidth: 110, }, diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 4b1f18d5b5b57..90205e80e64e4 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -83,7 +83,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< this.node = node; this.setTitle( this.input.title || - i18n.translate('xpack.observability.sloEmbeddable.displayTitle', { + i18n.translate('xpack.observability.sloAlertsEmbeddable.displayTitle', { defaultMessage: 'SLO Alerts', }) ); diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index 5b2727ab71c07..94f6d0fb23770 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -80,7 +80,7 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe public getDescription() { return i18n.translate('xpack.observability.sloAlertsEmbeddable.description', { - defaultMessage: 'Get SLO alerts', + defaultMessage: 'Get an overview of your SLO alerts', }); } From cf20b6c08e489fd1ab2a0dea55690f8e5be5ed27 Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 20 Nov 2023 12:04:20 +0100 Subject: [PATCH 43/85] pass isServerless to the KibanaContextProvider --- .../slo/alerts/components/slo_alerts_table.tsx | 2 +- .../embeddable/slo/alerts/slo_alerts_embeddable.tsx | 10 +++++++++- .../slo/alerts/slo_alerts_embeddable_factory.ts | 3 ++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index 3cf502f4b2a05..163fa5079ea0b 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -12,7 +12,7 @@ import type { SloItem } from '../types'; type SloIdAndInstanceId = [string, string]; const ALERTS_PER_PAGE = 10; -const ALERTS_TABLE_ID = 'xpack.observability.sloEmbeddable.alert.table'; +const ALERTS_TABLE_ID = 'xpack.observability.sloAlertsEmbeddable.alert.table'; interface Props { deps: SloEmbeddableDeps; diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 90205e80e64e4..91a586f965f5b 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -33,6 +33,7 @@ import { SettingsStart } from '@kbn/core-ui-settings-browser'; import { SecurityPluginStart } from '@kbn/security-plugin/public'; import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { ServerlessPluginStart } from '@kbn/serverless/public'; import { SloAlertsWrapper } from './slo_alerts_wrapper'; import type { SloAlertsEmbeddableInput } from './types'; @@ -53,6 +54,7 @@ export interface SloEmbeddableDeps { security: SecurityPluginStart; charts: ChartsPluginStart; uiActions: UiActionsStart; + serverless?: ServerlessPluginStart; } export class SLOAlertsEmbeddable extends AbstractEmbeddable< @@ -94,7 +96,13 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< const deps = this.deps; ReactDOM.render( - + diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index 94f6d0fb23770..f7e633d7d1638 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -53,7 +53,7 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe try { const [ { uiSettings, application, http, i18n: i18nService, notifications, settings }, - { triggersActionsUi, cases, data, security, charts, uiActions }, + { triggersActionsUi, cases, data, security, charts, uiActions, serverless }, ] = await this.getStartServices(); return new SLOAlertsEmbeddable( { @@ -69,6 +69,7 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe security, charts, uiActions, + serverless, }, initialInput, parent From 80dd64f8302369846eb4f866c3d6dc8c27c64f3d Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 20 Nov 2023 12:46:53 +0100 Subject: [PATCH 44/85] remove onBrushEnd --- .../embeddable/slo/alerts/components/slo_alerts_summary.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx index 9c03a4dddb37a..92bdea190635d 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx @@ -85,7 +85,6 @@ export function SloAlertsSummary({ slos, deps, timeRange }: Props) { const chartProps = { theme: charts.theme.useChartsTheme(), baseTheme: charts.theme.useChartsBaseTheme(), - onBrushEnd: () => {}, // TODO }; return ( Date: Mon, 20 Nov 2023 13:19:51 +0100 Subject: [PATCH 45/85] dispatch render complete when both summary and table have loaded --- .../alerts/components/slo_alerts_summary.tsx | 9 +++++- .../alerts/components/slo_alerts_table.tsx | 8 ++++- .../slo/alerts/slo_alerts_embeddable.tsx | 19 +++++++++++- .../slo/alerts/slo_alerts_wrapper.tsx | 30 ++++++++++++++++--- .../alert_summary_widget.tsx | 9 +++++- .../alert_summary_widget_full_size.tsx | 2 ++ .../sections/alert_summary_widget/types.ts | 1 + .../alerts_table/alerts_table_state.tsx | 8 +++++ 8 files changed, 78 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx index 92bdea190635d..6414650cf11c8 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx @@ -21,13 +21,15 @@ interface Props { deps: SloEmbeddableDeps; slos: SloItem[]; timeRange: TimeRange; + onLoaded?: () => void; } -export function SloAlertsSummary({ slos, deps, timeRange }: Props) { +export function SloAlertsSummary({ slos, deps, timeRange, onLoaded }: Props) { const { charts, triggersActionsUi: { getAlertSummaryWidget: AlertSummaryWidget }, } = deps; + const slosWithoutName = slos.map((slo) => ({ id: slo.id, instanceId: slo.instanceId, @@ -93,6 +95,11 @@ export function SloAlertsSummary({ slos, deps, timeRange }: Props) { timeRange={alertSummaryTimeRange} chartProps={chartProps} fullSize + onLoaded={() => { + if (onLoaded) { + onLoaded(); + } + }} /> ); } diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index 163fa5079ea0b..294240b564385 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -18,9 +18,10 @@ interface Props { deps: SloEmbeddableDeps; slos: SloItem[]; timeRange: TimeRange; + onLoaded?: () => void; } -export function SloAlertsTable({ slos, deps, timeRange }: Props) { +export function SloAlertsTable({ slos, deps, timeRange, onLoaded }: Props) { const { triggersActionsUi: { alertsTableConfigurationRegistry, getAlertsStateTable: AlertsStateTable }, } = deps; @@ -69,6 +70,11 @@ export function SloAlertsTable({ slos, deps, timeRange }: Props) { id={ALERTS_TABLE_ID} pageSize={ALERTS_PER_PAGE} showAlertStatusWithFlapping + onLoaded={() => { + if (onLoaded) { + onLoaded(); + } + }} /> ); } diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 91a586f965f5b..620d19a8743f3 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -77,12 +77,23 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< this.subscription.add(this.getInput$().subscribe(() => this.reload())); } + public reportsEmbeddableLoad() { + return true; + } + + public onRenderComplete() { + this.renderComplete.dispatchComplete(); + } + setTitle(title: string) { this.updateInput({ title }); } public render(node: HTMLElement) { + super.render(node); this.node = node; + // required for the export feature to work + this.node.setAttribute('data-shared-item', ''); this.setTitle( this.input.title || i18n.translate('xpack.observability.sloAlertsEmbeddable.displayTitle', { @@ -105,7 +116,13 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< > - + this.onRenderComplete()} + embeddable={this} + deps={deps} + slos={slos} + timeRange={timeRange} + /> diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index 081962cdede25..885a1e372a871 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; @@ -25,14 +25,25 @@ interface Props { slos: SloItem[]; timeRange: TimeRange; embeddable: IEmbeddable; + onRenderComplete?: () => void; } -export function SloAlertsWrapper({ embeddable, slos, deps, timeRange }: Props) { +export function SloAlertsWrapper({ embeddable, slos, deps, timeRange, onRenderComplete }: Props) { const { application: { navigateToUrl }, http: { basePath }, } = deps; + const [isSummaryLoaded, setIsSummaryLoaded] = useState(false); + const [isTableLoaded, setIsTableLoaded] = useState(false); + useEffect(() => { + if (!onRenderComplete) { + return; + } + if (isSummaryLoaded && isTableLoaded) { + onRenderComplete(); + } + }, [isSummaryLoaded, isTableLoaded, onRenderComplete]); const handleGoToAlertsClick = () => { let kuery = ''; slos.map((slo, index) => { @@ -48,6 +59,7 @@ export function SloAlertsWrapper({ embeddable, slos, deps, timeRange }: Props) { },rangeTo:${timeRange.to})` ); }; + return ( <> - + setIsSummaryLoaded(true)} + /> - + setIsTableLoaded(true)} + /> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/alert_summary_widget.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/alert_summary_widget.tsx index b880d93d63179..2031c9a1f3fe2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/alert_summary_widget.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/alert_summary_widget.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { useEffect } from 'react'; import { useLoadAlertSummary } from '../../hooks/use_load_alert_summary'; import { AlertSummaryWidgetProps } from '.'; import { @@ -23,6 +23,7 @@ export const AlertSummaryWidget = ({ onClick = () => {}, timeRange, hideChart, + onLoaded, }: AlertSummaryWidgetProps) => { const { alertSummary: { activeAlertCount, activeAlerts, recoveredAlertCount }, @@ -34,6 +35,12 @@ export const AlertSummaryWidget = ({ timeRange, }); + useEffect(() => { + if (!isLoading && onLoaded) { + onLoaded(); + } + }, [isLoading, onLoaded]); + if (isLoading) return ; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/components/alert_summary_widget_full_size.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/components/alert_summary_widget_full_size.tsx index 4d2945f86ed23..c058b82414882 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/components/alert_summary_widget_full_size.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/components/alert_summary_widget_full_size.tsx @@ -30,6 +30,7 @@ export interface AlertSummaryWidgetFullSizeProps { recoveredAlertCount: number; dateFormat?: string; hideChart?: boolean; + isLoading?: boolean; } export const AlertSummaryWidgetFullSize = ({ @@ -39,6 +40,7 @@ export const AlertSummaryWidgetFullSize = ({ dateFormat, recoveredAlertCount, hideChart, + isLoading, }: AlertSummaryWidgetFullSizeProps) => { const chartTheme = [ theme, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/types.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/types.ts index 7e7e7355e1a2a..019b6018e69b9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/types.ts @@ -38,4 +38,5 @@ export interface AlertSummaryWidgetProps { timeRange: AlertSummaryTimeRange; chartProps: ChartProps; hideChart?: boolean; + onLoaded?: () => void; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx index bc47845fb9d9e..2438f4f540ee1 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx @@ -67,6 +67,7 @@ export type AlertsTableStateProps = { pageSize?: number; browserFields?: BrowserFields; onUpdate?: (args: TableUpdateHandlerArgs) => void; + onLoaded?: () => void; runtimeMappings?: MappingRuntimeFields; showAlertStatusWithFlapping?: boolean; toolbarVisibility?: EuiDataGridToolBarVisibilityOptions; @@ -158,6 +159,7 @@ const AlertsTableStateWithQueryProvider = ({ gridStyle, browserFields: propBrowserFields, onUpdate, + onLoaded, runtimeMappings, showAlertStatusWithFlapping, toolbarVisibility, @@ -263,6 +265,12 @@ const AlertsTableStateWithQueryProvider = ({ skip: false, }); + useEffect(() => { + if (!isLoading && onLoaded) { + onLoaded(); + } + }, [isLoading, onLoaded]); + useEffect(() => { alertsTableConfigurationRegistry.update(configurationId, { ...alertsTableConfiguration, From 72d3be68a6e9ab53afa4d9be1dad98b6ece2e565 Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 20 Nov 2023 21:34:15 +0100 Subject: [PATCH 46/85] check for proper license --- x-pack/plugins/observability/public/plugin.ts | 58 ++++++++++++------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts index 7603e7c581ff9..eddfa6ec90feb 100644 --- a/x-pack/plugins/observability/public/plugin.ts +++ b/x-pack/plugins/observability/public/plugin.ts @@ -34,6 +34,8 @@ import type { ObservabilitySharedPluginSetup, ObservabilitySharedPluginStart, } from '@kbn/observability-shared-plugin/public'; +import type { LicensingPluginSetup } from '@kbn/licensing-plugin/public'; + import { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import { TriggersAndActionsUIPublicPluginSetup, @@ -61,6 +63,7 @@ import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/publi import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import { ServerlessPluginStart } from '@kbn/serverless/public'; import type { UiActionsStart, UiActionsSetup } from '@kbn/ui-actions-plugin/public'; +import { firstValueFrom } from 'rxjs'; import { observabilityAppId, observabilityFeatureId } from '../common'; import { ALERTS_PATH, @@ -117,6 +120,7 @@ export interface ObservabilityPublicPluginsSetup { usageCollection: UsageCollectionSetup; embeddable: EmbeddableSetup; uiActions: UiActionsSetup; + licensing: LicensingPluginSetup; } export interface ObservabilityPublicPluginsStart { @@ -296,31 +300,41 @@ export class Plugin coreSetup.application.register(app); registerObservabilityRuleTypes(config, this.observabilityRuleTypeRegistry); - const registerSloEmbeddableFactory = async () => { - const { SloOverviewEmbeddableFactoryDefinition } = await import( - './embeddable/slo/overview/slo_embeddable_factory' - ); - const factory = new SloOverviewEmbeddableFactoryDefinition(coreSetup.getStartServices); - pluginsSetup.embeddable.registerEmbeddableFactory(factory.type, factory); - }; - registerSloEmbeddableFactory(); - const registerSloAlertsEmbeddableFactory = async () => { - const { SloAlertsEmbeddableFactoryDefinition } = await import( - './embeddable/slo/alerts/slo_alerts_embeddable_factory' - ); - const factory = new SloAlertsEmbeddableFactoryDefinition(coreSetup.getStartServices); - pluginsSetup.embeddable.registerEmbeddableFactory(factory.type, factory); - }; - registerSloAlertsEmbeddableFactory(); - - const registerAsyncSloAlertsUiActions = async () => { - if (pluginsSetup.uiActions) { - const { registerSloAlertsUiActions } = await import('./ui_actions'); - registerSloAlertsUiActions(pluginsSetup.uiActions, coreSetup); + const assertPlatinumLicense = async () => { + const licensing = await pluginsSetup.licensing; + const license = await firstValueFrom(licensing.license$); + + const hasPlatinumLicense = license.hasAtLeast('platinum'); + if (hasPlatinumLicense) { + const registerSloOverviewEmbeddableFactory = async () => { + const { SloOverviewEmbeddableFactoryDefinition } = await import( + './embeddable/slo/overview/slo_embeddable_factory' + ); + const factory = new SloOverviewEmbeddableFactoryDefinition(coreSetup.getStartServices); + pluginsSetup.embeddable.registerEmbeddableFactory(factory.type, factory); + }; + registerSloOverviewEmbeddableFactory(); + const registerSloAlertsEmbeddableFactory = async () => { + const { SloAlertsEmbeddableFactoryDefinition } = await import( + './embeddable/slo/alerts/slo_alerts_embeddable_factory' + ); + const factory = new SloAlertsEmbeddableFactoryDefinition(coreSetup.getStartServices); + pluginsSetup.embeddable.registerEmbeddableFactory(factory.type, factory); + }; + registerSloAlertsEmbeddableFactory(); + + const registerAsyncSloAlertsUiActions = async () => { + if (pluginsSetup.uiActions) { + const { registerSloAlertsUiActions } = await import('./ui_actions'); + registerSloAlertsUiActions(pluginsSetup.uiActions, coreSetup); + } + }; + registerAsyncSloAlertsUiActions(); } }; - registerAsyncSloAlertsUiActions(); + + assertPlatinumLicense(); if (pluginsSetup.home) { pluginsSetup.home.featureCatalogue.registerSolution({ From 931da964538045d855661044a37abfa4f09b2cc3 Mon Sep 17 00:00:00 2001 From: mgiota Date: Tue, 21 Nov 2023 00:00:19 +0100 Subject: [PATCH 47/85] remove compact slo summary component --- .../slo/alerts/slo_summary.test.tsx | 156 ------------------ .../embeddable/slo/alerts/slo_summary.tsx | 82 --------- 2 files changed, 238 deletions(-) delete mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx delete mode 100644 x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx deleted file mode 100644 index d6b42ffb03b41..0000000000000 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.test.tsx +++ /dev/null @@ -1,156 +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 { screen } from '@testing-library/react'; -import React from 'react'; - -import { sloList } from '../../../data/slo/slo'; -import { render } from '../../../utils/test_helper'; -import { SloSummary } from './slo_summary'; -import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; -import { ActiveAlerts } from '../../../hooks/slo/active_alerts'; -import { SloItem } from './types'; -jest.mock('../../../hooks/slo/use_fetch_active_alerts'); -const useFetchActiveAlertsMock = useFetchActiveAlerts as jest.Mock; - -// TODO write a few more scenarios that cover -/** - * a) display title - * b) color of the panel - * c) use group by SLOs and verify number of alerts is correct - */ -describe('SLO Alert Summary', () => { - describe('Multiple selected SLOs', () => { - it('displays 0 alerts when there are no active alerts', async () => { - const { results } = sloList; - const slos = results.map((slo) => ({ - id: slo.id, - instanceId: slo.instanceId, - name: slo.name, - groupBy: slo.groupBy, - })) as SloItem[]; - - useFetchActiveAlertsMock.mockReturnValue({ - isLoading: false, - data: new ActiveAlerts(), - }); - - render(); - expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('0'); - }); - - describe('only 1 selected SLO has active alerts', () => { - it('displays total alerts when there are alerts from one SLO', async () => { - const { results } = sloList; - const slos = results.map((slo) => ({ - id: slo.id, - instanceId: slo.instanceId, - name: slo.name, - groupBy: slo.groupBy, - })) as SloItem[]; - const activeAlertsData = { - '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, - }; - - useFetchActiveAlertsMock.mockReturnValue({ - isLoading: false, - data: new ActiveAlerts(activeAlertsData), - }); - - render(); - expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('1'); - }); - }); - - describe('multiple SLOs have active alerts', () => { - it('displays total alerts when multiple selected SLOs have 1 active alert', async () => { - const { results } = sloList; - const slos = results.map((slo) => ({ - id: slo.id, - instanceId: slo.instanceId, - name: slo.name, - groupBy: slo.groupBy, - })) as SloItem[]; - const activeAlertsData = { - '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, - 'c0f8d669-9177-4706-9098-f397a88173a6|*': 1, - }; - - useFetchActiveAlertsMock.mockReturnValue({ - isLoading: false, - data: new ActiveAlerts(activeAlertsData), - }); - - render(); - expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('2'); - }); - - it('displays total alerts when multiple selected SLOs have multiple active alerts', async () => { - const { results } = sloList; - const slos = results.map((slo) => ({ - id: slo.id, - instanceId: slo.instanceId, - name: slo.name, - groupBy: slo.groupBy, - })) as SloItem[]; - const activeAlertsData = { - '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 3, - 'c0f8d669-9177-4706-9098-f397a88173a6|*': 2, - }; - - useFetchActiveAlertsMock.mockReturnValue({ - isLoading: false, - data: new ActiveAlerts(activeAlertsData), - }); - - render(); - expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('5'); - }); - }); - }); - - describe('One selected SLO', () => { - it('displays 0 alerts when there are no active alerts', async () => { - const { results } = sloList; - const slos = results.map((slo) => ({ - id: slo.id, - instanceId: slo.instanceId, - groupBy: slo.groupBy, - })) as SloItem[]; - const selectedSlo = [slos[0]]; - - useFetchActiveAlertsMock.mockReturnValue({ - isLoading: false, - data: new ActiveAlerts(), - }); - - render(); - expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('0'); - }); - - it('displays total number of alerts when there are active alerts', async () => { - const { results } = sloList; - const slos = results.map((slo) => ({ - id: slo.id, - instanceId: slo.instanceId, - groupBy: slo.groupBy, - })) as SloItem[]; - const selectedSlo = [slos[0]]; - const activeAlertsData = { - '1f1c6ee7-433f-4b56-b727-5682262e0d7d|*': 1, - }; - useFetchActiveAlertsMock.mockReturnValue({ - isLoading: false, - data: new ActiveAlerts(activeAlertsData), - }); - - render(); - - expect(screen.queryByTestId('sloAlertsSummaryStat')).toHaveTextContent('1'); - }); - }); -}); diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx deleted file mode 100644 index 988ce4edcc7ae..0000000000000 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_summary.tsx +++ /dev/null @@ -1,82 +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 React from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiFlexGroup, EuiText, EuiFlexItem, EuiPanel, EuiStat, EuiBadge } from '@elastic/eui'; -import { euiLightVars } from '@kbn/ui-theme'; -import { ALL_VALUE } from '@kbn/slo-schema'; -import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; -import { EmbeddableSloProps } from './types'; -type SloIdAndInstanceId = [string, string]; - -export function SloSummary({ slos }: EmbeddableSloProps) { - const sloBadges = slos.map((slo) => - slo.instanceId !== ALL_VALUE ? `${slo.name} (${slo.instanceId})` : slo.name - ); - const more = sloBadges.length - 1; - const { data: activeAlerts } = useFetchActiveAlerts({ - sloIdsAndInstanceIds: slos - .map((slo) => ({ - id: slo.id, - instanceId: slo.instanceId, - })) - .map(Object.values) as SloIdAndInstanceId[], - }); - const totalActiveAlerts = slos.reduce((total, slo) => { - if (activeAlerts && activeAlerts.get(slo)) { - total += activeAlerts.get(slo)!; - } - return total; - }, 0); - return ( - - - - - -

- {i18n.translate('xpack.observability.sloSummary.h5.activeAlertsLabel', { - defaultMessage: 'Active Alerts', - })} -

-
-
- - - {sloBadges[0]} - - {more > 0 && ( - - {`+${more} more`} - - )} - -
- - - - - - -
-
- ); -} From beeb82fcb82da2cceaf72978993b87133e6bcc75 Mon Sep 17 00:00:00 2001 From: mgiota Date: Tue, 21 Nov 2023 12:23:36 +0100 Subject: [PATCH 48/85] remove unused prop --- .../components/alert_summary_widget_full_size.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/components/alert_summary_widget_full_size.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/components/alert_summary_widget_full_size.tsx index c058b82414882..4d2945f86ed23 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/components/alert_summary_widget_full_size.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/components/alert_summary_widget_full_size.tsx @@ -30,7 +30,6 @@ export interface AlertSummaryWidgetFullSizeProps { recoveredAlertCount: number; dateFormat?: string; hideChart?: boolean; - isLoading?: boolean; } export const AlertSummaryWidgetFullSize = ({ @@ -40,7 +39,6 @@ export const AlertSummaryWidgetFullSize = ({ dateFormat, recoveredAlertCount, hideChart, - isLoading, }: AlertSummaryWidgetFullSizeProps) => { const chartTheme = [ theme, From 0145babae4bfe5e2a7eeaa7ac3b68898939b8e9c Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 28 Nov 2023 20:57:01 +0100 Subject: [PATCH 49/85] fix imports --- x-pack/plugins/observability/public/plugin.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts index e6fe128e43eab..6e86b8e52c0b1 100644 --- a/x-pack/plugins/observability/public/plugin.ts +++ b/x-pack/plugins/observability/public/plugin.ts @@ -64,8 +64,7 @@ import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import { ServerlessPluginStart } from '@kbn/serverless/public'; import type { UiActionsStart, UiActionsSetup } from '@kbn/ui-actions-plugin/public'; import { firstValueFrom } from 'rxjs'; -import type { LicensingPluginSetup } from '@kbn/licensing-plugin/public'; -import { firstValueFrom } from 'rxjs'; + import { observabilityAppId, observabilityFeatureId } from '../common'; import { ALERTS_PATH, From 59d3d557519269b564bb6f1806789d583df964d9 Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Wed, 29 Nov 2023 13:20:04 +0100 Subject: [PATCH 50/85] fix types --- .../public/pages/slos/components/card_view/slos_card_view.tsx | 2 +- .../public/pages/slos/components/slo_list_items.stories.tsx | 2 +- .../public/pages/slos/components/slo_list_items.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slos_card_view.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slos_card_view.tsx index 3768bdbb7dac3..57be10c55aa13 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/card_view/slos_card_view.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slos_card_view.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { EuiFlexGrid, EuiFlexItem, EuiPanel, EuiSkeletonText } from '@elastic/eui'; import { SLOWithSummaryResponse, ALL_VALUE } from '@kbn/slo-schema'; import { EuiFlexGridProps } from '@elastic/eui/src/components/flex/flex_grid'; -import { ActiveAlerts } from '../../../../hooks/slo/use_fetch_active_alerts'; +import { ActiveAlerts } from '../../../../hooks/slo/active_alerts'; import type { UseFetchRulesForSloResponse } from '../../../../hooks/slo/use_fetch_rules_for_slo'; import { useFetchHistoricalSummary } from '../../../../hooks/slo/use_fetch_historical_summary'; import { SloCardItem } from './slo_card_item'; diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_list_items.stories.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_list_items.stories.tsx index 9e92eeb95799f..9d59cf956a202 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/slo_list_items.stories.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/slo_list_items.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { ComponentStory } from '@storybook/react'; -import { ActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; +import { ActiveAlerts } from '../../../hooks/slo/active_alerts'; import { KibanaReactStorybookDecorator } from '../../../utils/kibana_react.storybook_decorator'; import { SloListItems as Component, Props } from './slo_list_items'; import { sloList } from '../../../data/slo/slo'; diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_list_items.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_list_items.tsx index e0ec34d2bac4e..c7d55fb219959 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/slo_list_items.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/slo_list_items.tsx @@ -7,7 +7,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; import React from 'react'; -import { ActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; +import { ActiveAlerts } from '../../../hooks/slo/active_alerts'; import { useFetchHistoricalSummary } from '../../../hooks/slo/use_fetch_historical_summary'; import { UseFetchRulesForSloResponse } from '../../../hooks/slo/use_fetch_rules_for_slo'; import { SloListItem } from './slo_list_item'; From 5d64d4c59e051af1c87f813531774007b98bf58b Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Wed, 29 Nov 2023 14:06:37 +0100 Subject: [PATCH 51/85] use card color util --- .../embeddable/slo/overview/slo_overview.tsx | 26 +++---------------- .../components/card_view/slo_card_item.tsx | 4 +-- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx index 873c37f89eca2..db732e13004b8 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx @@ -7,12 +7,13 @@ import React, { useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiIcon, useEuiBackgroundColor } from '@elastic/eui'; +import { EuiIcon } from '@elastic/eui'; import { Chart, Metric, MetricTrendShape, Settings } from '@elastic/charts'; import numeral from '@elastic/numeral'; import { ALL_VALUE } from '@kbn/slo-schema'; import { EuiLoadingChart } from '@elastic/eui'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import { useSloCardColor } from '../../../pages/slos/components/card_view/slo_card_item'; import { NOT_AVAILABLE_LABEL } from '../../../../common/i18n'; import { useKibana } from '../../../utils/kibana_react'; import { useFetchSloDetails } from '../../../hooks/slo/use_fetch_slo_details'; @@ -65,27 +66,8 @@ export function SloOverview({ const sloSummary = slo?.summary; const sloStatus = sloSummary?.status; - const healthyColor = useEuiBackgroundColor('success'); - const noDataColor = useEuiBackgroundColor('subdued'); - const degradingColor = useEuiBackgroundColor('warning'); - const violatedColor = useEuiBackgroundColor('danger'); - let color; - switch (sloStatus) { - case 'HEALTHY': - color = healthyColor; - break; - case 'NO_DATA': - color = noDataColor; - break; - case 'DEGRADING': - color = degradingColor; - break; - case 'VIOLATED': - color = violatedColor; - break; - default: - color = noDataColor; - } + + const color = useSloCardColor(sloStatus); if (isRefetching || isLoading) { return ( diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx index 07ad3caf1fd00..e90f64d0b992b 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx @@ -40,7 +40,7 @@ export interface Props { cardsPerRow: number; } -const useCardColor = (status?: SLOWithSummaryResponse['summary']['status']) => { +export const useSloCardColor = (status?: SLOWithSummaryResponse['summary']['status']) => { const colors = { DEGRADING: useEuiBackgroundColor('warning'), VIOLATED: useEuiBackgroundColor('danger'), @@ -72,7 +72,7 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cards const { sliValue, sloTarget, sloDetailsUrl } = useSloFormattedSummary(slo); - const cardColor = useCardColor(slo.summary.status); + const cardColor = useSloCardColor(slo.summary.status); const subTitle = getSubTitle(slo, cardsPerRow); From c56a0124fd6eac38fa0abfe92efd02f1981a02bc Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Wed, 29 Nov 2023 15:18:58 +0100 Subject: [PATCH 52/85] use shared component --- .../slo/alerts/slo_alerts_embeddable.tsx | 5 - .../slo/overview/slo_embeddable.tsx | 4 - .../embeddable/slo/overview/slo_overview.tsx | 114 +++++++----------- .../components/card_view/slo_card_item.tsx | 110 +++++++++-------- .../card_view/slo_card_item_badges.tsx | 11 +- 5 files changed, 110 insertions(+), 134 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 620d19a8743f3..208c5b5374283 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -76,11 +76,6 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< this.subscription = new Subscription(); this.subscription.add(this.getInput$().subscribe(() => this.reload())); } - - public reportsEmbeddableLoad() { - return true; - } - public onRenderComplete() { this.renderComplete.dispatchComplete(); } diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx index ec5709ce45f98..e1421884c3ad2 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx @@ -50,10 +50,6 @@ export class SLOEmbeddable extends AbstractEmbeddable { refetch(); }, [lastReloadRequestTime, refetch]); @@ -53,23 +59,9 @@ export function SloOverview({ } }, [isLoading, onRenderComplete]); - const percentFormat = uiSettings.get('format:percent:defaultPattern'); const isSloNotFound = !isLoading && slo === undefined; - const getIcon = useCallback( - (type: string) => - ({ width = 20, height = 20, color }: { width: number; height: number; color: string }) => { - return ; - }, - [] - ); - - const sloSummary = slo?.summary; - const sloStatus = sloSummary?.status; - - const color = useSloCardColor(sloStatus); - - if (isRefetching || isLoading) { + if (isRefetching || isLoading || !slo) { return ( @@ -92,51 +84,29 @@ export function SloOverview({ ); } - const TargetCopy = i18n.translate('xpack.observability.sloEmbeddable.overview.sloTargetLabel', { - defaultMessage: 'Target', - }); - const extraContent = `${TargetCopy} ${numeral(slo?.objective.target).format( - percentFormat - )}`; - // eslint-disable-next-line react/no-danger - const extra = ; - const metricData = - slo !== undefined - ? [ - { - color, - title: slo.name, - subtitle: slo.groupBy !== ALL_VALUE ? `${slo.groupBy}:${slo.instanceId}` : '', - icon: getIcon('visGauge'), - value: - sloStatus === 'NO_DATA' - ? NOT_AVAILABLE_LABEL - : numeral(slo.summary.sliValue).format(percentFormat), - valueFormatter: (value: number) => `${value}%`, - extra, - trend: [], - trendShape: MetricTrendShape.Area, - }, - ] - : []; + const rules = rulesBySlo?.[slo?.id]; + const activeAlerts = activeAlertsBySlo.get(slo); + + const hasGroupBy = Boolean(slo.groupBy && slo.groupBy !== ALL_VALUE); + + const historicalSummary = historicalSummaries.find( + (histSummary) => + histSummary.sloId === slo.id && histSummary.instanceId === (slo.instanceId ?? ALL_VALUE) + )?.data; + + const historicalSliData = formatHistoricalData(historicalSummary, 'sli_value'); + return ( <> - - { - navigateToUrl( - basePath.prepend( - paths.observability.sloDetails( - slo!.id, - slo?.groupBy !== ALL_VALUE && slo?.instanceId ? slo.instanceId : undefined - ) - ) - ); - }} - locale={i18n.getLocale()} - /> - - + + {}} + hasGroupBy={hasGroupBy} + isEmbeddable={true} + /> ); } diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx index e90f64d0b992b..bd55840f0d83b 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx @@ -61,21 +61,11 @@ const getSubTitle = (slo: SLOWithSummaryResponse, cardsPerRow: number) => { }; export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cardsPerRow }: Props) { - const { - application: { navigateToUrl }, - } = useKibana().services; - const [isMouseOver, setIsMouseOver] = useState(false); const [isActionsPopoverOpen, setIsActionsPopoverOpen] = useState(false); const [isAddRuleFlyoutOpen, setIsAddRuleFlyoutOpen] = useState(false); const [isDeleteConfirmationModalOpen, setDeleteConfirmationModalOpen] = useState(false); - const { sliValue, sloTarget, sloDetailsUrl } = useSloFormattedSummary(slo); - - const cardColor = useSloCardColor(slo.summary.status); - - const subTitle = getSubTitle(slo, cardsPerRow); - const historicalSliData = formatHistoricalData(historicalSummary, 'sli_value'); const { handleCreateRule, handleDeleteCancel, handleDeleteConfirm } = useSloListActions({ @@ -106,45 +96,7 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cards }} title={slo.summary.status} > - - { - if (isMetricElementEvent(d)) { - navigateToUrl(sloDetailsUrl); - } - }} - locale={i18n.getLocale()} - /> - ({ - x: d.key as number, - y: d.value as number, - })), - extra: ( - - ), - icon: () => , - color: cardColor, - }, - ], - ]} - /> - + ); } + +export function SloCardChart({ + slo, + cardsPerRow, + historicalSliData, +}: { + slo: SLOWithSummaryResponse; + cardsPerRow: number; + historicalSliData?: Array<{ key?: number; value?: number }>; +}) { + const { + application: { navigateToUrl }, + } = useKibana().services; + + const cardColor = useSloCardColor(slo.summary.status); + const subTitle = getSubTitle(slo, cardsPerRow); + const { sliValue, sloTarget, sloDetailsUrl } = useSloFormattedSummary(slo); + + return ( + + { + if (isMetricElementEvent(d)) { + navigateToUrl(sloDetailsUrl); + } + }} + locale={i18n.getLocale()} + /> + ({ + x: d.key as number, + y: d.value as number, + })), + extra: ( + + ), + icon: () => , + color: cardColor, + }, + ], + ]} + /> + + ); +} diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_badges.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_badges.tsx index 06bc6cf19e0c9..82115f3930a0d 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_badges.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_badges.tsx @@ -18,6 +18,7 @@ import { SloRulesBadge } from '../badges/slo_rules_badge'; import { SloRule } from '../../../../hooks/slo/use_fetch_rules_for_slo'; interface Props { + isEmbeddable?: boolean; hasGroupBy: boolean; activeAlerts?: number; slo: SLOWithSummaryResponse; @@ -25,13 +26,12 @@ interface Props { handleCreateRule: () => void; } -const Container = styled.div<{ hasGroupBy: boolean }>` +const Container = styled.div<{ topPosition: string }>` position: absolute; display: inline-block; - top: ${({ hasGroupBy }) => (hasGroupBy ? '55px' : '35px')}; + top: ${({ topPosition }) => topPosition}; left: 7px; z-index: 1; - border-radius: ${({ theme }) => theme.eui.euiBorderRadius}; `; export function SloCardItemBadges({ @@ -40,9 +40,12 @@ export function SloCardItemBadges({ rules, handleCreateRule, hasGroupBy, + isEmbeddable, }: Props) { + const topPosition = + hasGroupBy && isEmbeddable ? '75px' : hasGroupBy || isEmbeddable ? '55px' : '35px'; return ( - + {!slo.summary ? ( From 62d1de96927dac7c22832c39918fcaa83b06c049 Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Wed, 29 Nov 2023 15:39:15 +0100 Subject: [PATCH 53/85] loading while loading --- .../public/embeddable/slo/alerts/slo_configuration.tsx | 2 +- .../public/embeddable/slo/alerts/slo_selector.tsx | 10 +--------- .../public/embeddable/slo/overview/slo_selector.tsx | 10 +--------- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx index b8655f3163aea..dc13155cef091 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx @@ -78,7 +78,7 @@ export function SloConfiguration({ initialInput, onCreate, onCancel }: SloConfig diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx index ddc47b91a5ca3..bd72bbc6402e0 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx @@ -35,11 +35,7 @@ export function SloSelector({ initialSlos, onSelected, hasError }: Props) { mapSlosToOptions(initialSlos) ); const [searchValue, setSearchValue] = useState(''); - const { - isInitialLoading, - isLoading, - data: sloList, - } = useFetchSloList({ + const { isLoading, data: sloList } = useFetchSloList({ kqlQuery: `slo.name: ${searchValue.replaceAll(' ', '*')}*`, }); @@ -70,10 +66,6 @@ export function SloSelector({ initialSlos, onSelected, hasError }: Props) { [] ); - if (isInitialLoading) { - return null; - } - return ( >>([]); const [selectedOptions, setSelectedOptions] = useState>>(); const [searchValue, setSearchValue] = useState(''); - const { - isInitialLoading, - isLoading, - data: sloList, - } = useFetchSloList({ + const { isLoading, data: sloList } = useFetchSloList({ kqlQuery: `slo.name: ${searchValue.replaceAll(' ', '*')}*`, }); @@ -70,10 +66,6 @@ export function SloSelector({ initialSlo, onSelected, hasError }: Props) { [] ); - if (isInitialLoading) { - return null; - } - return ( Date: Wed, 29 Nov 2023 15:41:45 +0100 Subject: [PATCH 54/85] fix i18n --- x-pack/plugins/translations/translations/fr-FR.json | 1 - x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 3 files changed, 3 deletions(-) diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index cb92fe0fe194d..0e9a45eb27c11 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -29655,7 +29655,6 @@ "xpack.observability.sloEmbeddable.displayName": "Aperçu du SLO", "xpack.observability.sloEmbeddable.displayTitle": "Aperçu du SLO", "xpack.observability.sloEmbeddable.overview.sloNotFoundText": "Le SLO a été supprimé. Vous pouvez supprimer sans risque le widget du tableau de bord.", - "xpack.observability.sloEmbeddable.overview.sloTargetLabel": "Cible", "xpack.observability.slos.sloDetails.headerControl.exploreInApm": "Détails du service", "xpack.observability.slosLinkTitle": "SLO", "xpack.observability.slosPage.autoRefreshButtonLabel": "Actualisation automatique", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 6c0effafd281c..547aafe71380b 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -29654,7 +29654,6 @@ "xpack.observability.sloEmbeddable.displayName": "SLO概要", "xpack.observability.sloEmbeddable.displayTitle": "SLO概要", "xpack.observability.sloEmbeddable.overview.sloNotFoundText": "SLOが削除されました。ウィジェットをダッシュボードから安全に削除できます。", - "xpack.observability.sloEmbeddable.overview.sloTargetLabel": "目標", "xpack.observability.slos.sloDetails.headerControl.exploreInApm": "サービス詳細", "xpack.observability.slosLinkTitle": "SLO", "xpack.observability.slosPage.autoRefreshButtonLabel": "自動更新", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b58c600756803..bbf4e44d48573 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -29652,7 +29652,6 @@ "xpack.observability.sloEmbeddable.displayName": "SLO 概览", "xpack.observability.sloEmbeddable.displayTitle": "SLO 概览", "xpack.observability.sloEmbeddable.overview.sloNotFoundText": "SLO 已删除。您可以放心从仪表板中删除小组件。", - "xpack.observability.sloEmbeddable.overview.sloTargetLabel": "目标", "xpack.observability.slos.sloDetails.headerControl.exploreInApm": "服务详情", "xpack.observability.slosLinkTitle": "SLO", "xpack.observability.slosPage.autoRefreshButtonLabel": "自动刷新", From f9158d0a5427cbec0a49f3441988d00fab54cffe Mon Sep 17 00:00:00 2001 From: mgiota Date: Fri, 1 Dec 2023 00:13:19 +0100 Subject: [PATCH 55/85] change initial dimensions of SLO overview embeddable --- .../public/embeddable/slo/overview/slo_embeddable_factory.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts index 1163a558d5851..50b42f7e13910 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts @@ -56,9 +56,7 @@ export class SloOverviewEmbeddableFactoryDefinition SloEmbeddableInput, unknown >['getPanelPlacementSettings'] = () => { - const width = 8; - const height = 7; - return { width, height, strategy: 'placeAtTop' }; + return { width: 12, height: 8 }; }; public async create(initialInput: SloEmbeddableInput, parent?: IContainer) { From 62d4242d0c1dff3e5bf534339131900879a861c7 Mon Sep 17 00:00:00 2001 From: mgiota Date: Fri, 1 Dec 2023 00:45:38 +0100 Subject: [PATCH 56/85] pass kibanaVersion --- .../public/embeddable/slo/alerts/slo_alerts_embeddable.tsx | 6 +++++- .../embeddable/slo/alerts/slo_alerts_embeddable_factory.ts | 5 ++++- x-pack/plugins/observability/public/plugin.ts | 5 ++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 208c5b5374283..0051fb96bf2b7 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -64,15 +64,17 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< public readonly type = SLO_ALERTS_EMBEDDABLE; private subscription: Subscription; private node?: HTMLElement; + kibanaVersion: string; constructor( private readonly deps: SloEmbeddableDeps, initialInput: SloAlertsEmbeddableInput, + kibanaVersion: string, parent?: IContainer ) { super(initialInput, {}, parent); this.deps = deps; - + this.kibanaVersion = kibanaVersion; this.subscription = new Subscription(); this.subscription.add(this.getInput$().subscribe(() => this.reload())); } @@ -100,6 +102,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< const I18nContext = this.deps.i18n.Context; const { slos, timeRange = { from: 'now-15m/m', to: 'now' } } = this.getInput(); const deps = this.deps; + const kibanaVersion = this.kibanaVersion; ReactDOM.render( diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index f7e633d7d1638..8b80ea19f8f02 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -32,7 +32,8 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe private getStartServices: CoreSetup< ObservabilityPublicPluginsStart, ObservabilityPublicStart - >['getStartServices'] + >['getStartServices'], + private kibanaVersion: string ) {} public async isEditable() { @@ -55,6 +56,7 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe { uiSettings, application, http, i18n: i18nService, notifications, settings }, { triggersActionsUi, cases, data, security, charts, uiActions, serverless }, ] = await this.getStartServices(); + const kibanaVersion = this.kibanaVersion; return new SLOAlertsEmbeddable( { uiSettings, @@ -72,6 +74,7 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe serverless, }, initialInput, + kibanaVersion, parent ); } catch (e) { diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts index 6e86b8e52c0b1..fa44c18e97b29 100644 --- a/x-pack/plugins/observability/public/plugin.ts +++ b/x-pack/plugins/observability/public/plugin.ts @@ -319,7 +319,10 @@ export class Plugin const { SloAlertsEmbeddableFactoryDefinition } = await import( './embeddable/slo/alerts/slo_alerts_embeddable_factory' ); - const factory = new SloAlertsEmbeddableFactoryDefinition(coreSetup.getStartServices); + const factory = new SloAlertsEmbeddableFactoryDefinition( + coreSetup.getStartServices, + kibanaVersion + ); pluginsSetup.embeddable.registerEmbeddableFactory(factory.type, factory); }; registerSloAlertsEmbeddableFactory(); From 42061170be2ae9e91b4272b0b121752102bce7a4 Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Fri, 1 Dec 2023 17:29:36 +0100 Subject: [PATCH 57/85] handle embeddable state --- .../embeddable/slo/overview/slo_overview.tsx | 24 +++++++++++-------- .../components/card_view/slo_card_item.tsx | 17 ++++++------- .../card_view/slo_card_item_badges.tsx | 1 - 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx index f6dbc81bdfb94..4746f9af869f1 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import { EuiLoadingChart } from '@elastic/eui'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { ALL_VALUE } from '@kbn/slo-schema'; +import { SloCardBadgesPortal } from '../../../pages/slos/components/card_view/badges_portal'; import { formatHistoricalData } from '../../../utils/slo/chart_data_formatter'; import { useFetchHistoricalSummary } from '../../../hooks/slo/use_fetch_historical_summary'; import { useFetchActiveAlerts } from '../../../hooks/slo/use_fetch_active_alerts'; @@ -26,6 +27,8 @@ export function SloOverview({ lastReloadRequestTime, onRenderComplete, }: EmbeddableSloProps) { + const containerRef = React.useRef(null); + const { isLoading, data: slo, @@ -97,17 +100,18 @@ export function SloOverview({ const historicalSliData = formatHistoricalData(historicalSummary, 'sli_value'); return ( - <> +
- {}} - hasGroupBy={hasGroupBy} - isEmbeddable={true} - /> - + + {}} + hasGroupBy={hasGroupBy} + /> + +
); } diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx index 0f4acb06774e3..b3ce1f2c5b0fd 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx @@ -100,14 +100,6 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cards title={slo.summary.status} > - - {(isMouseOver || isActionsPopoverOpen) && ( )}
+ + + Date: Fri, 1 Dec 2023 22:00:31 +0100 Subject: [PATCH 58/85] fix types --- .../public/pages/slos/components/card_view/slo_card_item.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx index b3ce1f2c5b0fd..8da351e5ba0e3 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx @@ -57,10 +57,6 @@ const getSubTitle = (slo: SLOWithSummaryResponse, cardsPerRow: number) => { }; export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cardsPerRow }: Props) { - const { - application: { navigateToUrl }, - } = useKibana().services; - const containerRef = React.useRef(null); const [isMouseOver, setIsMouseOver] = useState(false); From daa44d196ca0ff96fcfd313575275ca929d7dcb0 Mon Sep 17 00:00:00 2001 From: mgiota Date: Sun, 3 Dec 2023 22:22:02 +0100 Subject: [PATCH 59/85] remove instanceId * from alerts query to fix empty results --- .../alerts/components/slo_alerts_table.tsx | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index 294240b564385..252f7dcc1eddb 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -7,10 +7,14 @@ import React from 'react'; import { AlertConsumers } from '@kbn/rule-data-utils'; import type { TimeRange } from '@kbn/es-query'; +import { ALL_VALUE } from '@kbn/slo-schema'; import { SloEmbeddableDeps } from '../slo_alerts_embeddable'; import type { SloItem } from '../types'; type SloIdAndInstanceId = [string, string]; +interface FilterQuery { + [key: string]: any; +} const ALERTS_PER_PAGE = 10; const ALERTS_TABLE_ID = 'xpack.observability.sloAlertsEmbeddable.alert.table'; @@ -50,14 +54,17 @@ export function SloAlertsTable({ slos, deps, timeRange, onLoaded }: Props) { }, { bool: { - should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ - bool: { - filter: [ - { term: { 'slo.id': sloId } }, - { term: { 'slo.instanceId': instanceId } }, - ], - }, - })), + should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => { + const filterQuery = [{ term: { 'slo.id': sloId } } as FilterQuery]; + if (instanceId !== ALL_VALUE) { + filterQuery.push({ term: { 'slo.instanceId': instanceId } }); + } + return { + bool: { + filter: filterQuery, + }, + }; + }), }, }, ], From a1acde74c936725f66d3a14c6041495bc20c1390 Mon Sep 17 00:00:00 2001 From: mgiota Date: Sun, 3 Dec 2023 22:57:58 +0100 Subject: [PATCH 60/85] pass all startServices as deps to alerts embeddable --- .../alerts/slo_alerts_embeddable_factory.ts | 27 +++---------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index 8b80ea19f8f02..5674b7d2c35fb 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -52,31 +52,10 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe public async create(initialInput: SloAlertsEmbeddableInput, parent?: IContainer) { try { - const [ - { uiSettings, application, http, i18n: i18nService, notifications, settings }, - { triggersActionsUi, cases, data, security, charts, uiActions, serverless }, - ] = await this.getStartServices(); + const [coreStart, pluginsStart] = await this.getStartServices(); + const deps = { ...coreStart, ...pluginsStart }; const kibanaVersion = this.kibanaVersion; - return new SLOAlertsEmbeddable( - { - uiSettings, - application, - http, - i18n: i18nService, - triggersActionsUi, - notifications, - cases, - data, - settings, - security, - charts, - uiActions, - serverless, - }, - initialInput, - kibanaVersion, - parent - ); + return new SLOAlertsEmbeddable(deps, initialInput, kibanaVersion, parent); } catch (e) { return new ErrorEmbeddable(e, initialInput, parent); } From aef25b5649028d5bad4c4943379cfd4893955265 Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 4 Dec 2023 13:08:17 +0100 Subject: [PATCH 61/85] call onLoaded in the use fetch alerts hook --- .../sections/alerts_table/alerts_table_state.tsx | 7 +------ .../sections/alerts_table/hooks/use_fetch_alerts.tsx | 8 ++++++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx index 2438f4f540ee1..94e9c7f588918 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx @@ -260,17 +260,12 @@ const AlertsTableStateWithQueryProvider = ({ query, pagination, onPageChange, + onLoaded, runtimeMappings, sort, skip: false, }); - useEffect(() => { - if (!isLoading && onLoaded) { - onLoaded(); - } - }, [isLoading, onLoaded]); - useEffect(() => { alertsTableConfigurationRegistry.update(configurationId, { ...alertsTableConfiguration, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_fetch_alerts.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_fetch_alerts.tsx index d4de3eb4b8c84..9b62174661e62 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_fetch_alerts.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_fetch_alerts.tsx @@ -36,6 +36,7 @@ export interface FetchAlertsArgs { pageIndex: number; pageSize: number; }; + onLoaded?: () => void; onPageChange: (pagination: RuleRegistrySearchRequestPagination) => void; runtimeMappings?: MappingRuntimeFields; sort: SortCombinations[]; @@ -147,6 +148,7 @@ export type UseFetchAlerts = ({ fields, query, pagination, + onLoaded, onPageChange, runtimeMappings, skip, @@ -157,6 +159,7 @@ const useFetchAlerts = ({ fields, query, pagination, + onLoaded, onPageChange, runtimeMappings, skip, @@ -259,12 +262,13 @@ const useFetchAlerts = ({ totalAlerts, }); dispatch({ type: 'loading', loading: false }); - + onLoaded?.(); searchSubscription$.current.unsubscribe(); } }, error: (msg) => { dispatch({ type: 'loading', loading: false }); + onLoaded?.(); data.search.showError(msg); searchSubscription$.current.unsubscribe(); }, @@ -277,7 +281,7 @@ const useFetchAlerts = ({ asyncSearch(); refetch.current = asyncSearch; }, - [skip, data, featureIds, query, fields] + [skip, data, featureIds, query, fields, onLoaded] ); // FUTURE ENGINEER From 01c11abe3c1a410d91d67f193e99e9db3e3899d5 Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 4 Dec 2023 21:03:35 +0100 Subject: [PATCH 62/85] change alerts table configuration id --- .../alerts_table/slo/get_slo_alerts_table_configuration.tsx | 4 ++-- .../embeddable/slo/alerts/components/slo_alerts_table.tsx | 3 ++- .../plugins/observability/public/embeddable/slo/constants.ts | 3 +++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx b/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx index 28ace3961c02c..d43c12c4627ed 100644 --- a/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx +++ b/x-pack/plugins/observability/public/components/alerts_table/slo/get_slo_alerts_table_configuration.tsx @@ -9,7 +9,6 @@ import type { GetRenderCellValue } from '@kbn/triggers-actions-ui-plugin/public' import { TIMESTAMP } from '@kbn/rule-data-utils'; import { SortOrder } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { AlertsTableConfigurationRegistry } from '@kbn/triggers-actions-ui-plugin/public/types'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { casesFeatureId, observabilityFeatureId } from '../../../../common'; import { getRenderCellValue } from './render_cell_value'; import { columns } from './default_columns'; @@ -17,12 +16,13 @@ import { useGetAlertFlyoutComponents } from '../../alerts_flyout/use_get_alert_f import type { ObservabilityRuleTypeRegistry } from '../../../rules/create_observability_rule_type_registry'; import type { ConfigSchema } from '../../../plugin'; import type { TopAlert } from '../../../typings/alerts'; +import { SLO_ALERTS_TABLE_CONFID } from '../../../embeddable/slo/constants'; export const getSloAlertsTableConfiguration = ( observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry, config: ConfigSchema ): AlertsTableConfigurationRegistry => ({ - id: AlertConsumers.SLO, + id: SLO_ALERTS_TABLE_CONFID, cases: { featureId: casesFeatureId, owner: [observabilityFeatureId] }, columns, getRenderCellValue: (({ setFlyoutAlert }: { setFlyoutAlert: (data: TopAlert) => void }) => { diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index 252f7dcc1eddb..0cc0187c6eef6 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -10,6 +10,7 @@ import type { TimeRange } from '@kbn/es-query'; import { ALL_VALUE } from '@kbn/slo-schema'; import { SloEmbeddableDeps } from '../slo_alerts_embeddable'; import type { SloItem } from '../types'; +import { SLO_ALERTS_TABLE_CONFID } from '../../constants'; type SloIdAndInstanceId = [string, string]; interface FilterQuery { @@ -71,7 +72,7 @@ export function SloAlertsTable({ slos, deps, timeRange, onLoaded }: Props) { }, }} alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} - configurationId={AlertConsumers.SLO} + configurationId={SLO_ALERTS_TABLE_CONFID} featureIds={[AlertConsumers.SLO, AlertConsumers.OBSERVABILITY]} hideLazyLoader id={ALERTS_TABLE_ID} diff --git a/x-pack/plugins/observability/public/embeddable/slo/constants.ts b/x-pack/plugins/observability/public/embeddable/slo/constants.ts index 31298a375caaa..00f4b9858988f 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/constants.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/constants.ts @@ -4,4 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { AlertConsumers } from '@kbn/rule-data-utils'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; + +export const SLO_ALERTS_TABLE_CONFID = `${AlertConsumers.SLO}-embeddable-alerts-table`; From a8b6a1a02ec3b277390ea3b9bda7a7637c3bc14f Mon Sep 17 00:00:00 2001 From: mgiota Date: Mon, 4 Dec 2023 21:21:27 +0100 Subject: [PATCH 63/85] wrap kuery in parenthesis --- .../public/embeddable/slo/alerts/slo_alerts_wrapper.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index 885a1e372a871..1c02050b7c5d8 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -48,7 +48,7 @@ export function SloAlertsWrapper({ embeddable, slos, deps, timeRange, onRenderCo let kuery = ''; slos.map((slo, index) => { const shouldAddOr = index < slos.length - 1; - kuery += `slo.id:"${slo.id}" and slo.instanceId:"${slo.instanceId}"`; + kuery += `(slo.id:"${slo.id}" and slo.instanceId:"${slo.instanceId}")`; if (shouldAddOr) { kuery += ' or '; } From a1a4e26c454d280a6c610bf5e834c44115113918 Mon Sep 17 00:00:00 2001 From: mgiota Date: Tue, 5 Dec 2023 09:19:51 +0100 Subject: [PATCH 64/85] refresh alerts table on refresh button --- .../slo/alerts/components/slo_alerts_table.tsx | 4 +++- .../embeddable/slo/alerts/slo_alerts_embeddable.tsx | 2 ++ .../embeddable/slo/alerts/slo_alerts_wrapper.tsx | 11 ++++++++++- .../sections/alerts_table/alerts_table_state.tsx | 8 +++++++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index 0cc0187c6eef6..6d452f7c1ce7e 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -24,9 +24,10 @@ interface Props { slos: SloItem[]; timeRange: TimeRange; onLoaded?: () => void; + lastReloadRequestTime: number | undefined; } -export function SloAlertsTable({ slos, deps, timeRange, onLoaded }: Props) { +export function SloAlertsTable({ slos, deps, timeRange, onLoaded, lastReloadRequestTime }: Props) { const { triggersActionsUi: { alertsTableConfigurationRegistry, getAlertsStateTable: AlertsStateTable }, } = deps; @@ -83,6 +84,7 @@ export function SloAlertsTable({ slos, deps, timeRange, onLoaded }: Props) { onLoaded(); } }} + lastReloadRequestTime={lastReloadRequestTime} /> ); } diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 0051fb96bf2b7..9dc80a16cabd6 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -101,6 +101,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< const I18nContext = this.deps.i18n.Context; const { slos, timeRange = { from: 'now-15m/m', to: 'now' } } = this.getInput(); + this.input.lastReloadRequestTime = Date.now(); const deps = this.deps; const kibanaVersion = this.kibanaVersion; ReactDOM.render( @@ -121,6 +122,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< deps={deps} slos={slos} timeRange={timeRange} + lastReloadRequestTime={this.input.lastReloadRequestTime} /> diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index 1c02050b7c5d8..ba638dc969061 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -26,9 +26,17 @@ interface Props { timeRange: TimeRange; embeddable: IEmbeddable; onRenderComplete?: () => void; + lastReloadRequestTime?: number | undefined; } -export function SloAlertsWrapper({ embeddable, slos, deps, timeRange, onRenderComplete }: Props) { +export function SloAlertsWrapper({ + embeddable, + slos, + deps, + timeRange, + onRenderComplete, + lastReloadRequestTime, +}: Props) { const { application: { navigateToUrl }, http: { basePath }, @@ -117,6 +125,7 @@ export function SloAlertsWrapper({ embeddable, slos, deps, timeRange, onRenderCo deps={deps} timeRange={timeRange} onLoaded={() => setIsTableLoaded(true)} + lastReloadRequestTime={lastReloadRequestTime} />
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx index 94e9c7f588918..5fff062610a74 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx @@ -79,6 +79,7 @@ export type AlertsTableStateProps = { * Enable when rows may have variable heights (disables virtualization) */ dynamicRowHeight?: boolean; + lastReloadRequestTime?: number; } & Partial; export interface AlertsTableStorage { @@ -165,9 +166,9 @@ const AlertsTableStateWithQueryProvider = ({ toolbarVisibility, shouldHighlightRow, dynamicRowHeight, + lastReloadRequestTime, }: AlertsTableStateProps) => { const { cases: casesService } = useKibana<{ cases?: CasesService }>().services; - const hasAlertsTableConfiguration = alertsTableConfigurationRegistry?.has(configurationId) ?? false; @@ -279,6 +280,11 @@ const AlertsTableStateWithQueryProvider = ({ onUpdate({ isLoading, totalCount: alertsCount, refresh }); } }, [isLoading, alertsCount, onUpdate, refresh]); + useEffect(() => { + if (lastReloadRequestTime) { + refresh(); + } + }, [lastReloadRequestTime, refresh]); const caseIds = useMemo(() => getCaseIdsFromAlerts(alerts), [alerts]); const maintenanceWindowIds = useMemo(() => getMaintenanceWindowIdsFromAlerts(alerts), [alerts]); From 2c6a4af6fe3e2e6733d67f9df568794e7f82ebee Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 09:53:55 +0100 Subject: [PATCH 65/85] update --- .../embeddable/slo/alerts/slo_alerts_embeddable.tsx | 3 ++- .../slo/alerts/slo_alerts_embeddable_factory.ts | 9 ++++----- .../public/embeddable/slo/overview/slo_embeddable.tsx | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 9dc80a16cabd6..fc6d0018fff60 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -101,7 +101,6 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< const I18nContext = this.deps.i18n.Context; const { slos, timeRange = { from: 'now-15m/m', to: 'now' } } = this.getInput(); - this.input.lastReloadRequestTime = Date.now(); const deps = this.deps; const kibanaVersion = this.kibanaVersion; ReactDOM.render( @@ -133,6 +132,8 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< } public reload() { + this.input.lastReloadRequestTime = Date.now(); + if (this.node) { this.render(this.node); } diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index 5674b7d2c35fb..fe9ddcbf1a062 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -8,12 +8,12 @@ import { i18n } from '@kbn/i18n'; import type { CoreSetup } from '@kbn/core/public'; import { - IContainer, - EmbeddableFactoryDefinition, EmbeddableFactory, + EmbeddableFactoryDefinition, ErrorEmbeddable, + IContainer, } from '@kbn/embeddable-plugin/public'; -import { SLOAlertsEmbeddable, SLO_ALERTS_EMBEDDABLE } from './slo_alerts_embeddable'; +import { SLO_ALERTS_EMBEDDABLE, SLOAlertsEmbeddable } from './slo_alerts_embeddable'; import { ObservabilityPublicPluginsStart, ObservabilityPublicStart } from '../../..'; import { SloAlertsEmbeddableInput } from './types'; @@ -54,8 +54,7 @@ export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDe try { const [coreStart, pluginsStart] = await this.getStartServices(); const deps = { ...coreStart, ...pluginsStart }; - const kibanaVersion = this.kibanaVersion; - return new SLOAlertsEmbeddable(deps, initialInput, kibanaVersion, parent); + return new SLOAlertsEmbeddable(deps, initialInput, this.kibanaVersion, parent); } catch (e) { return new ErrorEmbeddable(e, initialInput, parent); } diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx index e1421884c3ad2..9a90efb19bc87 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx @@ -65,7 +65,6 @@ export class SLOEmbeddable extends AbstractEmbeddable Date: Tue, 5 Dec 2023 10:59:17 +0100 Subject: [PATCH 66/85] fix it --- .../slo/alerts/slo_alerts_embeddable.tsx | 33 +++++++++---------- .../slo/alerts/slo_alerts_wrapper.tsx | 15 +++++++-- .../slo/overview/slo_embeddable.tsx | 28 +++++++--------- .../embeddable/slo/overview/slo_overview.tsx | 16 ++++++--- .../public/embeddable/slo/overview/types.ts | 3 +- 5 files changed, 53 insertions(+), 42 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index fc6d0018fff60..849abd470b27d 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; import ReactDOM from 'react-dom'; -import { Subscription } from 'rxjs'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; @@ -35,6 +34,7 @@ import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { ServerlessPluginStart } from '@kbn/serverless/public'; +import { Subject } from 'rxjs'; import { SloAlertsWrapper } from './slo_alerts_wrapper'; import type { SloAlertsEmbeddableInput } from './types'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; @@ -62,7 +62,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< EmbeddableOutput > { public readonly type = SLO_ALERTS_EMBEDDABLE; - private subscription: Subscription; + private reloadSubject: Subject; private node?: HTMLElement; kibanaVersion: string; @@ -75,8 +75,14 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< super(initialInput, {}, parent); this.deps = deps; this.kibanaVersion = kibanaVersion; - this.subscription = new Subscription(); - this.subscription.add(this.getInput$().subscribe(() => this.reload())); + this.reloadSubject = new Subject(); + + this.setTitle( + this.input.title || + i18n.translate('xpack.observability.sloAlertsEmbeddable.displayTitle', { + defaultMessage: 'SLO Alerts', + }) + ); } public onRenderComplete() { this.renderComplete.dispatchComplete(); @@ -91,16 +97,12 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< this.node = node; // required for the export feature to work this.node.setAttribute('data-shared-item', ''); - this.setTitle( - this.input.title || - i18n.translate('xpack.observability.sloAlertsEmbeddable.displayTitle', { - defaultMessage: 'SLO Alerts', - }) - ); + const queryClient = new QueryClient(); const I18nContext = this.deps.i18n.Context; const { slos, timeRange = { from: 'now-15m/m', to: 'now' } } = this.getInput(); + const deps = this.deps; const kibanaVersion = this.kibanaVersion; ReactDOM.render( @@ -121,7 +123,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< deps={deps} slos={slos} timeRange={timeRange} - lastReloadRequestTime={this.input.lastReloadRequestTime} + reloadSubject={this.reloadSubject} /> @@ -132,16 +134,13 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< } public reload() { - this.input.lastReloadRequestTime = Date.now(); - - if (this.node) { - this.render(this.node); - } + // this.input.lastReloadRequestTime = Date.now(); + // console.log('reload', new Date(this.input.lastReloadRequestTime).toISOString()); + this.reloadSubject?.next(true); } public destroy() { super.destroy(); - this.subscription.unsubscribe(); if (this.node) { ReactDOM.unmountComponentAtNode(this.node); } diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index ba638dc969061..9661e5b9d2ac6 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -12,6 +12,7 @@ import type { TimeRange } from '@kbn/es-query'; import { CONTEXT_MENU_TRIGGER } from '@kbn/embeddable-plugin/public'; import { IEmbeddable, EmbeddableOutput } from '@kbn/embeddable-plugin/public'; import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; +import { Subject } from 'rxjs'; import { SloAlertsSummary } from './components/slo_alerts_summary'; import { SloAlertsTable } from './components/slo_alerts_table'; import type { SloItem } from './types'; @@ -26,7 +27,7 @@ interface Props { timeRange: TimeRange; embeddable: IEmbeddable; onRenderComplete?: () => void; - lastReloadRequestTime?: number | undefined; + reloadSubject: Subject; } export function SloAlertsWrapper({ @@ -35,13 +36,21 @@ export function SloAlertsWrapper({ deps, timeRange, onRenderComplete, - lastReloadRequestTime, + reloadSubject, }: Props) { const { application: { navigateToUrl }, http: { basePath }, } = deps; + const [lastRefreshTime, setLastRefreshTime] = useState(undefined); + + useEffect(() => { + reloadSubject.subscribe(() => { + setLastRefreshTime(Date.now()); + }); + }, [reloadSubject]); + const [isSummaryLoaded, setIsSummaryLoaded] = useState(false); const [isTableLoaded, setIsTableLoaded] = useState(false); useEffect(() => { @@ -125,7 +134,7 @@ export function SloAlertsWrapper({ deps={deps} timeRange={timeRange} onLoaded={() => setIsTableLoaded(true)} - lastReloadRequestTime={lastReloadRequestTime} + lastReloadRequestTime={lastRefreshTime} />
diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx index 9a90efb19bc87..94f80e30fc582 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; import ReactDOM from 'react-dom'; -import { Subscription } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { @@ -18,6 +17,7 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { type CoreStart, IUiSettingsClient, ApplicationStart } from '@kbn/core/public'; +import { Subject } from 'rxjs'; import { SloOverview } from './slo_overview'; import type { SloEmbeddableInput } from './types'; @@ -32,8 +32,8 @@ interface SloEmbeddableDeps { export class SLOEmbeddable extends AbstractEmbeddable { public readonly type = SLO_EMBEDDABLE; - private subscription: Subscription; private node?: HTMLElement; + private reloadSubject: Subject; constructor( private readonly deps: SloEmbeddableDeps, @@ -41,9 +41,14 @@ export class SLOEmbeddable extends AbstractEmbeddable(); - this.subscription = new Subscription(); - this.subscription.add(this.getInput$().subscribe(() => this.reload())); + this.setTitle( + this.input.title || + i18n.translate('xpack.observability.sloEmbeddable.displayTitle', { + defaultMessage: 'SLO Overview', + }) + ); } setTitle(title: string) { @@ -59,12 +64,6 @@ export class SLOEmbeddable extends AbstractEmbeddable this.onRenderComplete()} sloId={sloId} sloInstanceId={sloInstanceId} - lastReloadRequestTime={this.input.lastReloadRequestTime} + reloadSubject={this.reloadSubject} />
@@ -88,16 +87,11 @@ export class SLOEmbeddable extends AbstractEmbeddable(null); + const containerRef = useRef(null); + + const [lastRefreshTime, setLastRefreshTime] = useState(undefined); + + useEffect(() => { + reloadSubject.subscribe(() => { + setLastRefreshTime(Date.now()); + }); + }, [reloadSubject]); const { isLoading, @@ -53,7 +61,7 @@ export function SloOverview({ useEffect(() => { refetch(); - }, [lastReloadRequestTime, refetch]); + }, [lastRefreshTime, refetch]); useEffect(() => { if (!onRenderComplete) return; diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/types.ts b/x-pack/plugins/observability/public/embeddable/slo/overview/types.ts index a6f55069dc47e..ac1f906d1f2ed 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/types.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/types.ts @@ -5,11 +5,12 @@ * 2.0. */ import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; +import { Subject } from 'rxjs'; export interface EmbeddableSloProps { sloId: string | undefined; sloInstanceId: string | undefined; - lastReloadRequestTime?: number | undefined; + reloadSubject: Subject; onRenderComplete?: () => void; } From 9c025b2954c732c08e63096780822250605fcd9b Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 11:15:06 +0100 Subject: [PATCH 67/85] fix styles --- .../slo/alerts/slo_alerts_wrapper.tsx | 119 +++++++++--------- 1 file changed, 61 insertions(+), 58 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index 9661e5b9d2ac6..bc2c3ada5fc5e 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -13,6 +13,7 @@ import { CONTEXT_MENU_TRIGGER } from '@kbn/embeddable-plugin/public'; import { IEmbeddable, EmbeddableOutput } from '@kbn/embeddable-plugin/public'; import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; import { Subject } from 'rxjs'; +import styled from 'styled-components'; import { SloAlertsSummary } from './components/slo_alerts_summary'; import { SloAlertsTable } from './components/slo_alerts_table'; import type { SloItem } from './types'; @@ -78,68 +79,70 @@ export function SloAlertsWrapper({ }; return ( - <> - - - - - { - const trigger = deps.uiActions.getTrigger(CONTEXT_MENU_TRIGGER); - deps.uiActions.getAction(EDIT_SLO_ALERTS_ACTION).execute({ - trigger, - embeddable, - } as ActionExecutionContext); - }} - data-test-subj="o11ySloAlertsWrapperSlOsIncludedLink" - > - {i18n.translate('xpack.observability.sloAlertsWrapper.sLOsIncludedFlexItemLabel', { - defaultMessage: '{numOfSlos} SLOs included', - values: { numOfSlos: slos.length }, - })} - - - - - {' '} - - - - + + + + { + const trigger = deps.uiActions.getTrigger(CONTEXT_MENU_TRIGGER); + deps.uiActions.getAction(EDIT_SLO_ALERTS_ACTION).execute({ + trigger, + embeddable, + } as ActionExecutionContext); + }} + data-test-subj="o11ySloAlertsWrapperSlOsIncludedLink" + > + {i18n.translate('xpack.observability.sloAlertsWrapper.sLOsIncludedFlexItemLabel', { + defaultMessage: '{numOfSlos} SLOs included', + values: { numOfSlos: slos.length }, + })} + + + + + + + + - - - setIsSummaryLoaded(true)} - /> - - - setIsTableLoaded(true)} - lastReloadRequestTime={lastRefreshTime} - /> - - + setIsSummaryLoaded(true)} + /> + + + setIsTableLoaded(true)} + lastReloadRequestTime={lastRefreshTime} + /> - + ); } + +const Wrapper = styled.div` + width: 100%; +`; From f4a196c11696b9c4ecaa8871ad19c83199468107 Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 11:22:18 +0100 Subject: [PATCH 68/85] fix date picker reload for alerts table --- .../public/embeddable/slo/alerts/slo_alerts_embeddable.tsx | 4 ++++ .../public/embeddable/slo/alerts/slo_alerts_wrapper.tsx | 2 +- .../public/embeddable/slo/alerts/slo_configuration.tsx | 7 ++++++- .../public/embeddable/slo/overview/slo_overview.tsx | 2 +- .../observability/public/embeddable/slo/overview/types.ts | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 849abd470b27d..3825e5ce89878 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -77,6 +77,10 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< this.kibanaVersion = kibanaVersion; this.reloadSubject = new Subject(); + this.getInput$().subscribe(() => { + this.reloadSubject.next(true); + }); + this.setTitle( this.input.title || i18n.translate('xpack.observability.sloAlertsEmbeddable.displayTitle', { diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index bc2c3ada5fc5e..f22a31dc9f804 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -47,7 +47,7 @@ export function SloAlertsWrapper({ const [lastRefreshTime, setLastRefreshTime] = useState(undefined); useEffect(() => { - reloadSubject.subscribe(() => { + reloadSubject?.subscribe(() => { setLastRefreshTime(Date.now()); }); }, [reloadSubject]); diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx index dc13155cef091..c741a39e28560 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx @@ -35,7 +35,12 @@ export function SloConfiguration({ initialInput, onCreate, onCancel }: SloConfig const onConfirmClick = () => onCreate({ slos: selectedSlos }); return ( - + {i18n.translate('xpack.observability.sloEmbeddable.config.sloSelector.headerTitle', { diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx index df067f210bc2e..a36bb478fc325 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx @@ -32,7 +32,7 @@ export function SloOverview({ const [lastRefreshTime, setLastRefreshTime] = useState(undefined); useEffect(() => { - reloadSubject.subscribe(() => { + reloadSubject?.subscribe(() => { setLastRefreshTime(Date.now()); }); }, [reloadSubject]); diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/types.ts b/x-pack/plugins/observability/public/embeddable/slo/overview/types.ts index ac1f906d1f2ed..f4ba87fd7d52f 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/types.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/types.ts @@ -10,7 +10,7 @@ import { Subject } from 'rxjs'; export interface EmbeddableSloProps { sloId: string | undefined; sloInstanceId: string | undefined; - reloadSubject: Subject; + reloadSubject?: Subject; onRenderComplete?: () => void; } From 74a9797fac5df9bcd7d39ee0a7540553e9bbad4a Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 11:28:18 +0100 Subject: [PATCH 69/85] resolve PR feedback --- .../public/embeddable/slo/overview/slo_overview.tsx | 1 - .../public/pages/slos/components/badges/slo_rules_badge.tsx | 2 +- .../pages/slos/components/card_view/slo_card_item_badges.tsx | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx index a36bb478fc325..3cec4e148ab16 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx @@ -115,7 +115,6 @@ export function SloOverview({ slo={slo} rules={rules} activeAlerts={activeAlerts} - handleCreateRule={() => {}} hasGroupBy={hasGroupBy} /> diff --git a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_rules_badge.tsx b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_rules_badge.tsx index 5feec4691cd0a..bcb3a1a0c5111 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_rules_badge.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_rules_badge.tsx @@ -14,7 +14,7 @@ import { SloRule } from '../../../../hooks/slo/use_fetch_rules_for_slo'; export interface Props { rules: Array> | undefined; - onClick: () => void; + onClick?: () => void; } export function SloRulesBadge({ rules, onClick }: Props) { diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_badges.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_badges.tsx index 4a3663b0a8c54..1fec95eb98f73 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_badges.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_badges.tsx @@ -22,7 +22,7 @@ interface Props { activeAlerts?: number; slo: SLOWithSummaryResponse; rules: Array> | undefined; - handleCreateRule: () => void; + handleCreateRule?: () => void; } const Container = styled.div` From 30a554f9f5cebc06df6a68f5a8dad623994a5b2a Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 11:30:23 +0100 Subject: [PATCH 70/85] common constant PR feedback --- .../slo/alerts/slo_alerts_embeddable_factory.ts | 8 ++------ .../slo/overview/slo_embeddable_factory.ts | 13 +++++++------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts index fe9ddcbf1a062..dcdd632d6edb0 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.ts @@ -13,6 +13,7 @@ import { ErrorEmbeddable, IContainer, } from '@kbn/embeddable-plugin/public'; +import { COMMON_SLO_GROUPING } from '../overview/slo_embeddable_factory'; import { SLO_ALERTS_EMBEDDABLE, SLOAlertsEmbeddable } from './slo_alerts_embeddable'; import { ObservabilityPublicPluginsStart, ObservabilityPublicStart } from '../../..'; import { SloAlertsEmbeddableInput } from './types'; @@ -21,12 +22,7 @@ export type SloAlertsEmbeddableFactory = EmbeddableFactory; export class SloAlertsEmbeddableFactoryDefinition implements EmbeddableFactoryDefinition { public readonly type = SLO_ALERTS_EMBEDDABLE; - public readonly grouping = [ - { - id: 'slos', - getDisplayName: () => 'SLOs', - }, - ]; + public readonly grouping = COMMON_SLO_GROUPING; constructor( private getStartServices: CoreSetup< diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts index 50b42f7e13910..4188b31432e99 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts @@ -18,18 +18,19 @@ import { SLOEmbeddable, SLO_EMBEDDABLE } from './slo_embeddable'; import { ObservabilityPublicPluginsStart, ObservabilityPublicStart } from '../../..'; import type { SloEmbeddableInput } from './types'; +export const COMMON_SLO_GROUPING = [ + { + id: 'slos', + getDisplayName: () => 'SLOs', + }, +]; export type SloOverviewEmbeddableFactory = EmbeddableFactory; export class SloOverviewEmbeddableFactoryDefinition implements EmbeddableFactoryDefinition, IProvidesPanelPlacementSettings { public readonly type = SLO_EMBEDDABLE; - public readonly grouping = [ - { - id: 'slos', - getDisplayName: () => 'SLOs', - }, - ]; + public readonly grouping = COMMON_SLO_GROUPING; constructor( private getStartServices: CoreSetup< From 400404a7c437d535ebb8fb27524adbc47347b499 Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 11:53:28 +0100 Subject: [PATCH 71/85] simplify query PR feedback --- .../alerts_table/render_cell_value.tsx | 8 +- .../alerts/components/slo_alerts_summary.tsx | 4 +- .../alerts/components/slo_alerts_table.tsx | 78 +++++++++---------- 3 files changed, 43 insertions(+), 47 deletions(-) diff --git a/x-pack/plugins/observability/public/components/alerts_table/render_cell_value.tsx b/x-pack/plugins/observability/public/components/alerts_table/render_cell_value.tsx index c54569f9a6699..4dac209279f33 100644 --- a/x-pack/plugins/observability/public/components/alerts_table/render_cell_value.tsx +++ b/x-pack/plugins/observability/public/components/alerts_table/render_cell_value.tsx @@ -49,12 +49,16 @@ const getRenderValue = (mappedNonEcsValue: any) => { if (!isEmpty(value)) { if (typeof value === 'object') { - return JSON.stringify(value); + try { + return JSON.stringify(value); + } catch (e) { + return 'Error: Unable to parse JSON value.'; + } } return value; } - return '—'; + return '—-'; }; /** diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx index 6414650cf11c8..3314f7dc830e4 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx @@ -78,8 +78,8 @@ export function SloAlertsSummary({ slos, deps, timeRange, onLoaded }: Props) { from: timeRange.from, to: timeRange.to, }, - bucketSize?.intervalString || DEFAULT_INTERVAL, - bucketSize?.dateFormat || DEFAULT_DATE_FORMAT + bucketSize?.intervalString ?? DEFAULT_INTERVAL, + bucketSize?.dateFormat ?? DEFAULT_DATE_FORMAT ), [timeRange.from, timeRange.to, bucketSize] ); diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index 6d452f7c1ce7e..accbe6696fd7e 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -4,18 +4,15 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { AlertConsumers } from '@kbn/rule-data-utils'; import type { TimeRange } from '@kbn/es-query'; import { ALL_VALUE } from '@kbn/slo-schema'; +import { AlertsTableStateProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/alerts_table_state'; import { SloEmbeddableDeps } from '../slo_alerts_embeddable'; import type { SloItem } from '../types'; import { SLO_ALERTS_TABLE_CONFID } from '../../constants'; -type SloIdAndInstanceId = [string, string]; -interface FilterQuery { - [key: string]: any; -} const ALERTS_PER_PAGE = 10; const ALERTS_TABLE_ID = 'xpack.observability.sloAlertsEmbeddable.alert.table'; @@ -27,51 +24,46 @@ interface Props { lastReloadRequestTime: number | undefined; } +const useSloAlertsQuery = (slos: SloItem[], timeRange: TimeRange) => { + return useMemo(() => { + const sloInstanceIds = slos + .filter((slo) => slo.instanceId !== ALL_VALUE) + .map((slo) => slo.instanceId); + const sloIds = slos.filter((slo) => slo.instanceId === ALL_VALUE).map((slo) => slo.id); + + const query: AlertsTableStateProps['query'] = { + bool: { + filter: [ + { + range: { + '@timestamp': { + gte: timeRange.from, + }, + }, + }, + { + term: { + 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', + }, + }, + ...(sloIds.length > 0 ? [{ term: { 'slo.id': sloIds } }] : []), + ...(sloInstanceIds.length > 0 ? [{ term: { 'slo.instanceId': sloInstanceIds } }] : []), + ], + }, + }; + + return query; + }, [slos, timeRange]); +}; + export function SloAlertsTable({ slos, deps, timeRange, onLoaded, lastReloadRequestTime }: Props) { const { triggersActionsUi: { alertsTableConfigurationRegistry, getAlertsStateTable: AlertsStateTable }, } = deps; - const slosWithoutName = slos.map((slo) => ({ - id: slo.id, - instanceId: slo.instanceId, - })); - const sloIdsAndInstanceIds = slosWithoutName.map(Object.values) as SloIdAndInstanceId[]; return ( { - const filterQuery = [{ term: { 'slo.id': sloId } } as FilterQuery]; - if (instanceId !== ALL_VALUE) { - filterQuery.push({ term: { 'slo.instanceId': instanceId } }); - } - return { - bool: { - filter: filterQuery, - }, - }; - }), - }, - }, - ], - }, - }} + query={useSloAlertsQuery(slos, timeRange)} alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} configurationId={SLO_ALERTS_TABLE_CONFID} featureIds={[AlertConsumers.SLO, AlertConsumers.OBSERVABILITY]} From 2ff0c2e160309696aba0d1b175e9c190ffcc8cd3 Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 11:57:09 +0100 Subject: [PATCH 72/85] some PR feedback nits --- .../public/embeddable/slo/alerts/slo_selector.tsx | 4 ++-- .../public/embeddable/slo/overview/slo_selector.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx index bd72bbc6402e0..c767e632211e6 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx @@ -40,9 +40,9 @@ export function SloSelector({ initialSlos, onSelected, hasError }: Props) { }); useEffect(() => { - const isLoadedWithData = !isLoading && sloList!.results !== undefined; + const isLoadedWithData = !isLoading && sloList?.results !== undefined; const opts: Array> = isLoadedWithData - ? mapSlosToOptions(sloList!.results!) + ? mapSlosToOptions(sloList?.results) : []; setOptions(opts); }, [isLoading, sloList]); diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_selector.tsx index 49283764afe07..b20f469f49725 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_selector.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_selector.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { debounce } from 'lodash'; @@ -58,7 +58,7 @@ export function SloSelector({ initialSlo, onSelected, hasError }: Props) { onSelected(selectedSlo); }; - const onSearchChange = useMemo( + const onSearchChange = useCallback( () => debounce((value: string) => { setSearchValue(value); From aef588d3d42d54fc16dcd6948214b600e5a5dde0 Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 12:03:57 +0100 Subject: [PATCH 73/85] fix query --- .../slo/alerts/components/slo_alerts_table.tsx | 4 ++-- .../slo/alerts/slo_alerts_embeddable.tsx | 16 +++++++++------- .../embeddable/slo/alerts/slo_alerts_wrapper.tsx | 13 ++++++++++--- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index accbe6696fd7e..4dfb148f9f4d4 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -46,8 +46,8 @@ const useSloAlertsQuery = (slos: SloItem[], timeRange: TimeRange) => { 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', }, }, - ...(sloIds.length > 0 ? [{ term: { 'slo.id': sloIds } }] : []), - ...(sloInstanceIds.length > 0 ? [{ term: { 'slo.instanceId': sloInstanceIds } }] : []), + ...(sloIds.length > 0 ? [{ terms: { 'slo.id': sloIds } }] : []), + ...(sloInstanceIds.length > 0 ? [{ terms: { 'slo.instanceId': sloInstanceIds } }] : []), ], }, }; diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index 3825e5ce89878..b825170424c34 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -35,6 +35,7 @@ import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { ServerlessPluginStart } from '@kbn/serverless/public'; import { Subject } from 'rxjs'; +import { TimeRange } from '@kbn/es-query'; import { SloAlertsWrapper } from './slo_alerts_wrapper'; import type { SloAlertsEmbeddableInput } from './types'; export const SLO_ALERTS_EMBEDDABLE = 'SLO_ALERTS_EMBEDDABLE'; @@ -62,7 +63,7 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< EmbeddableOutput > { public readonly type = SLO_ALERTS_EMBEDDABLE; - private reloadSubject: Subject; + private reloadSubject: Subject; private node?: HTMLElement; kibanaVersion: string; @@ -75,10 +76,11 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< super(initialInput, {}, parent); this.deps = deps; this.kibanaVersion = kibanaVersion; - this.reloadSubject = new Subject(); + this.reloadSubject = new Subject(); - this.getInput$().subscribe(() => { - this.reloadSubject.next(true); + this.getInput$().subscribe((input) => { + const { timeRange = { from: 'now-15m/m', to: 'now' } } = input; + this.reloadSubject.next(timeRange); }); this.setTitle( @@ -138,9 +140,9 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< } public reload() { - // this.input.lastReloadRequestTime = Date.now(); - // console.log('reload', new Date(this.input.lastReloadRequestTime).toISOString()); - this.reloadSubject?.next(true); + const { timeRange = { from: 'now-15m/m', to: 'now' } } = this.getInput(); + + this.reloadSubject?.next(timeRange); } public destroy() { diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index f22a31dc9f804..30e5cbe4cbeb0 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -28,14 +28,14 @@ interface Props { timeRange: TimeRange; embeddable: IEmbeddable; onRenderComplete?: () => void; - reloadSubject: Subject; + reloadSubject: Subject; } export function SloAlertsWrapper({ embeddable, slos, deps, - timeRange, + timeRange: initialTimeRange, onRenderComplete, reloadSubject, }: Props) { @@ -44,14 +44,21 @@ export function SloAlertsWrapper({ http: { basePath }, } = deps; + const [timeRange, setTimeRange] = useState(initialTimeRange); + const [lastRefreshTime, setLastRefreshTime] = useState(undefined); useEffect(() => { - reloadSubject?.subscribe(() => { + reloadSubject?.subscribe((nTimeRange) => { setLastRefreshTime(Date.now()); + setTimeRange(nTimeRange); }); }, [reloadSubject]); + useEffect(() => { + setTimeRange(initialTimeRange); + }, [initialTimeRange]); + const [isSummaryLoaded, setIsSummaryLoaded] = useState(false); const [isTableLoaded, setIsTableLoaded] = useState(false); useEffect(() => { From 644fa72ef027b9d9eb2576fa3286ecb27f4ce152 Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 12:06:23 +0100 Subject: [PATCH 74/85] update --- .../public/embeddable/slo/alerts/slo_alerts_wrapper.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index 30e5cbe4cbeb0..7727b1fabe526 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -50,8 +50,8 @@ export function SloAlertsWrapper({ useEffect(() => { reloadSubject?.subscribe((nTimeRange) => { - setLastRefreshTime(Date.now()); setTimeRange(nTimeRange); + setLastRefreshTime(Date.now()); }); }, [reloadSubject]); From 6e0bb579a2b258bb395bef52ac726a67d8382a5f Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 12:13:56 +0100 Subject: [PATCH 75/85] clean up --- .../slo/alerts/slo_alerts_embeddable.tsx | 14 +++++++------- .../embeddable/slo/alerts/slo_alerts_wrapper.tsx | 11 ++++++++--- .../embeddable/slo/overview/slo_overview.tsx | 3 +++ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx index b825170424c34..b8e182e1f0fd2 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_embeddable.tsx @@ -34,7 +34,7 @@ import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { ServerlessPluginStart } from '@kbn/serverless/public'; -import { Subject } from 'rxjs'; +import { Subject, Subscription } from 'rxjs'; import { TimeRange } from '@kbn/es-query'; import { SloAlertsWrapper } from './slo_alerts_wrapper'; import type { SloAlertsEmbeddableInput } from './types'; @@ -63,9 +63,10 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< EmbeddableOutput > { public readonly type = SLO_ALERTS_EMBEDDABLE; - private reloadSubject: Subject; + private reloadSubject: Subject; private node?: HTMLElement; kibanaVersion: string; + private subscription: Subscription; constructor( private readonly deps: SloEmbeddableDeps, @@ -76,9 +77,9 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< super(initialInput, {}, parent); this.deps = deps; this.kibanaVersion = kibanaVersion; - this.reloadSubject = new Subject(); + this.reloadSubject = new Subject(); - this.getInput$().subscribe((input) => { + this.subscription = this.getInput$().subscribe((input) => { const { timeRange = { from: 'now-15m/m', to: 'now' } } = input; this.reloadSubject.next(timeRange); }); @@ -140,13 +141,12 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< } public reload() { - const { timeRange = { from: 'now-15m/m', to: 'now' } } = this.getInput(); - - this.reloadSubject?.next(timeRange); + this.reloadSubject?.next(undefined); } public destroy() { super.destroy(); + this.subscription.unsubscribe(); if (this.node) { ReactDOM.unmountComponentAtNode(this.node); } diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index 7727b1fabe526..693fbce4e6469 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -28,7 +28,7 @@ interface Props { timeRange: TimeRange; embeddable: IEmbeddable; onRenderComplete?: () => void; - reloadSubject: Subject; + reloadSubject: Subject; } export function SloAlertsWrapper({ @@ -50,10 +50,15 @@ export function SloAlertsWrapper({ useEffect(() => { reloadSubject?.subscribe((nTimeRange) => { - setTimeRange(nTimeRange); + if (nTimeRange && (nTimeRange.from !== timeRange.from || nTimeRange.to !== timeRange.to)) { + setTimeRange(nTimeRange); + } setLastRefreshTime(Date.now()); }); - }, [reloadSubject]); + return () => { + reloadSubject?.unsubscribe(); + }; + }, [reloadSubject, timeRange.from, timeRange.to]); useEffect(() => { setTimeRange(initialTimeRange); diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx index 3cec4e148ab16..0bd1b7048dcc0 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_overview.tsx @@ -35,6 +35,9 @@ export function SloOverview({ reloadSubject?.subscribe(() => { setLastRefreshTime(Date.now()); }); + return () => { + reloadSubject?.unsubscribe(); + }; }, [reloadSubject]); const { From 184defcdbc680ee9f54d277d0e405ccbb3a8351a Mon Sep 17 00:00:00 2001 From: mgiota Date: Tue, 5 Dec 2023 12:40:42 +0100 Subject: [PATCH 76/85] increase number of SLOs to 100 --- .../public/embeddable/slo/alerts/slo_selector.tsx | 1 + .../observability/public/hooks/slo/use_fetch_slo_list.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx index c767e632211e6..8895ebafe93ef 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx @@ -37,6 +37,7 @@ export function SloSelector({ initialSlos, onSelected, hasError }: Props) { const [searchValue, setSearchValue] = useState(''); const { isLoading, data: sloList } = useFetchSloList({ kqlQuery: `slo.name: ${searchValue.replaceAll(' ', '*')}*`, + perPage: 100, }); useEffect(() => { diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts index a05ec3c616950..f3f51de9d4890 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_slo_list.ts @@ -20,6 +20,7 @@ interface SLOListParams { sortBy?: string; sortDirection?: 'asc' | 'desc'; shouldRefetch?: boolean; + perPage?: number; } export interface UseFetchSloListResponse { @@ -37,6 +38,7 @@ export function useFetchSloList({ sortBy = 'status', sortDirection = 'desc', shouldRefetch, + perPage, }: SLOListParams = {}): UseFetchSloListResponse { const { http, @@ -56,6 +58,7 @@ export function useFetchSloList({ ...(sortBy && { sortBy }), ...(sortDirection && { sortDirection }), ...(page && { page }), + ...(perPage && { perPage }), }, signal, }); From 1c4f44611f8748a53105aa45417bc1d0791e1cf6 Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 12:48:32 +0100 Subject: [PATCH 77/85] update search --- .../public/embeddable/slo/alerts/slo_selector.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx index 8895ebafe93ef..d215348449f98 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx @@ -35,8 +35,9 @@ export function SloSelector({ initialSlos, onSelected, hasError }: Props) { mapSlosToOptions(initialSlos) ); const [searchValue, setSearchValue] = useState(''); + const query = `${searchValue.replaceAll(' ', '*')}*`; const { isLoading, data: sloList } = useFetchSloList({ - kqlQuery: `slo.name: ${searchValue.replaceAll(' ', '*')}*`, + kqlQuery: `slo.name: ${query} or slo.instanceId: ${query}`, perPage: 100, }); From fc74b7ee54dde233e42356d0a66f220b8379176c Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 12:54:32 +0100 Subject: [PATCH 78/85] fix unsub --- .../public/embeddable/slo/alerts/slo_alerts_wrapper.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index 693fbce4e6469..0a8b9bed5c805 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -49,14 +49,14 @@ export function SloAlertsWrapper({ const [lastRefreshTime, setLastRefreshTime] = useState(undefined); useEffect(() => { - reloadSubject?.subscribe((nTimeRange) => { + const subs = reloadSubject?.subscribe((nTimeRange) => { if (nTimeRange && (nTimeRange.from !== timeRange.from || nTimeRange.to !== timeRange.to)) { setTimeRange(nTimeRange); } setLastRefreshTime(Date.now()); }); return () => { - reloadSubject?.unsubscribe(); + subs?.unsubscribe(); }; }, [reloadSubject, timeRange.from, timeRange.to]); From 3432e028a63604e4131b4a71529e5fbd9cc40fd6 Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 13:10:47 +0100 Subject: [PATCH 79/85] fix queryn --- .../slo/alerts/components/slo_alerts_table.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index 4dfb148f9f4d4..1dd70763f3ace 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -46,8 +46,16 @@ const useSloAlertsQuery = (slos: SloItem[], timeRange: TimeRange) => { 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', }, }, - ...(sloIds.length > 0 ? [{ terms: { 'slo.id': sloIds } }] : []), - ...(sloInstanceIds.length > 0 ? [{ terms: { 'slo.instanceId': sloInstanceIds } }] : []), + { + bool: { + should: [ + ...(sloIds.length > 0 ? [{ terms: { 'slo.id': sloIds } }] : []), + ...(sloInstanceIds.length > 0 + ? [{ terms: { 'slo.instanceId': sloInstanceIds } }] + : []), + ], + }, + }, ], }, }; From 4cabd1939ae4eea3ec3f7b13a349b09a2bc753c7 Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 13:30:31 +0100 Subject: [PATCH 80/85] account for changes to slos --- .../slo/alerts/components/slo_alerts_table.tsx | 8 ++++++-- .../slo/alerts/slo_alerts_embeddable.tsx | 8 +++----- .../slo/alerts/slo_alerts_wrapper.tsx | 17 ++++++++++++----- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index 1dd70763f3ace..7b920ee0502e4 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -24,7 +24,11 @@ interface Props { lastReloadRequestTime: number | undefined; } -const useSloAlertsQuery = (slos: SloItem[], timeRange: TimeRange) => { +const useSloAlertsQuery = ( + slos: SloItem[], + timeRange: TimeRange, + lastReloadRequestTime?: number +) => { return useMemo(() => { const sloInstanceIds = slos .filter((slo) => slo.instanceId !== ALL_VALUE) @@ -71,7 +75,7 @@ export function SloAlertsTable({ slos, deps, timeRange, onLoaded, lastReloadRequ return ( { public readonly type = SLO_ALERTS_EMBEDDABLE; - private reloadSubject: Subject; + private reloadSubject: Subject; private node?: HTMLElement; kibanaVersion: string; private subscription: Subscription; @@ -77,11 +76,10 @@ export class SLOAlertsEmbeddable extends AbstractEmbeddable< super(initialInput, {}, parent); this.deps = deps; this.kibanaVersion = kibanaVersion; - this.reloadSubject = new Subject(); + this.reloadSubject = new Subject(); this.subscription = this.getInput$().subscribe((input) => { - const { timeRange = { from: 'now-15m/m', to: 'now' } } = input; - this.reloadSubject.next(timeRange); + this.reloadSubject.next(input); }); this.setTitle( diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index 0a8b9bed5c805..827ad8bc444b3 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -28,12 +28,12 @@ interface Props { timeRange: TimeRange; embeddable: IEmbeddable; onRenderComplete?: () => void; - reloadSubject: Subject; + reloadSubject: Subject; } export function SloAlertsWrapper({ embeddable, - slos, + slos: initialSlos, deps, timeRange: initialTimeRange, onRenderComplete, @@ -45,13 +45,20 @@ export function SloAlertsWrapper({ } = deps; const [timeRange, setTimeRange] = useState(initialTimeRange); + const [slos, setSlos] = useState(initialSlos); const [lastRefreshTime, setLastRefreshTime] = useState(undefined); useEffect(() => { - const subs = reloadSubject?.subscribe((nTimeRange) => { - if (nTimeRange && (nTimeRange.from !== timeRange.from || nTimeRange.to !== timeRange.to)) { - setTimeRange(nTimeRange); + const subs = reloadSubject?.subscribe((input) => { + if (input) { + const { timeRange: nTimeRange, slos: nSlos } = input; + + setSlos(nSlos); + + if (nTimeRange && (nTimeRange.from !== timeRange.from || nTimeRange.to !== timeRange.to)) { + setTimeRange(nTimeRange); + } } setLastRefreshTime(Date.now()); }); From efbd59e6de6ea1b86a85eb45f5453198ef0e5f0a Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 13:34:12 +0100 Subject: [PATCH 81/85] use same query in summary --- .../alerts/components/slo_alerts_summary.tsx | 32 ++----------------- .../alerts/components/slo_alerts_table.tsx | 8 ++--- 2 files changed, 4 insertions(+), 36 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx index 3314f7dc830e4..21cf577c00dc1 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx @@ -6,6 +6,7 @@ */ import React, { useMemo } from 'react'; import type { TimeRange } from '@kbn/es-query'; +import { useSloAlertsQuery } from './slo_alerts_table'; import { getAlertSummaryTimeRange } from '../../../../utils/alert_summary_widget'; import { observabilityAlertFeatureIds } from '../../../../../common/constants'; import { useTimeBuckets } from '../../../../hooks/use_time_buckets'; @@ -13,7 +14,6 @@ import { calculateTimeRangeBucketSize } from '../../../../pages/overview/helpers import { SloEmbeddableDeps } from '../slo_alerts_embeddable'; import { SloItem } from '../types'; -type SloIdAndInstanceId = [string, string]; const DEFAULT_INTERVAL = '60s'; const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD HH:mm'; @@ -30,35 +30,7 @@ export function SloAlertsSummary({ slos, deps, timeRange, onLoaded }: Props) { triggersActionsUi: { getAlertSummaryWidget: AlertSummaryWidget }, } = deps; - const slosWithoutName = slos.map((slo) => ({ - id: slo.id, - instanceId: slo.instanceId, - })); - const sloIdsAndInstanceIds = slosWithoutName.map(Object.values) as SloIdAndInstanceId[]; - const esQuery = { - bool: { - filter: [ - { - range: { - '@timestamp': { - gte: timeRange.from, - }, - }, - }, - { - term: { - 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', - }, - }, - ], - should: sloIdsAndInstanceIds.map(([sloId, instanceId]) => ({ - bool: { - filter: [{ term: { 'slo.id': sloId } }, { term: { 'slo.instanceId': instanceId } }], - }, - })), - minimum_should_match: 1, - }, - }; + const esQuery = useSloAlertsQuery(slos, timeRange); const timeBuckets = useTimeBuckets(); const bucketSize = useMemo( () => diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index 7b920ee0502e4..83d792448cc48 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -24,11 +24,7 @@ interface Props { lastReloadRequestTime: number | undefined; } -const useSloAlertsQuery = ( - slos: SloItem[], - timeRange: TimeRange, - lastReloadRequestTime?: number -) => { +export const useSloAlertsQuery = (slos: SloItem[], timeRange: TimeRange) => { return useMemo(() => { const sloInstanceIds = slos .filter((slo) => slo.instanceId !== ALL_VALUE) @@ -75,7 +71,7 @@ export function SloAlertsTable({ slos, deps, timeRange, onLoaded, lastReloadRequ return ( Date: Tue, 5 Dec 2023 14:09:16 +0100 Subject: [PATCH 82/85] wrap --- .../public/embeddable/slo/alerts/slo_alerts_wrapper.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index 827ad8bc444b3..d71650f27bd4d 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -99,7 +99,7 @@ export function SloAlertsWrapper({ return ( - + Date: Tue, 5 Dec 2023 14:15:29 +0100 Subject: [PATCH 83/85] improve styling --- .../slo/alerts/slo_alerts_wrapper.tsx | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx index d71650f27bd4d..2038c5ed707da 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_alerts_wrapper.tsx @@ -99,12 +99,14 @@ export function SloAlertsWrapper({ return ( - - + + { const trigger = deps.uiActions.getTrigger(CONTEXT_MENU_TRIGGER); @@ -121,12 +123,7 @@ export function SloAlertsWrapper({ })} - + Date: Tue, 5 Dec 2023 16:59:16 +0100 Subject: [PATCH 84/85] use common selector and update query --- .../alerts/components/slo_alerts_table.tsx | 35 ++++--- .../slo/alerts/slo_configuration.tsx | 25 +++-- .../embeddable/slo/alerts/slo_selector.tsx | 6 +- .../slo/overview/slo_configuration.tsx | 10 +- .../slo/overview/slo_embeddable_factory.ts | 3 + .../embeddable/slo/overview/slo_selector.tsx | 97 ------------------- 6 files changed, 47 insertions(+), 129 deletions(-) delete mode 100644 x-pack/plugins/observability/public/embeddable/slo/overview/slo_selector.tsx diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index 83d792448cc48..9df76482e4f39 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -24,13 +24,31 @@ interface Props { lastReloadRequestTime: number | undefined; } +export const getSloInstanceFilter = (sloId: string, sloInstanceId: string) => { + return { + bool: { + must: [ + { + term: { + 'slo.id': sloId, + }, + }, + ...(sloInstanceId !== ALL_VALUE + ? [ + { + term: { + 'slo.instanceId': sloInstanceId, + }, + }, + ] + : []), + ], + }, + }; +}; + export const useSloAlertsQuery = (slos: SloItem[], timeRange: TimeRange) => { return useMemo(() => { - const sloInstanceIds = slos - .filter((slo) => slo.instanceId !== ALL_VALUE) - .map((slo) => slo.instanceId); - const sloIds = slos.filter((slo) => slo.instanceId === ALL_VALUE).map((slo) => slo.id); - const query: AlertsTableStateProps['query'] = { bool: { filter: [ @@ -48,12 +66,7 @@ export const useSloAlertsQuery = (slos: SloItem[], timeRange: TimeRange) => { }, { bool: { - should: [ - ...(sloIds.length > 0 ? [{ terms: { 'slo.id': sloIds } }] : []), - ...(sloInstanceIds.length > 0 - ? [{ terms: { 'slo.instanceId': sloInstanceIds } }] - : []), - ], + should: slos.map((slo) => getSloInstanceFilter(slo.id, slo.instanceId)), }, }, ], diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx index c741a39e28560..148ffd8492ff2 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_configuration.tsx @@ -19,8 +19,8 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; -import { SloSelector } from './slo_selector'; +import { SloSelector } from './slo_selector'; import type { EmbeddableSloProps, SloAlertsEmbeddableInput, SloItem } from './types'; interface SloConfigurationProps { @@ -54,20 +54,19 @@ export function SloConfiguration({ initialInput, onCreate, onCancel }: SloConfig { - if (slos === undefined) { - setHasError(true); - } else { - setHasError(false); + setHasError(slos === undefined); + if (Array.isArray(slos)) { + setSelectedSlos( + slos?.map((slo) => ({ + id: slo?.id, + instanceId: slo?.instanceId, + name: slo?.name, + groupBy: slo?.groupBy, + })) as SloItem[] + ); } - setSelectedSlos( - slos?.map((slo) => ({ - id: slo?.id, - instanceId: slo?.instanceId, - name: slo?.name, - groupBy: slo?.groupBy, - })) as SloItem[] - ); }} /> diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx index d215348449f98..80d564a6ea619 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx @@ -15,15 +15,16 @@ import { SloItem } from './types'; interface Props { initialSlos?: SloItem[]; - onSelected: (slos: SLOWithSummaryResponse[] | undefined) => void; + onSelected: (slos: SLOWithSummaryResponse[] | SLOWithSummaryResponse | undefined) => void; hasError?: boolean; + singleSelection?: boolean; } const SLO_REQUIRED = i18n.translate('xpack.observability.sloEmbeddable.config.errors.sloRequired', { defaultMessage: 'SLO is required.', }); -export function SloSelector({ initialSlos, onSelected, hasError }: Props) { +export function SloSelector({ initialSlos, onSelected, hasError, singleSelection }: Props) { const mapSlosToOptions = (slos: SloItem[] | SLOWithSummaryResponse[] | undefined) => slos?.map((slo) => ({ label: @@ -92,6 +93,7 @@ export function SloSelector({ initialSlos, onSelected, hasError }: Props) { fullWidth onSearchChange={onSearchChange} isInvalid={hasError} + singleSelection={singleSelection ? { asPlainText: true } : undefined} /> ); diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx index c7fcb63be7a3a..9ad860d4ece54 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx @@ -19,7 +19,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; -import { SloSelector } from './slo_selector'; +import { SloSelector } from '../alerts/slo_selector'; import type { EmbeddableSloProps } from './types'; interface SloConfigurationProps { @@ -48,12 +48,10 @@ export function SloConfiguration({ onCreate, onCancel }: SloConfigurationProps) { - if (slo === undefined) { - setHasError(true); - } else { - setHasError(false); + setHasError(slo === undefined); + if (slo && 'id' in slo) { + setSelectedSlo({ sloId: slo.id, sloInstanceId: slo.instanceId }); } - setSelectedSlo({ sloId: slo?.id, sloInstanceId: slo?.instanceId }); }} /> diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts index 4188b31432e99..646be242bfb3c 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts @@ -22,6 +22,9 @@ export const COMMON_SLO_GROUPING = [ { id: 'slos', getDisplayName: () => 'SLOs', + getIconType: () => { + return 'visGauge'; + }, }, ]; export type SloOverviewEmbeddableFactory = EmbeddableFactory; diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_selector.tsx deleted file mode 100644 index b20f469f49725..0000000000000 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_selector.tsx +++ /dev/null @@ -1,97 +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 React, { useCallback, useEffect, useState } from 'react'; -import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { debounce } from 'lodash'; -import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; -import { useFetchSloList } from '../../../hooks/slo/use_fetch_slo_list'; - -interface Props { - initialSlo?: SLOWithSummaryResponse; - onSelected: (slo: SLOWithSummaryResponse | undefined) => void; - hasError?: boolean; -} - -const SLO_REQUIRED = i18n.translate('xpack.observability.sloEmbeddable.config.errors.sloRequired', { - defaultMessage: 'SLO is required.', -}); - -export function SloSelector({ initialSlo, onSelected, hasError }: Props) { - const [options, setOptions] = useState>>([]); - const [selectedOptions, setSelectedOptions] = useState>>(); - const [searchValue, setSearchValue] = useState(''); - const { isLoading, data: sloList } = useFetchSloList({ - kqlQuery: `slo.name: ${searchValue.replaceAll(' ', '*')}*`, - }); - - useEffect(() => { - const isLoadedWithData = !isLoading && sloList!.results !== undefined; - const opts: Array> = isLoadedWithData - ? sloList!.results!.map((slo) => { - const label = - slo.instanceId !== ALL_VALUE - ? `${slo.name} (${slo.groupBy}: ${slo.instanceId})` - : slo.name; - return { - value: `${slo.id}-${slo.instanceId}`, - label, - instanceId: slo.instanceId, - }; - }) - : []; - setOptions(opts); - }, [isLoading, sloList]); - - const onChange = (opts: Array>) => { - setSelectedOptions(opts); - const selectedSlo = - opts.length === 1 - ? sloList!.results?.find((slo) => opts[0].value === `${slo.id}-${slo.instanceId}`) - : undefined; - - onSelected(selectedSlo); - }; - - const onSearchChange = useCallback( - () => - debounce((value: string) => { - setSearchValue(value); - }, 300), - [] - ); - - return ( - - - - ); -} From 137ff377b519f934615c47136d73a1f0d6cce9fe Mon Sep 17 00:00:00 2001 From: shahzad31 Date: Tue, 5 Dec 2023 17:04:31 +0100 Subject: [PATCH 85/85] enable single selection --- .../observability/public/embeddable/slo/alerts/slo_selector.tsx | 2 +- .../public/embeddable/slo/overview/slo_configuration.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx index 80d564a6ea619..dd926cc9fc179 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/alerts/slo_selector.tsx @@ -58,7 +58,7 @@ export function SloSelector({ initialSlos, onSelected, hasError, singleSelection opts.find((opt) => opt.value === `${slo.id}-${slo.instanceId}`) ) : undefined; - onSelected(selectedSlos); + onSelected(singleSelection ? selectedSlos?.[0] : selectedSlos); }; const onSearchChange = useMemo( diff --git a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx index 9ad860d4ece54..eeee1d708463b 100644 --- a/x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx +++ b/x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx @@ -46,6 +46,7 @@ export function SloConfiguration({ onCreate, onCancel }: SloConfigurationProps) { setHasError(slo === undefined);