Skip to content

Commit a3bc5c2

Browse files
[Alert details] Related dashboards tags are shown (#228902)
This PR closes #212131 Before: <img width="1510" height="824" alt="Screenshot 2025-07-22 at 09 46 01" src="https://github.com/user-attachments/assets/1e86d302-099d-423d-ac8a-0d1a66105dd2" /> After: <img width="1512" height="828" alt="Screenshot 2025-07-22 at 09 47 24" src="https://github.com/user-attachments/assets/982ca76e-2356-4577-884d-8e81b68333c5" /> ### **Acceptance criteria**: - Dashboard tags should appear for both linked dashboards and suggested dashboards when they are shown on the alert details page "related dashboards" tab ✅ --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
1 parent cb9122d commit a3bc5c2

File tree

16 files changed

+101
-58
lines changed

16 files changed

+101
-58
lines changed

x-pack/solutions/observability/packages/kbn-observability-schema/related_dashboards/latest.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77

88
export { type RelevantPanel, relevantPanelSchema } from './schema/relevant_panel/v1';
99
export {
10-
type RelatedDashboard,
10+
type LinkedDashboard,
1111
type SuggestedDashboard,
12-
relatedDashboardSchema,
12+
type RelatedDashboard,
13+
linkedDashboardSchema,
1314
suggestedDashboardSchema,
1415
} from './schema/related_dashboard/v1';
1516
export {

x-pack/solutions/observability/packages/kbn-observability-schema/related_dashboards/rest_specs/get_related_dashboards/v1.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import { z } from '@kbn/zod';
9-
import { relatedDashboardSchema } from '../../schema/related_dashboard/v1';
9+
import { linkedDashboardSchema, suggestedDashboardSchema } from '../../schema/related_dashboard/v1';
1010

1111
export const getRelatedDashboardsParamsSchema = z.object({
1212
query: z.object({
@@ -15,8 +15,8 @@ export const getRelatedDashboardsParamsSchema = z.object({
1515
});
1616

1717
export const getRelatedDashboardsResponseSchema = z.object({
18-
suggestedDashboards: z.array(relatedDashboardSchema),
19-
linkedDashboards: z.array(relatedDashboardSchema),
18+
suggestedDashboards: z.array(suggestedDashboardSchema),
19+
linkedDashboards: z.array(linkedDashboardSchema),
2020
});
2121

2222
export type GetRelatedDashboardsResponse = z.output<typeof getRelatedDashboardsResponseSchema>;

x-pack/solutions/observability/packages/kbn-observability-schema/related_dashboards/schema/related_dashboard/latest.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

x-pack/solutions/observability/packages/kbn-observability-schema/related_dashboards/schema/related_dashboard/v1.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@
88
import { z } from '@kbn/zod';
99
import { relevantPanelSchema } from '../relevant_panel/latest';
1010

11-
export const relatedDashboardSchema = z.object({
11+
const commonDashboardSchema = {
1212
id: z.string(),
1313
title: z.string(),
1414
description: z.string(),
15+
tags: z.array(z.string()).optional(),
16+
};
17+
18+
export const linkedDashboardSchema = z.object({
19+
...commonDashboardSchema,
1520
matchedBy: z.object({
1621
fields: z.array(z.string()).optional(),
1722
index: z.array(z.string()).optional(),
@@ -22,9 +27,7 @@ export const relatedDashboardSchema = z.object({
2227
});
2328

2429
export const suggestedDashboardSchema = z.object({
25-
id: z.string(),
26-
title: z.string(),
27-
description: z.string(),
30+
...commonDashboardSchema,
2831
matchedBy: z.object({
2932
fields: z.array(z.string()).optional(),
3033
index: z.array(z.string()).optional(),
@@ -34,5 +37,6 @@ export const suggestedDashboardSchema = z.object({
3437
score: z.number(),
3538
});
3639

37-
export type RelatedDashboard = z.output<typeof relatedDashboardSchema>;
40+
export type LinkedDashboard = z.output<typeof linkedDashboardSchema>;
3841
export type SuggestedDashboard = z.output<typeof suggestedDashboardSchema>;
42+
export type RelatedDashboard = LinkedDashboard | SuggestedDashboard;

x-pack/solutions/observability/plugins/observability/kibana.jsonc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
"licensing",
4444
"navigation",
4545
"fieldsMetadata",
46-
"esql"
46+
"esql",
47+
"savedObjectsTagging",
4748
],
4849
"optionalPlugins": [
4950
"aiops",

x-pack/solutions/observability/plugins/observability/public/pages/alert_details/alert_details.test.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { render } from '../../utils/test_helper';
2828
import { AlertDetails } from './alert_details';
2929
import { alertDetail, alertWithNoData } from './mock/alert';
3030
import { createTelemetryClientMock } from '../../services/telemetry/telemetry_client.mock';
31+
import type { SavedObjectReference } from '@kbn/core/server';
3132

3233
jest.mock('react-router-dom', () => ({
3334
...jest.requireActual('react-router-dom'),
@@ -65,6 +66,7 @@ jest.mock('./hooks/use_related_dashboards', () => ({
6566
id: 'suggested-dashboard-1',
6667
title: 'Suggested Dashboard 1',
6768
description: 'A suggested dashboard for testing',
69+
tags: ['SuggestedTag', 'SecondTag'],
6870
},
6971
],
7072
linkedDashboards: [
@@ -92,6 +94,10 @@ const mockSpaces = {
9294
}),
9395
};
9496

97+
const mockConvertNameToReference = jest
98+
.fn()
99+
.mockImplementation((value: string) => ({ id: value, type: value }));
100+
95101
const mockKibana = () => {
96102
useKibanaMock.mockReturnValue({
97103
services: {
@@ -109,6 +115,28 @@ const mockKibana = () => {
109115
dashboard: {},
110116
spaces: mockSpaces,
111117
telemetryClient: createTelemetryClientMock(),
118+
savedObjectsTagging: {
119+
ui: {
120+
convertNameToReference: (value: string) => mockConvertNameToReference(value),
121+
components: {
122+
TagList: ({
123+
object,
124+
}: {
125+
object: {
126+
references: SavedObjectReference[];
127+
};
128+
}) => {
129+
return (
130+
<div data-test-subj="tagList">
131+
{object.references.map(({ name }) => (
132+
<div>{name}</div>
133+
))}
134+
</div>
135+
);
136+
},
137+
},
138+
},
139+
},
112140
},
113141
});
114142
};
@@ -273,5 +301,10 @@ describe('Alert details', () => {
273301
expect(
274302
alertDetails.queryByTestId('addSuggestedDashboard_alertDetailsPage_custom_threshold')
275303
).toBeTruthy();
304+
305+
// Verify that tags are displayed
306+
expect(mockConvertNameToReference).toHaveBeenNthCalledWith(1, 'SuggestedTag');
307+
expect(mockConvertNameToReference).toHaveBeenNthCalledWith(2, 'SecondTag');
308+
expect(alertDetails.queryByTestId('tagList')).toBeTruthy();
276309
});
277310
});

x-pack/solutions/observability/plugins/observability/public/pages/alert_details/components/related_dashboards.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
import React, { useMemo } from 'react';
99
import { i18n } from '@kbn/i18n';
1010
import { Rule } from '@kbn/triggers-actions-ui-plugin/public';
11+
import type { LinkedDashboard, SuggestedDashboard } from '@kbn/observability-schema';
1112
import { DashboardTiles } from './related_dashboards/dashboard_tiles';
12-
import { DashboardMetadata } from './related_dashboards/dashboard_tile';
1313
import { useAddSuggestedDashboards } from '../hooks/use_add_suggested_dashboard';
1414

1515
interface RelatedDashboardsProps {
1616
rule: Rule;
17-
suggestedDashboards?: DashboardMetadata[];
18-
linkedDashboards?: DashboardMetadata[];
17+
suggestedDashboards?: SuggestedDashboard[];
18+
linkedDashboards?: LinkedDashboard[];
1919
isLoadingRelatedDashboards: boolean;
2020
onSuccessAddSuggestedDashboard: () => Promise<void>;
2121
}

x-pack/solutions/observability/plugins/observability/public/pages/alert_details/components/related_dashboards/dashboard_tile.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,12 @@ import {
1616
EuiButtonEmpty,
1717
EuiLink,
1818
} from '@elastic/eui';
19+
import { SavedObjectsReference } from '@kbn/content-management-content-editor';
20+
import type { RelatedDashboard } from '@kbn/observability-schema';
1921
import { useKibana } from '../../../../utils/kibana_react';
20-
export interface DashboardMetadata {
21-
id: string;
22-
title: string;
23-
description: string;
24-
}
2522

2623
export interface ActionButtonProps {
27-
onClick: (dashboard: DashboardMetadata) => void;
24+
onClick: (dashboard: RelatedDashboard) => void;
2825
label: string;
2926
isLoading: boolean;
3027
isDisabled: boolean;
@@ -35,20 +32,26 @@ export function DashboardTile({
3532
dashboard,
3633
actionButtonProps,
3734
}: {
38-
dashboard: DashboardMetadata;
35+
dashboard: RelatedDashboard;
3936
actionButtonProps?: ActionButtonProps;
4037
}) {
4138
const {
4239
services: {
4340
share: { url: urlService },
41+
savedObjectsTagging: { ui: savedObjectsTaggingUi },
4442
},
4543
} = useKibana();
4644
const dashboardLocator = urlService.locators.get<DashboardLocatorParams>(DASHBOARD_APP_LOCATOR);
4745

46+
const tagsReferences: SavedObjectsReference[] = (dashboard.tags || []).flatMap((tag) => {
47+
const ref = savedObjectsTaggingUi.convertNameToReference(tag);
48+
return ref ? [{ ...ref, name: tag }] : [];
49+
});
50+
4851
return (
4952
<>
50-
<EuiFlexGroup gutterSize="xs" responsive={false} key={dashboard.id}>
51-
<EuiFlexItem key={dashboard.id}>
53+
<EuiFlexGroup gutterSize="xs" responsive={false} key={dashboard.id} alignItems="center">
54+
<EuiFlexGroup key={dashboard.id} gutterSize="s" direction="column">
5255
<EuiLink
5356
data-test-subj="o11yDashboardTileLink"
5457
href={dashboardLocator?.getRedirectUrl({
@@ -61,7 +64,14 @@ export function DashboardTile({
6164
<EuiText color={'subdued'} size="s">
6265
{dashboard.description}
6366
</EuiText>
64-
</EuiFlexItem>
67+
{tagsReferences.length ? (
68+
<savedObjectsTaggingUi.components.TagList
69+
object={{
70+
references: tagsReferences,
71+
}}
72+
/>
73+
) : null}
74+
</EuiFlexGroup>
6575
{actionButtonProps ? (
6676
<EuiFlexItem grow={false}>
6777
<EuiButtonEmpty

x-pack/solutions/observability/plugins/observability/public/pages/alert_details/components/related_dashboards/dashboard_tiles.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import {
1616
EuiLoadingSpinner,
1717
EuiText,
1818
} from '@elastic/eui';
19-
import { ActionButtonProps, DashboardTile, DashboardMetadata } from './dashboard_tile';
19+
import type { RelatedDashboard } from '@kbn/observability-schema';
20+
import { ActionButtonProps, DashboardTile } from './dashboard_tile';
2021

2122
export function DashboardTiles({
2223
title,
@@ -26,7 +27,7 @@ export function DashboardTiles({
2627
}: {
2728
title: string;
2829
isLoadingDashboards: boolean;
29-
dashboards?: Array<DashboardMetadata & { actionButtonProps?: ActionButtonProps }>;
30+
dashboards?: Array<RelatedDashboard & { actionButtonProps?: ActionButtonProps }>;
3031
dataTestSubj: string;
3132
}) {
3233
const wrapWithHeader = (component: React.ReactNode) => {

x-pack/solutions/observability/plugins/observability/public/pages/alert_details/hooks/use_add_suggested_dashboard.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { renderHook, act } from '@testing-library/react';
99
import { Rule } from '@kbn/triggers-actions-ui-plugin/public';
1010
import { useAddSuggestedDashboards } from './use_add_suggested_dashboard';
1111
import { kibanaStartMock } from '../../../utils/kibana_react.mock';
12-
import { DashboardMetadata } from '../components/related_dashboards/dashboard_tile';
12+
import type { RelatedDashboard } from '@kbn/observability-schema';
1313

1414
const mockUseKibanaReturnValue = kibanaStartMock.startContract();
1515
let capturedOnSuccess: (data: Rule) => Promise<void> | undefined;
@@ -54,11 +54,11 @@ const mockRule = {
5454

5555
const mockOnSuccessAddSuggestedDashboard = jest.fn();
5656

57-
const mockDashboard: DashboardMetadata = {
57+
const mockDashboard = {
5858
id: TEST_DASHBOARD.id,
5959
title: TEST_DASHBOARD.title,
6060
description: TEST_DASHBOARD.description,
61-
};
61+
} as RelatedDashboard;
6262

6363
describe('useAddSuggestedDashboards', () => {
6464
beforeEach(() => {

0 commit comments

Comments
 (0)