Skip to content

Commit 554ebbe

Browse files
[8.19] [One Discover] Handle Alerts and SLOs Privileges (#221786) (#222979)
# Backport This will backport the following commits from `main` to `8.19`: - [[One Discover] Handle Alerts and SLOs Privileges (#221786)](#221786) <!--- Backport version: 10.0.0 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"mohamedhamed-ahmed","email":"[email protected]"},"sourceCommit":{"committedDate":"2025-06-04T08:16:25Z","message":"[One Discover] Handle Alerts and SLOs Privileges (#221786)\n\n## Summary\n\ncloses https://github.com/elastic/kibana/issues/177067\ncloses https://github.com/elastic/kibana/issues/184564\n\nThis PR check on assigned privileges for the user to hide/show Alerts\nand SLOs depending on whether the user has access to them or not.\n\n---------\n\nCo-authored-by: kibanamachine <[email protected]>","sha":"7f5aa3e2692fd12cdff14847261952dc294391e4","branchLabelMapping":{"^v9.1.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Feature:Discover","release_note:skip","backport missing","Team:DataDiscovery","Team:obs-ux-logs","Project:OneDiscover","backport:version","v9.1.0","v8.19.0"],"title":"[One Discover] Handle Alerts and SLOs Privileges","number":221786,"url":"https://github.com/elastic/kibana/pull/221786","mergeCommit":{"message":"[One Discover] Handle Alerts and SLOs Privileges (#221786)\n\n## Summary\n\ncloses https://github.com/elastic/kibana/issues/177067\ncloses https://github.com/elastic/kibana/issues/184564\n\nThis PR check on assigned privileges for the user to hide/show Alerts\nand SLOs depending on whether the user has access to them or not.\n\n---------\n\nCo-authored-by: kibanamachine <[email protected]>","sha":"7f5aa3e2692fd12cdff14847261952dc294391e4"}},"sourceBranch":"main","suggestedTargetBranches":["8.19"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/221786","number":221786,"mergeCommit":{"message":"[One Discover] Handle Alerts and SLOs Privileges (#221786)\n\n## Summary\n\ncloses https://github.com/elastic/kibana/issues/177067\ncloses https://github.com/elastic/kibana/issues/184564\n\nThis PR check on assigned privileges for the user to hide/show Alerts\nand SLOs depending on whether the user has access to them or not.\n\n---------\n\nCo-authored-by: kibanamachine <[email protected]>","sha":"7f5aa3e2692fd12cdff14847261952dc294391e4"}},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
1 parent 7d8481e commit 554ebbe

File tree

13 files changed

+179
-158
lines changed

13 files changed

+179
-158
lines changed

src/platform/plugins/shared/discover/public/__mocks__/services.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
chromeServiceMock,
2020
coreMock,
2121
docLinksServiceMock,
22+
notificationServiceMock,
2223
scopedHistoryMock,
2324
themeServiceMock,
2425
} from '@kbn/core/public/mocks';
@@ -221,6 +222,9 @@ export function createDiscoverServicesMock(): DiscoverServices {
221222
addDanger: jest.fn(),
222223
addSuccess: jest.fn(),
223224
},
225+
notifications: {
226+
toasts: notificationServiceMock.createStartContract().toasts,
227+
},
224228
expressions: expressionsPlugin,
225229
savedObjectsTagging: {
226230
ui: {

src/platform/plugins/shared/discover/public/application/main/components/layout/discover_layout.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
SHOW_FIELD_STATISTICS,
3838
SORT_DEFAULT_ORDER_SETTING,
3939
} from '@kbn/discover-utils';
40+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4041
import { useSavedSearchInitial } from '../../state_management/discover_state_provider';
4142
import type { DiscoverStateContainer } from '../../state_management/discover_state';
4243
import { VIEW_MODE } from '../../../../../common/constants';
@@ -45,6 +46,7 @@ import { useDiscoverServices } from '../../../../hooks/use_discover_services';
4546
import { DiscoverNoResults } from '../no_results';
4647
import { LoadingSpinner } from '../loading_spinner/loading_spinner';
4748
import { DiscoverSidebarResponsive } from '../sidebar';
49+
import type { DiscoverTopNavProps } from '../top_nav/discover_topnav';
4850
import { DiscoverTopNav } from '../top_nav/discover_topnav';
4951
import { getResultState } from '../../utils/get_result_state';
5052
import { DiscoverUninitialized } from '../uninitialized/uninitialized';
@@ -64,7 +66,13 @@ import { useIsEsqlMode } from '../../hooks/use_is_esql_mode';
6466
import { useCurrentDataView, useInternalStateSelector } from '../../state_management/redux';
6567

6668
const SidebarMemoized = React.memo(DiscoverSidebarResponsive);
67-
const TopNavMemoized = React.memo(DiscoverTopNav);
69+
70+
const TopNavMemoized = React.memo((props: DiscoverTopNavProps) => (
71+
// QueryClientProvider is used to allow querying the authorized rules api hook
72+
<QueryClientProvider client={new QueryClient()}>
73+
<DiscoverTopNav {...props} />
74+
</QueryClientProvider>
75+
));
6876

6977
export interface DiscoverLayoutProps {
7078
stateContainer: DiscoverStateContainer;

src/platform/plugins/shared/discover/public/application/main/components/top_nav/app_menu_actions/get_alerts.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const mount = (dataView = dataViewMock, isEsqlMode = false) => {
2626
dataView,
2727
adHocDataViews: [],
2828
isEsqlMode,
29+
authorizedRuleTypeIds: [],
2930
onNewSearch: jest.fn(),
3031
onOpenSavedSearch: jest.fn(),
3132
onUpdateAdHocDataViews: jest.fn(),

src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav.test.tsx

Lines changed: 28 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import type { ReactElement } from 'react';
1111
import React from 'react';
12+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
1213
import { mountWithIntl } from '@kbn/test-jest-helpers';
1314
import { dataViewMock } from '@kbn/discover-utils/src/__mocks__';
1415
import type { DiscoverTopNavProps } from './discover_topnav';
@@ -83,6 +84,16 @@ function getProps(
8384
}
8485

8586
const mockUseKibana = useKibana as jest.Mock;
87+
const getTestComponent = (props: DiscoverTopNavProps) =>
88+
mountWithIntl(
89+
<DiscoverMainProvider value={props.stateContainer}>
90+
<RuntimeStateProvider currentDataView={dataViewMock} adHocDataViews={[]}>
91+
<QueryClientProvider client={new QueryClient()}>
92+
<DiscoverTopNav {...props} />
93+
</QueryClientProvider>
94+
</RuntimeStateProvider>
95+
</DiscoverMainProvider>
96+
);
8697

8798
describe('Discover topnav component', () => {
8899
beforeEach(() => {
@@ -112,41 +123,25 @@ describe('Discover topnav component', () => {
112123

113124
test('generated config of TopNavMenu config is correct when discover save permissions are assigned', () => {
114125
const props = getProps({ capabilities: { discover: { save: true } } });
115-
const component = mountWithIntl(
116-
<DiscoverMainProvider value={props.stateContainer}>
117-
<RuntimeStateProvider currentDataView={dataViewMock} adHocDataViews={[]}>
118-
<DiscoverTopNav {...props} />
119-
</RuntimeStateProvider>
120-
</DiscoverMainProvider>
121-
);
126+
const component = getTestComponent(props);
122127
const topNavMenu = component.find(TopNavMenu);
123128
const topMenuConfig = topNavMenu.props().config?.map((obj: TopNavMenuData) => obj.id);
124129
expect(topMenuConfig).toEqual(['inspect', 'new', 'open', 'share', 'save']);
125130
});
126131

127132
test('generated config of TopNavMenu config is correct when no discover save permissions are assigned', () => {
128133
const props = getProps({ capabilities: { discover: { save: false } } });
129-
const component = mountWithIntl(
130-
<DiscoverMainProvider value={props.stateContainer}>
131-
<RuntimeStateProvider currentDataView={dataViewMock} adHocDataViews={[]}>
132-
<DiscoverTopNav {...props} />
133-
</RuntimeStateProvider>
134-
</DiscoverMainProvider>
135-
);
134+
const component = getTestComponent(props);
135+
136136
const topNavMenu = component.find(TopNavMenu).props();
137137
const topMenuConfig = topNavMenu.config?.map((obj: TopNavMenuData) => obj.id);
138138
expect(topMenuConfig).toEqual(['inspect', 'new', 'open', 'share']);
139139
});
140140

141141
test('top nav is correct when discover saveQuery permission is granted', () => {
142142
const props = getProps({ capabilities: { discover: { saveQuery: true } } });
143-
const component = mountWithIntl(
144-
<DiscoverMainProvider value={props.stateContainer}>
145-
<RuntimeStateProvider currentDataView={dataViewMock} adHocDataViews={[]}>
146-
<DiscoverTopNav {...props} />
147-
</RuntimeStateProvider>
148-
</DiscoverMainProvider>
149-
);
143+
const component = getTestComponent(props);
144+
150145
const statefulSearchBar = component.find(
151146
mockDiscoverService.navigation.ui.AggregateQueryTopNavMenu
152147
);
@@ -155,13 +150,8 @@ describe('Discover topnav component', () => {
155150

156151
test('top nav is correct when discover saveQuery permission is not granted', () => {
157152
const props = getProps({ capabilities: { discover: { saveQuery: false } } });
158-
const component = mountWithIntl(
159-
<DiscoverMainProvider value={props.stateContainer}>
160-
<RuntimeStateProvider currentDataView={dataViewMock} adHocDataViews={[]}>
161-
<DiscoverTopNav {...props} />
162-
</RuntimeStateProvider>
163-
</DiscoverMainProvider>
164-
);
153+
const component = getTestComponent(props);
154+
165155
const statefulSearchBar = component.find(
166156
mockDiscoverService.navigation.ui.AggregateQueryTopNavMenu
167157
);
@@ -180,13 +170,8 @@ describe('Discover topnav component', () => {
180170
saveItem: { disabled: true },
181171
};
182172
const props = getProps();
183-
const component = mountWithIntl(
184-
<DiscoverMainProvider value={props.stateContainer}>
185-
<RuntimeStateProvider currentDataView={dataViewMock} adHocDataViews={[]}>
186-
<DiscoverTopNav {...props} />
187-
</RuntimeStateProvider>
188-
</DiscoverMainProvider>
189-
);
173+
const component = getTestComponent(props);
174+
190175
const topNavMenu = component.find(TopNavMenu);
191176
const topMenuConfig = topNavMenu.props().config?.map((obj: TopNavMenuData) => obj.id);
192177
expect(topMenuConfig).toEqual([]);
@@ -202,27 +187,16 @@ describe('Discover topnav component', () => {
202187
});
203188

204189
const props = getProps();
205-
const component = mountWithIntl(
206-
<DiscoverMainProvider value={props.stateContainer}>
207-
<RuntimeStateProvider currentDataView={dataViewMock} adHocDataViews={[]}>
208-
<DiscoverTopNav {...props} />
209-
</RuntimeStateProvider>
210-
</DiscoverMainProvider>
211-
);
190+
const component = getTestComponent(props);
212191

213192
expect(component.find({ 'data-test-subj': 'custom-search-bar' })).toHaveLength(1);
214193
});
215194

216195
it('should render CustomDataViewPicker', () => {
217196
mockUseCustomizations = true;
218197
const props = getProps();
219-
const component = mountWithIntl(
220-
<DiscoverMainProvider value={props.stateContainer}>
221-
<RuntimeStateProvider currentDataView={dataViewMock} adHocDataViews={[]}>
222-
<DiscoverTopNav {...props} />
223-
</RuntimeStateProvider>
224-
</DiscoverMainProvider>
225-
);
198+
const component = getTestComponent(props);
199+
226200
const topNav = component.find(mockDiscoverService.navigation.ui.AggregateQueryTopNavMenu);
227201
expect(topNav.prop('dataViewPickerComponentProps')).toBeUndefined();
228202
const dataViewPickerOverride = mountWithIntl(
@@ -239,13 +213,7 @@ describe('Discover topnav component', () => {
239213
});
240214

241215
const props = getProps();
242-
const component = mountWithIntl(
243-
<DiscoverMainProvider value={props.stateContainer}>
244-
<RuntimeStateProvider currentDataView={dataViewMock} adHocDataViews={[]}>
245-
<DiscoverTopNav {...props} />
246-
</RuntimeStateProvider>
247-
</DiscoverMainProvider>
248-
);
216+
const component = getTestComponent(props);
249217

250218
const topNav = component.find(mockDiscoverService.navigation.ui.AggregateQueryTopNavMenu);
251219
expect(topNav.prop('dataViewPickerComponentProps')).toBeUndefined();
@@ -255,13 +223,8 @@ describe('Discover topnav component', () => {
255223
describe('inline top nav', () => {
256224
it('should render top nav when inline top nav is not enabled', () => {
257225
const props = getProps();
258-
const component = mountWithIntl(
259-
<DiscoverMainProvider value={props.stateContainer}>
260-
<RuntimeStateProvider currentDataView={dataViewMock} adHocDataViews={[]}>
261-
<DiscoverTopNav {...props} />
262-
</RuntimeStateProvider>
263-
</DiscoverMainProvider>
264-
);
226+
const component = getTestComponent(props);
227+
265228
const searchBar = component.find(mockDiscoverService.navigation.ui.AggregateQueryTopNavMenu);
266229
expect(searchBar.prop('badges')).toBeDefined();
267230
expect(searchBar.prop('config')).toBeDefined();
@@ -271,13 +234,8 @@ describe('Discover topnav component', () => {
271234
it('should not render top nav when inline top nav is enabled', () => {
272235
const props = getProps();
273236
props.stateContainer.customizationContext.inlineTopNav.enabled = true;
274-
const component = mountWithIntl(
275-
<DiscoverMainProvider value={props.stateContainer}>
276-
<RuntimeStateProvider currentDataView={dataViewMock} adHocDataViews={[]}>
277-
<DiscoverTopNav {...props} />
278-
</RuntimeStateProvider>
279-
</DiscoverMainProvider>
280-
);
237+
const component = getTestComponent(props);
238+
281239
const searchBar = component.find(mockDiscoverService.navigation.ui.AggregateQueryTopNavMenu);
282240
expect(searchBar.prop('badges')).toBeUndefined();
283241
expect(searchBar.prop('config')).toBeUndefined();

src/platform/plugins/shared/discover/public/application/main/components/top_nav/discover_topnav_inline.test.tsx

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { DiscoverMainProvider } from '../../state_management/discover_state_prov
1212
import { DiscoverTopNavInline } from './discover_topnav_inline';
1313
import { getDiscoverStateMock } from '../../../../__mocks__/discover_state.mock';
1414
import { dataViewMock } from '@kbn/discover-utils/src/__mocks__';
15+
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
1516
import { discoverServiceMock as mockDiscoverService } from '../../../../__mocks__/services';
1617
import { useKibana } from '@kbn/kibana-react-plugin/public';
1718
import { render, screen, waitFor } from '@testing-library/react';
@@ -37,6 +38,14 @@ function getProps({ hideNavMenuItems }: { hideNavMenuItems?: boolean } = {}) {
3738

3839
const mockUseKibana = useKibana as jest.Mock;
3940

41+
const DiscoverTopNavInlineWrapper = ({ props }: { props: ReturnType<typeof getProps> }) => (
42+
<DiscoverMainProvider value={props.stateContainer}>
43+
<QueryClientProvider client={new QueryClient()}>
44+
<DiscoverTopNavInline {...props} />
45+
</QueryClientProvider>
46+
</DiscoverMainProvider>
47+
);
48+
4049
describe('DiscoverTopNavInline', () => {
4150
beforeEach(() => {
4251
jest.clearAllMocks();
@@ -48,46 +57,33 @@ describe('DiscoverTopNavInline', () => {
4857
it('should not render when top nav inline is not enabled', async () => {
4958
const props = getProps();
5059
props.stateContainer.customizationContext.inlineTopNav.enabled = false;
51-
render(
52-
<DiscoverMainProvider value={props.stateContainer}>
53-
<DiscoverTopNavInline {...props} />
54-
</DiscoverMainProvider>
55-
);
60+
render(<DiscoverTopNavInlineWrapper props={props} />);
5661
const topNav = screen.queryByTestId('discoverTopNavInline');
5762
expect(topNav).toBeNull();
5863
});
5964

6065
it('should render when top nav inline is enabled and displayMode is "standalone"', async () => {
6166
const props = getProps();
62-
render(
63-
<DiscoverMainProvider value={props.stateContainer}>
64-
<DiscoverTopNavInline {...props} />
65-
</DiscoverMainProvider>
66-
);
67+
render(<DiscoverTopNavInlineWrapper props={props} />);
68+
6769
const topNav = screen.queryByTestId('discoverTopNavInline');
6870
expect(topNav).not.toBeNull();
6971
});
7072

7173
it('should not render when top nav inline is enabled and displayMode is not "standalone"', async () => {
7274
const props = getProps();
7375
props.stateContainer.customizationContext.displayMode = 'embedded';
74-
render(
75-
<DiscoverMainProvider value={props.stateContainer}>
76-
<DiscoverTopNavInline {...props} />
77-
</DiscoverMainProvider>
78-
);
76+
render(<DiscoverTopNavInlineWrapper props={props} />);
77+
7978
const topNav = screen.queryByTestId('discoverTopNavInline');
8079
expect(topNav).toBeNull();
8180
});
8281

8382
describe('nav menu items', () => {
8483
it('should show nav menu items when hideNavMenuItems is false', async () => {
8584
const props = getProps();
86-
render(
87-
<DiscoverMainProvider value={props.stateContainer}>
88-
<DiscoverTopNavInline {...props} />
89-
</DiscoverMainProvider>
90-
);
85+
render(<DiscoverTopNavInlineWrapper props={props} />);
86+
9187
const topNav = screen.queryByTestId('discoverTopNavInline');
9288
expect(topNav).not.toBeNull();
9389
await waitFor(() => {
@@ -98,11 +94,8 @@ describe('DiscoverTopNavInline', () => {
9894

9995
it('should hide nav menu items when hideNavMenuItems is true', async () => {
10096
const props = getProps({ hideNavMenuItems: true });
101-
render(
102-
<DiscoverMainProvider value={props.stateContainer}>
103-
<DiscoverTopNavInline {...props} />
104-
</DiscoverMainProvider>
105-
);
97+
render(<DiscoverTopNavInlineWrapper props={props} />);
98+
10699
const topNav = screen.queryByTestId('discoverTopNavInline');
107100
expect(topNav).not.toBeNull();
108101
await waitFor(() => {
@@ -116,11 +109,8 @@ describe('DiscoverTopNavInline', () => {
116109
it('should render when showLogsExplorerTabs is true', async () => {
117110
const props = getProps();
118111
props.stateContainer.customizationContext.inlineTopNav.showLogsExplorerTabs = true;
119-
render(
120-
<DiscoverMainProvider value={props.stateContainer}>
121-
<DiscoverTopNavInline {...props} />
122-
</DiscoverMainProvider>
123-
);
112+
render(<DiscoverTopNavInlineWrapper props={props} />);
113+
124114
const topNav = screen.queryByTestId('discoverTopNavInline');
125115
expect(topNav).not.toBeNull();
126116
await waitFor(() => {
@@ -131,11 +121,8 @@ describe('DiscoverTopNavInline', () => {
131121

132122
it('should not render when showLogsExplorerTabs is false', async () => {
133123
const props = getProps();
134-
render(
135-
<DiscoverMainProvider value={props.stateContainer}>
136-
<DiscoverTopNavInline {...props} />
137-
</DiscoverMainProvider>
138-
);
124+
render(<DiscoverTopNavInlineWrapper props={props} />);
125+
139126
const topNav = screen.queryByTestId('discoverTopNavInline');
140127
expect(topNav).not.toBeNull();
141128
await waitFor(() => {

src/platform/plugins/shared/discover/public/application/main/components/top_nav/use_top_nav_links.test.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type { DiscoverServices } from '../../../../build_services';
1616
import { getDiscoverStateMock } from '../../../../__mocks__/discover_state.mock';
1717
import { createDiscoverServicesMock } from '../../../../__mocks__/services';
1818
import { DiscoverMainProvider } from '../../state_management/discover_state_provider';
19+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
1920

2021
describe('useTopNavLinks', () => {
2122
const services = {
@@ -36,7 +37,9 @@ describe('useTopNavLinks', () => {
3637
const Wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
3738
return (
3839
<KibanaContextProvider services={services}>
39-
<DiscoverMainProvider value={state}>{children}</DiscoverMainProvider>
40+
<QueryClientProvider client={new QueryClient()}>
41+
<DiscoverMainProvider value={state}>{children}</DiscoverMainProvider>
42+
</QueryClientProvider>
4043
</KibanaContextProvider>
4144
);
4245
};

0 commit comments

Comments
 (0)