Skip to content

Commit

Permalink
[RAM] Hide Logs tab in Rules page to unauthorized users, deduplicate …
Browse files Browse the repository at this point in the history
…rule types requests (#171417)

Closes #158256, #155394

## Summary

- Hides the Logs tab in the Stack Management > Rules page when the user
lacks the necessary permissions to avoid error messages (as shown in
#158256)
- Switches old `useLoadRuleTypes` hook usages to the new
`useLoadRuleTypesQuery` hook
- Assigns a staleTime to the rule types query to avoid duplicated
requests (as shown in #155394)

---------

Co-authored-by: Xavier Mouligneau <[email protected]>
  • Loading branch information
umbopepato and XavierM authored Dec 5, 2023
1 parent 727fb13 commit 0f5b544
Show file tree
Hide file tree
Showing 18 changed files with 542 additions and 383 deletions.
56 changes: 40 additions & 16 deletions x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import ActionForm from '@kbn/triggers-actions-ui-plugin/public/application/secti
import { Legacy } from '../legacy_shims';
import { I18nProvider } from '@kbn/i18n-react';
import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

interface AlertAction {
group: string;
Expand All @@ -43,9 +44,12 @@ const { loadActionTypes } = jest.requireMock(
'@kbn/triggers-actions-ui-plugin/public/application/lib/action_connector_api'
);

jest.mock('@kbn/triggers-actions-ui-plugin/public/application/lib/rule_api', () => ({
loadAlertTypes: jest.fn(),
}));
jest.mock(
'@kbn/triggers-actions-ui-plugin/public/application/hooks/use_load_rule_types_query',
() => ({
useLoadRuleTypesQuery: jest.fn(),
})
);

jest.mock('@kbn/kibana-react-plugin/public/ui_settings/use_ui_setting', () => ({
useUiSetting: jest.fn().mockImplementation((_, defaultValue) => defaultValue),
Expand Down Expand Up @@ -109,6 +113,14 @@ describe('alert_form', () => {
let wrapper: ReactWrapper<any>;

beforeEach(async () => {
const { useLoadRuleTypesQuery } = jest.requireMock(
'@kbn/triggers-actions-ui-plugin/public/application/hooks/use_load_rule_types_query'
);
useLoadRuleTypesQuery.mockReturnValue({
ruleTypesState: {
data: new Map(),
},
});
ruleTypeRegistry.list.mockReturnValue([ruleType]);
ruleTypeRegistry.get.mockReturnValue(ruleType);
ruleTypeRegistry.has.mockReturnValue(true);
Expand Down Expand Up @@ -136,19 +148,31 @@ describe('alert_form', () => {
wrapper = mountWithIntl(
<I18nProvider>
<KibanaReactContext.Provider>
<RuleForm
rule={initialAlert}
config={{
isUsingSecurity: true,
minimumScheduleInterval: { value: '1m', enforce: false },
}}
dispatch={() => {}}
errors={{ name: [], 'schedule.interval': [] }}
operation="create"
actionTypeRegistry={actionTypeRegistry}
ruleTypeRegistry={ruleTypeRegistry}
onChangeMetaData={() => {}}
/>
<QueryClientProvider
client={
new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
})
}
>
<RuleForm
rule={initialAlert}
config={{
isUsingSecurity: true,
minimumScheduleInterval: { value: '1m', enforce: false },
}}
dispatch={() => {}}
errors={{ name: [], 'schedule.interval': [] }}
operation="create"
actionTypeRegistry={actionTypeRegistry}
ruleTypeRegistry={ruleTypeRegistry}
onChangeMetaData={() => {}}
/>
</QueryClientProvider>
</KibanaReactContext.Provider>
</I18nProvider>
);
Expand Down
108 changes: 69 additions & 39 deletions x-pack/plugins/observability/public/pages/rules/rules.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jest.mock('../../utils/kibana_react', () => ({
jest.mock('@kbn/observability-shared-plugin/public');

jest.mock('@kbn/triggers-actions-ui-plugin/public', () => ({
useLoadRuleTypes: jest.fn(),
useLoadRuleTypesQuery: jest.fn(),
}));

jest.spyOn(pluginContext, 'usePluginContext').mockImplementation(() => ({
Expand All @@ -55,7 +55,7 @@ jest.spyOn(pluginContext, 'usePluginContext').mockImplementation(() => ({
plugins: {} as ObservabilityPublicPluginsStart,
}));

const { useLoadRuleTypes } = jest.requireMock('@kbn/triggers-actions-ui-plugin/public');
const { useLoadRuleTypesQuery } = jest.requireMock('@kbn/triggers-actions-ui-plugin/public');

describe('RulesPage with all capabilities', () => {
async function setup() {
Expand All @@ -65,41 +65,54 @@ describe('RulesPage with all capabilities', () => {
enabledInLicense: true,
id: '1',
name: 'test rule',
actionGroups: [{ id: 'default', name: 'Default' }],
recoveryActionGroup: { id: 'recovered', name: 'Recovered' },
actionVariables: { context: [], state: [] },
defaultActionGroupId: 'default',
producer: ALERTS_FEATURE_ID,
minimumLicenseRequired: 'basic',
authorizedConsumers: {
[ALERTS_FEATURE_ID]: { all: true },
},
ruleTaskTimeout: '1m',
},
'2': {
enabledInLicense: true,
id: '2',
name: 'test rule ok',
actionGroups: [{ id: 'default', name: 'Default' }],
recoveryActionGroup: { id: 'recovered', name: 'Recovered' },
actionVariables: { context: [], state: [] },
defaultActionGroupId: 'default',
producer: ALERTS_FEATURE_ID,
minimumLicenseRequired: 'basic',
authorizedConsumers: {
[ALERTS_FEATURE_ID]: { all: true },
},
ruleTaskTimeout: '1m',
},
'3': {
enabledInLicense: true,
id: '3',
name: 'test rule pending',
actionGroups: [{ id: 'default', name: 'Default' }],
recoveryActionGroup: { id: 'recovered', name: 'Recovered' },
actionVariables: { context: [], state: [] },
defaultActionGroupId: 'default',
producer: ALERTS_FEATURE_ID,
minimumLicenseRequired: 'basic',
authorizedConsumers: {
[ALERTS_FEATURE_ID]: { all: true },
},
ruleTaskTimeout: '1m',
},
})
);

const ruleTypes = [
{
id: 'test_rule_type',
name: 'some rule type',
actionGroups: [{ id: 'default', name: 'Default' }],
recoveryActionGroup: { id: 'recovered', name: 'Recovered' },
actionVariables: { context: [], state: [] },
defaultActionGroupId: 'default',
producer: ALERTS_FEATURE_ID,
minimumLicenseRequired: 'basic',
enabledInLicense: true,
authorizedConsumers: {
[ALERTS_FEATURE_ID]: { all: true },
},
ruleTaskTimeout: '1m',
useLoadRuleTypesQuery.mockReturnValue({
ruleTypesState: {
data: ruleTypeIndex,
},
];

useLoadRuleTypes.mockReturnValue({
ruleTypes,
ruleTypeIndex,
});

return render(
Expand Down Expand Up @@ -133,38 +146,55 @@ describe('RulesPage with show only capability', () => {
enabledInLicense: true,
id: '1',
name: 'test rule',
actionGroups: [{ id: 'default', name: 'Default' }],
recoveryActionGroup: { id: 'recovered', name: 'Recovered' },
actionVariables: { context: [], state: [] },
defaultActionGroupId: 'default',
producer: ALERTS_FEATURE_ID,
minimumLicenseRequired: 'basic',
authorizedConsumers: {
[ALERTS_FEATURE_ID]: { read: true, all: false },
},
ruleTaskTimeout: '1m',
},
'2': {
enabledInLicense: true,
actionGroups: [{ id: 'default', name: 'Default' }],
recoveryActionGroup: { id: 'recovered', name: 'Recovered' },
actionVariables: { context: [], state: [] },
defaultActionGroupId: 'default',
producer: ALERTS_FEATURE_ID,
minimumLicenseRequired: 'basic',
authorizedConsumers: {
[ALERTS_FEATURE_ID]: { read: true, all: false },
},
ruleTaskTimeout: '1m',
id: '2',
name: 'test rule ok',
},
'3': {
enabledInLicense: true,
id: '3',
name: 'test rule pending',
actionGroups: [{ id: 'default', name: 'Default' }],
recoveryActionGroup: { id: 'recovered', name: 'Recovered' },
actionVariables: { context: [], state: [] },
defaultActionGroupId: 'default',
producer: ALERTS_FEATURE_ID,
minimumLicenseRequired: 'basic',
authorizedConsumers: {
[ALERTS_FEATURE_ID]: { read: true, all: false },
},
ruleTaskTimeout: '1m',
},
})
);

const ruleTypes = [
{
id: 'test_rule_type',
name: 'some rule type',
actionGroups: [{ id: 'default', name: 'Default' }],
recoveryActionGroup: { id: 'recovered', name: 'Recovered' },
actionVariables: { context: [], state: [] },
defaultActionGroupId: 'default',
producer: ALERTS_FEATURE_ID,
minimumLicenseRequired: 'basic',
enabledInLicense: true,
authorizedConsumers: {
[ALERTS_FEATURE_ID]: { read: true, all: false },
},
ruleTaskTimeout: '1m',
useLoadRuleTypesQuery.mockReturnValue({
ruleTypesState: {
data: ruleTypeIndex,
},
];
useLoadRuleTypes.mockReturnValue({ ruleTypes, ruleTypeIndex });
});

return render(<RulesPage />);
}
Expand Down
6 changes: 4 additions & 2 deletions x-pack/plugins/observability/public/pages/rules/rules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import { useHistory } from 'react-router-dom';
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { useLoadRuleTypes } from '@kbn/triggers-actions-ui-plugin/public';
import { ALERTS_FEATURE_ID } from '@kbn/alerting-plugin/common';
import { useBreadcrumbs } from '@kbn/observability-shared-plugin/public';

import { AlertConsumers } from '@kbn/rule-data-utils';
import { useLoadRuleTypesQuery } from '@kbn/triggers-actions-ui-plugin/public';
import { RULES_LOGS_PATH, RULES_PATH } from '../../../common/locators/paths';
import { useKibana } from '../../utils/kibana_react';
import { usePluginContext } from '../../hooks/use_plugin_context';
Expand Down Expand Up @@ -57,7 +57,9 @@ export function RulesPage({ activeTab = RULES_TAB_NAME }: RulesPageProps) {
]);

const filteredRuleTypes = useGetFilteredRuleTypes();
const { ruleTypes } = useLoadRuleTypes({
const {
ruleTypesState: { data: ruleTypes },
} = useLoadRuleTypesQuery({
filteredRuleTypes,
});

Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/triggers_actions_ui/public/application/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { Storage } from '@kbn/kibana-utils-plugin/public';
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
import { ActionsPublicPluginSetup } from '@kbn/actions-plugin/public';
import { ruleDetailsRoute } from '@kbn/rule-data-utils';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { QueryClientProvider } from '@tanstack/react-query';
import { DashboardStart } from '@kbn/dashboard-plugin/public';
import { ExpressionsStart } from '@kbn/expressions-plugin/public';
import { suspendedComponentWithProps } from './lib/suspended_component_with_props';
Expand All @@ -43,12 +43,12 @@ import { setDataViewsService } from '../common/lib/data_apis';
import { KibanaContextProvider, useKibana } from '../common/lib/kibana';
import { ConnectorProvider } from './context/connector_context';
import { CONNECTORS_PLUGIN_ID } from '../common/constants';
import { queryClient } from './query_client';

const TriggersActionsUIHome = lazy(() => import('./home'));
const RuleDetailsRoute = lazy(
() => import('./sections/rule_details/components/rule_details_route')
);
const queryClient = new QueryClient();

export interface TriggersAndActionsUiServices extends CoreStart {
actions: ActionsPublicPluginSetup;
Expand Down
Loading

0 comments on commit 0f5b544

Please sign in to comment.