forked from elastic/kibana
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[SLO] create SLO embeddable widget (elastic#165949)
Resolves elastic#165947 Resolves elastic/actionable-observability#124 ### Summary This PR adds an Embeddable SLO Overview Widget to the Dashboard app. It uses a [Metric chart](https://elastic.github.io/elastic-charts/?path=/story/metric-alpha--basic) component and displays an overview of the SLO health: - name - current sli value - target - status (background color) ### ✔️ Acceptance criteria - The SLO widget should display the basic information listed above - The SLO widget should be clickable and lead to the slo detail page - The user should be able to select the SLO and filter to instanceId - The tag "url.domain:mail.co" is the partition field and instanceId value <img width="1189" alt="Screenshot 2023-09-21 at 21 07 23" src="https://github.com/elastic/kibana/assets/2852703/03539b9d-23a5-45eb-aafb-df42e9421f77"> For more information regarding the key concepts and the usage of an embeddable you can have a look at the Embeddable plugin [README](https://github.com/elastic/kibana/tree/main/src/plugins/embeddable) --------- Co-authored-by: kibanamachine <[email protected]>
- Loading branch information
1 parent
5a785e8
commit 4c3fe71
Showing
11 changed files
with
604 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
x-pack/plugins/observability/public/embeddable/slo/overview/handle_explicit_input.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<EmbeddableSloProps> { | ||
const { overlays } = coreStart; | ||
const queryClient = new QueryClient(); | ||
return new Promise(async (resolve, reject) => { | ||
try { | ||
const modalSession = overlays.openModal( | ||
toMountPoint( | ||
<KibanaContextProvider | ||
services={{ | ||
...coreStart, | ||
...pluginStart, | ||
}} | ||
> | ||
<QueryClientProvider client={queryClient}> | ||
<SloConfiguration | ||
onCreate={(update: EmbeddableSloProps) => { | ||
modalSession.close(); | ||
resolve(update); | ||
}} | ||
onCancel={() => { | ||
modalSession.close(); | ||
reject(); | ||
}} | ||
/> | ||
</QueryClientProvider> | ||
</KibanaContextProvider>, | ||
{ i18n: coreStart.i18n, theme: coreStart.theme } | ||
) | ||
); | ||
} catch (error) { | ||
reject(error); | ||
} | ||
}); | ||
} |
8 changes: 8 additions & 0 deletions
8
x-pack/plugins/observability/public/embeddable/slo/overview/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 { SloOverviewEmbeddableFactoryDefinition } from './slo_embeddable_factory'; |
85 changes: 85 additions & 0 deletions
85
x-pack/plugins/observability/public/embeddable/slo/overview/slo_configuration.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
* 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; | ||
onCancel: () => void; | ||
} | ||
|
||
export function SloConfiguration({ onCreate, onCancel }: SloConfigurationProps) { | ||
const [selectedSlo, setSelectedSlo] = useState<EmbeddableSloProps>(); | ||
const onConfirmClick = () => | ||
onCreate({ sloId: selectedSlo?.sloId, sloInstanceId: selectedSlo?.sloInstanceId }); | ||
const [hasError, setHasError] = useState(false); | ||
|
||
return ( | ||
<EuiModal onClose={onCancel} style={{ minWidth: 550 }}> | ||
<EuiModalHeader> | ||
<EuiModalHeaderTitle> | ||
{i18n.translate('xpack.observability.sloEmbeddable.config.sloSelector.headerTitle', { | ||
defaultMessage: 'SLO configuration', | ||
})} | ||
</EuiModalHeaderTitle> | ||
</EuiModalHeader> | ||
<EuiModalBody> | ||
<EuiFlexGroup> | ||
<EuiFlexItem grow> | ||
<SloSelector | ||
hasError={hasError} | ||
onSelected={(slo) => { | ||
if (slo === undefined) { | ||
setHasError(true); | ||
} else { | ||
setHasError(false); | ||
} | ||
setSelectedSlo({ sloId: slo?.id, sloInstanceId: slo?.instanceId }); | ||
}} | ||
/> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
</EuiModalBody> | ||
<EuiModalFooter> | ||
<EuiButtonEmpty onClick={onCancel} data-test-subj="sloCancelButton"> | ||
<FormattedMessage | ||
id="xpack.observability.sloEmbeddable.config.cancelButtonLabel" | ||
defaultMessage="Cancel" | ||
/> | ||
</EuiButtonEmpty> | ||
|
||
<EuiButton | ||
data-test-subj="sloConfirmButton" | ||
isDisabled={!selectedSlo || hasError} | ||
onClick={onConfirmClick} | ||
fill | ||
> | ||
<FormattedMessage | ||
id="xpack.observability.embeddableSlo.config.confirmButtonLabel" | ||
defaultMessage="Confirm configurations" | ||
/> | ||
</EuiButton> | ||
</EuiModalFooter> | ||
</EuiModal> | ||
); | ||
} |
96 changes: 96 additions & 0 deletions
96
x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* | ||
* 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 ReactDOM from 'react-dom'; | ||
import { Subscription } from 'rxjs'; | ||
import { i18n } from '@kbn/i18n'; | ||
|
||
import { | ||
Embeddable as AbstractEmbeddable, | ||
EmbeddableOutput, | ||
IContainer, | ||
} from '@kbn/embeddable-plugin/public'; | ||
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 { SloOverview } from './slo_overview'; | ||
import type { SloEmbeddableInput } from './types'; | ||
|
||
export const SLO_EMBEDDABLE = 'SLO_EMBEDDABLE'; | ||
|
||
interface SloEmbeddableDeps { | ||
uiSettings: IUiSettingsClient; | ||
http: CoreStart['http']; | ||
i18n: CoreStart['i18n']; | ||
application: ApplicationStart; | ||
} | ||
|
||
export class SLOEmbeddable extends AbstractEmbeddable<SloEmbeddableInput, EmbeddableOutput> { | ||
public readonly type = SLO_EMBEDDABLE; | ||
private subscription: Subscription; | ||
private node?: HTMLElement; | ||
|
||
constructor( | ||
private readonly deps: SloEmbeddableDeps, | ||
initialInput: SloEmbeddableInput, | ||
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 Overview', | ||
}) | ||
); | ||
this.input.lastReloadRequestTime = Date.now(); | ||
|
||
const { sloId, sloInstanceId } = this.getInput(); | ||
const queryClient = new QueryClient(); | ||
|
||
const I18nContext = this.deps.i18n.Context; | ||
ReactDOM.render( | ||
<I18nContext> | ||
<KibanaContextProvider services={this.deps}> | ||
<QueryClientProvider client={queryClient}> | ||
<SloOverview | ||
sloId={sloId} | ||
sloInstanceId={sloInstanceId} | ||
lastReloadRequestTime={this.input.lastReloadRequestTime} | ||
/> | ||
</QueryClientProvider> | ||
</KibanaContextProvider> | ||
</I18nContext>, | ||
node | ||
); | ||
} | ||
|
||
public reload() { | ||
if (this.node) { | ||
this.render(this.node); | ||
} | ||
} | ||
|
||
public destroy() { | ||
super.destroy(); | ||
this.subscription.unsubscribe(); | ||
if (this.node) { | ||
ReactDOM.unmountComponentAtNode(this.node); | ||
} | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
x-pack/plugins/observability/public/embeddable/slo/overview/slo_embeddable_factory.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 { SLOEmbeddable, SLO_EMBEDDABLE } from './slo_embeddable'; | ||
import { ObservabilityPublicPluginsStart, ObservabilityPublicStart } from '../../..'; | ||
import type { SloEmbeddableInput } from './types'; | ||
|
||
export type SloOverviewEmbeddableFactory = EmbeddableFactory; | ||
export class SloOverviewEmbeddableFactoryDefinition implements EmbeddableFactoryDefinition { | ||
public readonly type = SLO_EMBEDDABLE; | ||
|
||
constructor( | ||
private getStartServices: CoreSetup< | ||
ObservabilityPublicPluginsStart, | ||
ObservabilityPublicStart | ||
>['getStartServices'] | ||
) {} | ||
|
||
public async isEditable() { | ||
return true; | ||
} | ||
|
||
public async getExplicitInput(): Promise<Partial<SloEmbeddableInput>> { | ||
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: SloEmbeddableInput, parent?: IContainer) { | ||
try { | ||
const [{ uiSettings, application, http, i18n: i18nService }] = await this.getStartServices(); | ||
return new SLOEmbeddable( | ||
{ uiSettings, application, http, i18n: i18nService }, | ||
initialInput, | ||
parent | ||
); | ||
} catch (e) { | ||
return new ErrorEmbeddable(e, initialInput, parent); | ||
} | ||
} | ||
|
||
public getDescription() { | ||
return i18n.translate('xpack.observability.sloEmbeddable.description', { | ||
defaultMessage: 'Get an overview of your SLO health', | ||
}); | ||
} | ||
|
||
public getDisplayName() { | ||
return i18n.translate('xpack.observability.sloEmbeddable.displayName', { | ||
defaultMessage: 'SLO Overview', | ||
}); | ||
} | ||
|
||
public getIconType() { | ||
return 'visGauge'; | ||
} | ||
} |
Oops, something went wrong.