Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
ba16762
add linked dashboards dropdown in the rule form
mgiota Apr 23, 2025
a25a162
Merge branch 'main' of github.com:elastic/kibana into linked_dashboar…
mgiota Apr 25, 2025
5ac42b5
Merge branch 'main' of github.com:elastic/kibana into linked_dashboar…
mgiota Apr 28, 2025
6e60602
basic UI showing related dashboards
mgiota Mar 21, 2025
53de12b
add actions
mgiota Mar 27, 2025
e96fdc1
Merge branch 'main' of github.com:elastic/kibana into linked_dashboar…
mgiota Apr 30, 2025
d326c5f
fix lint errors
mgiota Apr 30, 2025
0b8c050
[CI] Auto-commit changed files from 'node scripts/styled_components_m…
kibanamachine Apr 30, 2025
d2bba7f
remove duplicate action
mgiota Apr 30, 2025
02d173e
Merge branch 'linked_dashboards_ui' of github.com:mgiota/kibana into …
mgiota Apr 30, 2025
5e18c4f
fix types
mgiota May 5, 2025
01058f3
Merge branch 'main' of github.com:elastic/kibana into linked_dashboar…
mgiota May 5, 2025
ff35d41
unlink action
mgiota May 6, 2025
e505ba5
use updateRule api from response-ops-rule-form package
mgiota May 6, 2025
62088ee
fix failing unit tests
mgiota May 6, 2025
9d5aaa3
Merge branch 'main' into linked_dashboards_ui
elasticmachine May 6, 2025
7f8e493
fix types
mgiota May 6, 2025
651d889
completely remove actions
mgiota May 7, 2025
3da6049
Merge branch 'main' into linked_dashboards_ui
elasticmachine May 7, 2025
0931209
Merge branch 'main' into linked_dashboards_ui
elasticmachine May 7, 2025
beacd8b
Merge branch 'main' into linked_dashboards_ui
elasticmachine May 7, 2025
cf6cbd7
error handling
mgiota May 7, 2025
15b411a
refactor, use existing dashboard service in the alert details page
mgiota May 7, 2025
b142609
Merge branch 'main' into linked_dashboards_ui
elasticmachine May 7, 2025
b7e5dd4
remove unused import after refactoring
mgiota May 7, 2025
5c9b93a
fix wrong path
mgiota May 7, 2025
06bfa36
bring back FindDashboardsByIdResponse, it is used in alert details page
mgiota May 8, 2025
8648567
Merge branch 'main' into linked_dashboards_ui
elasticmachine May 8, 2025
64ac2e9
remove unnecessary await
mgiota May 8, 2025
af5c673
fix failing alert details tests
mgiota May 8, 2025
f4e9e04
fx synthetics tests
mgiota May 8, 2025
3504780
Merge branch 'main' into linked_dashboards_ui
elasticmachine May 19, 2025
21e9b85
Merge branch 'main' of github.com:elastic/kibana into linked_dashboar…
mgiota May 19, 2025
fb12054
Merge branch 'main' into linked_dashboards_ui
elasticmachine May 20, 2025
c636a86
remove double dashboard plugin
mgiota May 20, 2025
cd338aa
use contentManagement instead of dashboard dependency as an attempt t…
mgiota May 21, 2025
9f76798
[CI] Auto-commit changed files from 'node scripts/yarn_deduplicate'
kibanamachine May 21, 2025
400ae43
fix CI type issues
mgiota May 21, 2025
4fec3c8
Merge branch 'main' of github.com:elastic/kibana into linked_dashboar…
mgiota May 21, 2025
e490cc3
move linked dashboards to rule details
mgiota May 21, 2025
011b0f9
fix failing jest tests
mgiota May 21, 2025
6f2babc
pass contentManagement dependency to make linked dashboards appear in…
mgiota May 21, 2025
64cb433
Merge branch 'main' into linked_dashboards_ui
elasticmachine May 21, 2025
35a9b9c
[CI] Auto-commit changed files from 'node scripts/styled_components_m…
kibanamachine May 21, 2025
aa90535
Merge branch 'main' of github.com:elastic/kibana into linked_dashboar…
mgiota May 22, 2025
89ad5b8
increase line-height
mgiota May 22, 2025
7a16036
Merge branch 'main' into linked_dashboards_ui
elasticmachine May 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ export interface CreateRuleBody<Params extends RuleTypeParams = RuleTypeParams>
notifyWhen?: Rule<Params>['notifyWhen'];
alertDelay?: Rule<Params>['alertDelay'];
flapping?: Rule<Params>['flapping'];
artifacts?: Rule<Params>['artifacts'];
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export interface UpdateRuleBody<Params extends RuleTypeParams = RuleTypeParams>
notifyWhen?: Rule<Params>['notifyWhen'];
alertDelay?: Rule<Params>['alertDelay'];
flapping?: Rule<Params>['flapping'];
artifacts?: Rule<Params>['artifacts'];
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const UPDATE_FIELDS: Array<keyof UpdateRuleBody> = [
'params',
'alertDelay',
'flapping',
'artifacts',
];

export const UPDATE_FIELDS_WITH_ACTIONS: Array<keyof UpdateRuleBody> = [
Expand All @@ -33,6 +34,7 @@ export const UPDATE_FIELDS_WITH_ACTIONS: Array<keyof UpdateRuleBody> = [
'alertDelay',
'actions',
'flapping',
'artifacts',
];

export async function updateRule({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
*/

export * from './types';
export * from './services/dashboard_service';
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", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { dashboardServiceProvider } from './dashboard_service';
import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks';

describe('DashboardService', () => {
const contentManagement = contentManagementMock.createStartContract();
const dashboardService = dashboardServiceProvider(contentManagement);

test('should fetch dashboards', async () => {
// arrange
const searchMock = jest.spyOn(contentManagement.client, 'search').mockResolvedValue({
total: 0,
hits: [],
});

// act
const resp = await dashboardService.fetchDashboards({ text: 'test*' });

// assert
expect(searchMock).toHaveBeenCalledWith({
contentTypeId: 'dashboard',
query: {
text: 'test*',
},
options: {
fields: ['title', 'description'],
spaces: ['*'],
},
});
expect(resp).toEqual([]);

searchMock.mockRestore();
});

test('should fetch dashboard by id', async () => {
// mock get to resolve with a dashboard
const getMock = jest.spyOn(contentManagement.client, 'get').mockResolvedValue({
item: {
error: null,
attributes: {
title: 'Dashboard 1',
},
references: [],
},
});

// act
const resp = await dashboardService.fetchDashboard('1');

// assert
expect(getMock).toHaveBeenCalledWith({ contentTypeId: 'dashboard', id: '1' });
expect(resp).toEqual({
status: 'success',
id: '1',
attributes: {
title: 'Dashboard 1',
},
references: [],
});

getMock.mockRestore();
});

test('should return an error if dashboard id is not found', async () => {
const getMock = jest.spyOn(contentManagement.client, 'get').mockRejectedValue({
message: 'Dashboard not found',
});

const resp = await dashboardService.fetchDashboard('2');
expect(getMock).toHaveBeenCalledWith({ contentTypeId: 'dashboard', id: '2' });
expect(resp).toEqual({
status: 'error',
id: '2',
error: 'Dashboard not found',
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* 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", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import type { SearchQuery } from '@kbn/content-management-plugin/common';
import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
import type { Reference, ContentManagementCrudTypes } from '@kbn/content-management-utils';
import type { SavedObjectError } from '@kbn/core/public';
import type { GetIn } from '@kbn/content-management-plugin/common';

const DASHBOARD_CONTENT_TYPE_ID = 'dashboard';
export type DashboardGetIn = GetIn<typeof DASHBOARD_CONTENT_TYPE_ID>;

export type FindDashboardsByIdResponse = { id: string } & (
| { status: 'success'; attributes: any; references: Reference[] }
| { status: 'error'; error: SavedObjectError }
);

export interface DashboardItem {
id: string;
attributes: any; // DashboardAttributes is exported in the Dashboard plugin and this causes a cycle dependency. Get feedback on the best approach here
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nickpeihl DashboardAttributes is exported in the Dashboard plugin. I tried to search for any existing package that exports DashboardAttributes and I found @kbn/content-packs-schema

So here's what I tried:

In this file x-pack/platform/packages/shared/kbn-content-packs-schema/src/helpers/index.ts I exported export type { DashboardAttributes } from '@kbn/dashboard-plugin/common/content_management/v2'; and then I imported like this import type { DashboardAttributes } from '@kbn/content-packs-schema';

Then I ran yarn test:type_check and I was getting quite a few ts errors. I didn't push that code on Github, maybe CI would have autocommited some fix for me?

What do you recommend me to do here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer unknown over any

Suggested change
attributes: any; // DashboardAttributes is exported in the Dashboard plugin and this causes a cycle dependency. Get feedback on the best approach here
attributes: unknown; // DashboardAttributes is exported in the Dashboard plugin and this causes a cycle dependency. Get feedback on the best approach here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nickpeihl Shall I copy the types directly here?

import type { ControlGroupChainingSystem, ControlLabelPosition } from '@kbn/controls-plugin/common';
import type { RefreshInterval } from '@kbn/data-plugin/common';
interface ControlGroupAttributesV1 {
	chainingSystem?: ControlGroupChainingSystem;
	panelsJSON: string; // stringified version of ControlSerializedState
	ignoreParentSettingsJSON: string;
	controlStyle?: ControlLabelPosition;
}
export interface DashboardAttributes {
	controlGroupInput?: ControlGroupAttributesV1;
	refreshInterval?: RefreshInterval;
	timeRestore: boolean;
	optionsJSON?: string;
	useMargins?: boolean;
	description: string;
	panelsJSON: string;
	timeFrom?: string;
	version?: number;
	timeTo?: string;
	title: string;
	kibanaSavedObjectMeta: {
		searchSourceJSON: string;
	};
}

}

export type DashboardService = ReturnType<typeof dashboardServiceProvider>;
export type DashboardItems = Awaited<ReturnType<DashboardService['fetchDashboards']>>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL Waited


export function dashboardServiceProvider(contentManagementService: ContentManagementPublicStart) {
return {
/**
* Fetch dashboards
* @param query - The query to search for dashboards
* @returns - The dashboards that match the query
*/
async fetchDashboards(query: SearchQuery = {}) {
const response = await contentManagementService.client.search({
contentTypeId: 'dashboard',
query,
options: { spaces: ['*'], fields: ['title', 'description'] },
});

// Assert the type of response to access hits property
return (response as { hits: DashboardItem[] }).hits;
},
/**
* Fetch dashboard by id
* @param id - The id of the dashboard to fetch
* @returns - The dashboard with the given id
* @throws - An error if the dashboard does not exist
*/
async fetchDashboard(id: string): Promise<FindDashboardsByIdResponse> {
try {
const response = await contentManagementService.client.get<
DashboardGetIn,
ContentManagementCrudTypes<
typeof DASHBOARD_CONTENT_TYPE_ID,
any,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unknown better than any

object,
object,
object
>['GetOut']
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is GetOut? There's a property on ContentmanagementCrudTypes called GetOut?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, here's the GetOut property on ContentmanagementCrudTypes

>({
contentTypeId: 'dashboard',
id,
});
if (response.item.error) {
throw response.item.error;
}

return {
id,
status: 'success',
attributes: response.item.attributes,
references: response.item.references,
};
} catch (error) {
return {
status: 'error',
error: error.body || error.message,
id,
};
}
},

async fetchDashboardsByIds(ids: string[]) {
const findPromises = ids.map((id) => this.fetchDashboard(id));
const results = await Promise.all(findPromises);
return results as FindDashboardsByIdResponse[];
},
/**
* Fetch only the dashboards that still exist
* @param ids - The ids of the dashboards to fetch
* @returns - The dashboards that exist
*/
async fetchValidDashboards(ids: string[]) {
const responses = await this.fetchDashboardsByIds(ids);
const existingDashboards = responses.filter(({ status }) => status === 'success');
return existingDashboards;
},
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export const CreateRuleForm = (props: CreateRuleFormProps) => {
actions: newFormData.actions,
alertDelay: newFormData.alertDelay,
flapping: newFormData.flapping,
artifacts: newFormData.artifacts,
},
});
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export const EditRuleForm = (props: EditRuleFormProps) => {
actions: newFormData.actions,
alertDelay: newFormData.alertDelay,
flapping: newFormData.flapping,
artifacts: newFormData.artifacts,
},
});
},
Expand Down
Loading