diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slo_details/components/definition/definition.tsx b/x-pack/solutions/observability/plugins/slo/public/pages/slo_details/components/definition/definition.tsx
index 30d4403106a66..4c98db62b996e 100644
--- a/x-pack/solutions/observability/plugins/slo/public/pages/slo_details/components/definition/definition.tsx
+++ b/x-pack/solutions/observability/plugins/slo/public/pages/slo_details/components/definition/definition.tsx
@@ -27,6 +27,7 @@ import { ApmIndicatorOverview } from '../overview/apm_indicator_overview';
import { DisplayQuery } from '../overview/display_query';
import { DefinitionItem } from './definition_item';
import { SyntheticsIndicatorOverview } from '../overview/synthetics_indicator_overview';
+import { LinkedDashboards } from './linked_dashboards';
export interface Props {
slo: SLOWithSummaryResponse;
@@ -153,6 +154,12 @@ export function Definition({ slo }: Props) {
})}
subtitle={slo.settings.frequency}
/>
+ }
+ />
);
diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slo_details/components/definition/linked_dashboards.tsx b/x-pack/solutions/observability/plugins/slo/public/pages/slo_details/components/definition/linked_dashboards.tsx
new file mode 100644
index 0000000000000..b3d8d400b44c5
--- /dev/null
+++ b/x-pack/solutions/observability/plugins/slo/public/pages/slo_details/components/definition/linked_dashboards.tsx
@@ -0,0 +1,91 @@
+/*
+ * 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 { EuiFlexGroup, EuiFlexItem, EuiLink, EuiLoadingSpinner, EuiText } from '@elastic/eui';
+import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics';
+import React, { useMemo } from 'react';
+import type { DashboardLocatorParams } from '@kbn/dashboard-plugin/common';
+import { useQuery } from '@tanstack/react-query';
+import { i18n } from '@kbn/i18n';
+import type { DashboardStart } from '@kbn/dashboard-plugin/public';
+import type { SLODefinition } from '../../../../../server/domain/models';
+import { useKibana } from '../../../../hooks/use_kibana';
+
+interface Props {
+ dashboards: NonNullable['dashboards']>;
+}
+
+interface LinkedDashboard {
+ id: string;
+ title: string;
+}
+
+const getDashboards = async (
+ dashboardsIds: string[],
+ dashboardStart: DashboardStart
+): Promise => {
+ if (dashboardsIds.length === 0) {
+ return [];
+ }
+
+ const findDashboardsService = await dashboardStart.findDashboardsService();
+
+ const dashboards = await findDashboardsService.findByIds(dashboardsIds);
+
+ return dashboards.flatMap((dashboard) =>
+ dashboard.status === 'success' ? [{ id: dashboard.id, title: dashboard.attributes.title }] : []
+ );
+};
+
+export function LinkedDashboards({ dashboards }: Props) {
+ const {
+ services: { share },
+ services: { dashboard: dashboardStart },
+ } = useKibana();
+
+ const dashboardLocator = share.url.locators.get(DASHBOARD_APP_LOCATOR);
+
+ const dashboardsIds = useMemo(() => dashboards.map((dashboard) => dashboard.id), [dashboards]);
+
+ const { data, isLoading } = useQuery({
+ queryKey: ['SLO-dashboards', ...dashboardsIds],
+ queryFn: () => getDashboards(dashboardsIds, dashboardStart),
+ refetchOnWindowFocus: false,
+ });
+
+ if (isLoading) {
+ return ;
+ }
+
+ if (!data || data.length === 0) {
+ return (
+
+ {i18n.translate('xpack.slo.sloDetails.overview.noDashboards', {
+ defaultMessage: 'No linked dashboards',
+ })}
+
+ );
+ }
+
+ return (
+
+ {data.map((dashboardAsset) => {
+ return (
+
+
+ {dashboardAsset.title}
+
+
+ );
+ })}
+
+ );
+}
diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx b/x-pack/solutions/observability/plugins/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx
index f150599bc3838..1673dc0554e66 100644
--- a/x-pack/solutions/observability/plugins/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx
+++ b/x-pack/solutions/observability/plugins/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx
@@ -17,6 +17,8 @@ import {
import { i18n } from '@kbn/i18n';
import React from 'react';
import { Controller, useFormContext } from 'react-hook-form';
+import { DashboardsSelector } from '@kbn/dashboards-selector';
+import { useKibana } from '../../../hooks/use_kibana';
import { useFetchSLOSuggestions } from '../hooks/use_fetch_suggestions';
import type { CreateSLOForm } from '../types';
import { OptionalText } from './common/optional_text';
@@ -29,6 +31,7 @@ export function SloEditFormDescriptionSection() {
const tagsId = useGeneratedHtmlId({ prefix: 'tags' });
const { suggestions } = useFetchSLOSuggestions();
+ const { services } = useKibana();
return (
}
>
+ }
+ >
+ (
+ field.onChange(selected.map((d) => ({ id: d.value })))}
+ />
+ )}
+ />
+
);
}
@@ -157,3 +182,7 @@ function generateTagOptions(tags: string[] = []) {
'data-test-subj': `${tag}Option`,
}));
}
+
+const DASHBOARDS_COMBOBOX_PLACEHOLDER = i18n.translate('xpack.slo.sloEdit.dashboards.placeholder', {
+ defaultMessage: 'Add dashboards',
+});
diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slo_edit/helpers/process_slo_form_values.ts b/x-pack/solutions/observability/plugins/slo/public/pages/slo_edit/helpers/process_slo_form_values.ts
index 9033b0cf7be64..ed5172eff61ed 100644
--- a/x-pack/solutions/observability/plugins/slo/public/pages/slo_edit/helpers/process_slo_form_values.ts
+++ b/x-pack/solutions/observability/plugins/slo/public/pages/slo_edit/helpers/process_slo_form_values.ts
@@ -61,6 +61,9 @@ export function transformSloResponseToCreateSloForm(
: SETTINGS_DEFAULT_VALUES.frequency,
syncField: values.settings?.syncField ?? null,
},
+ artifacts: {
+ dashboards: values.artifacts?.dashboards || [],
+ },
};
}
@@ -93,6 +96,9 @@ export function transformCreateSLOFormToCreateSLOInput(values: CreateSLOForm): C
frequency: `${values.settings.frequency ?? SETTINGS_DEFAULT_VALUES.frequency}m`,
syncField: values.settings.syncField,
},
+ artifacts: {
+ dashboards: values.artifacts?.dashboards || [],
+ },
};
}
@@ -125,6 +131,9 @@ export function transformValuesToUpdateSLOInput(values: CreateSLOForm): UpdateSL
frequency: `${values.settings.frequency ?? SETTINGS_DEFAULT_VALUES.frequency}m`,
syncField: values.settings.syncField,
},
+ artifacts: {
+ dashboards: values.artifacts?.dashboards || [],
+ },
};
}
diff --git a/x-pack/solutions/observability/plugins/slo/public/pages/slo_edit/types.ts b/x-pack/solutions/observability/plugins/slo/public/pages/slo_edit/types.ts
index 9d887eaa303a5..a9018ef5c2017 100644
--- a/x-pack/solutions/observability/plugins/slo/public/pages/slo_edit/types.ts
+++ b/x-pack/solutions/observability/plugins/slo/public/pages/slo_edit/types.ts
@@ -29,4 +29,7 @@ export interface CreateSLOForm {
frequency: number; // in minutes
syncField: string | null;
};
+ artifacts?: {
+ dashboards?: { id: string }[];
+ };
}
diff --git a/x-pack/solutions/observability/plugins/slo/public/types.ts b/x-pack/solutions/observability/plugins/slo/public/types.ts
index 85b096ebf9bd6..a80d0aef484ef 100644
--- a/x-pack/solutions/observability/plugins/slo/public/types.ts
+++ b/x-pack/solutions/observability/plugins/slo/public/types.ts
@@ -54,6 +54,7 @@ import type {
import type { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin-types-public';
import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public';
import type { ApmSourceAccessPluginStart } from '@kbn/apm-sources-access-plugin/public';
+import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
import type { SLORouteRepository } from '../server/routes/get_slo_server_route_repository';
import type { SLOPlugin } from './plugin';
@@ -106,6 +107,7 @@ export interface SLOPublicPluginsStart {
security?: SecurityPluginStart;
fieldsMetadata: FieldsMetadataPublicStart;
apmSourcesAccess: ApmSourceAccessPluginStart;
+ contentManagement: ContentManagementPublicStart;
}
export type SLOPublicSetup = ReturnType;
diff --git a/x-pack/solutions/observability/plugins/slo/tsconfig.json b/x-pack/solutions/observability/plugins/slo/tsconfig.json
index e1c5a8552cd65..7a9f09203890c 100644
--- a/x-pack/solutions/observability/plugins/slo/tsconfig.json
+++ b/x-pack/solutions/observability/plugins/slo/tsconfig.json
@@ -108,5 +108,8 @@
"@kbn/lock-manager",
"@kbn/object-utils",
"@kbn/licensing-types",
+ "@kbn/deeplinks-analytics",
+ "@kbn/content-management-plugin",
+ "@kbn/dashboards-selector",
]
}