[AO][BUG] Disable view rule details when the rule is deleted (#163183)

## Summary

Fixes #163084

<img width="1397" alt="Screenshot 2023-08-04 at 17 33 34"
src="8075da4d-633d-4916-b6db-491f7c87c363">

### Release note
Disable the "View rule details" option from the Alert Details' Actions
list when the rule is deleted.
This commit is contained in:
Faisal Kanout 2023-08-08 16:04:54 +02:00 committed by GitHub
parent 69579014a3
commit 03303940f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 77 additions and 60 deletions

View file

@ -61,12 +61,10 @@ export function useFetchRule({ ruleId }: { ruleId?: string }): UseFetchRuleRespo
onError: (error: Error) => {
toasts.addError(error, {
title: i18n.translate('xpack.observability.ruleDetails.ruleLoadError', {
defaultMessage: 'Unable to load rule. Reason: {message}',
values: {
message:
error instanceof Error ? error.message : typeof error === 'string' ? error : '',
},
defaultMessage: 'Unable to load rule',
}),
toastMessage:
error instanceof Error ? error.message : typeof error === 'string' ? error : '',
});
},
}

View file

@ -65,13 +65,11 @@ export function useFetchRuleTypes({
refetchOnWindowFocus: false,
onError: (error: Error) => {
toasts.addError(error, {
title: i18n.translate('xpack.observability.ruleDetails.ruleLoadError', {
defaultMessage: 'Unable to load rule. Reason: {message}',
values: {
message:
error instanceof Error ? error.message : typeof error === 'string' ? error : '',
},
title: i18n.translate('xpack.observability.ruleDetails.ruleTypeLoadError', {
defaultMessage: 'Unable to load rule type.',
}),
toastMessage:
error instanceof Error ? error.message : typeof error === 'string' ? error : '',
});
},
}

View file

@ -14,13 +14,16 @@ import { render } from '../../../utils/test_helper';
import { useKibana } from '../../../utils/kibana_react';
import { kibanaStartMock } from '../../../utils/kibana_react.mock';
import { alertWithTags, mockAlertUuid } from '../mock/alert';
import { useFetchRule } from '../../../hooks/use_fetch_rule';
import { HeaderActions } from './header_actions';
import { CasesUiStart } from '@kbn/cases-plugin/public';
jest.mock('../../../utils/kibana_react');
jest.mock('../../../hooks/use_fetch_rule');
const useKibanaMock = useKibana as jest.Mock;
const useFetchRuleMock = useFetchRule as jest.Mock;
const mockCases = casesPluginMock.createStartContract();
const mockKibana = () => {
@ -33,61 +36,82 @@ const mockKibana = () => {
});
};
const ruleId = '123';
const ruleName = '456';
const mockRuleId = '123';
const mockRuleName = '456';
jest.mock('../../../hooks/use_fetch_rule', () => {
return {
useFetchRule: () => ({
reloadRule: jest.fn(),
rule: {
id: ruleId,
name: ruleName,
},
}),
};
});
const mockUseFetchRuleWithData = () => {
useFetchRuleMock.mockReturnValue({
reloadRule: jest.fn(),
rule: {
id: mockRuleId,
name: mockRuleName,
},
});
};
const mockUseFetchRuleWithoutData = () => {
useFetchRuleMock.mockReturnValue({
reloadRule: jest.fn(),
rule: null,
});
};
describe('Header Actions', () => {
beforeEach(() => {
afterAll(() => {
jest.clearAllMocks();
mockKibana();
});
it('should display an actions button', () => {
const { queryByTestId } = render(<HeaderActions alert={alertWithTags} />);
expect(queryByTestId('alert-details-header-actions-menu-button')).toBeTruthy();
});
describe('Header Actions - Enabled', () => {
beforeEach(() => {
mockKibana();
mockUseFetchRuleWithData();
});
describe('when clicking the actions button', () => {
it('should offer an "add to case" button which opens the add to case modal', async () => {
let attachments: any[] = [];
it('should display an actions button', () => {
const { queryByTestId } = render(<HeaderActions alert={alertWithTags} />);
expect(queryByTestId('alert-details-header-actions-menu-button')).toBeTruthy();
});
const useCasesAddToExistingCaseModalMock: any = jest.fn().mockImplementation(() => ({
open: ({ getAttachments }: { getAttachments: () => any[] }) => {
attachments = getAttachments();
},
})) as CasesUiStart['hooks']['useCasesAddToExistingCaseModal'];
describe('when clicking the actions button', () => {
it('should offer an "add to case" button which opens the add to case modal', async () => {
let attachments: any[] = [];
mockCases.hooks.useCasesAddToExistingCaseModal = useCasesAddToExistingCaseModalMock;
const { getByTestId, findByRole } = render(<HeaderActions alert={alertWithTags} />);
fireEvent.click(await findByRole('button', { name: 'Actions' }));
fireEvent.click(getByTestId('add-to-case-button'));
expect(attachments).toEqual([
{
alertId: mockAlertUuid,
index: '.internal.alerts-observability.metrics.alerts-*',
rule: {
id: ruleId,
name: ruleName,
const useCasesAddToExistingCaseModalMock: any = jest.fn().mockImplementation(() => ({
open: ({ getAttachments }: { getAttachments: () => any[] }) => {
attachments = getAttachments();
},
type: 'alert',
},
]);
})) as CasesUiStart['hooks']['useCasesAddToExistingCaseModal'];
mockCases.hooks.useCasesAddToExistingCaseModal = useCasesAddToExistingCaseModalMock;
const { getByTestId, findByRole } = render(<HeaderActions alert={alertWithTags} />);
fireEvent.click(await findByRole('button', { name: 'Actions' }));
fireEvent.click(getByTestId('add-to-case-button'));
expect(attachments).toEqual([
{
alertId: mockAlertUuid,
index: '.internal.alerts-observability.metrics.alerts-*',
rule: {
id: mockRuleId,
name: mockRuleName,
},
type: 'alert',
},
]);
});
});
});
describe('Header Actions - Disabled', () => {
beforeEach(() => {
mockKibana();
mockUseFetchRuleWithoutData();
});
it("should disable the 'View rule details' when the rule is not available/delete", async () => {
const { queryByTestId, findByRole } = render(<HeaderActions alert={alertWithTags} />);
fireEvent.click(await findByRole('button', { name: 'Actions' }));
expect(queryByTestId('view-rule-details-button')).toHaveAttribute('disabled');
});
});
});

View file

@ -95,7 +95,7 @@ export function HeaderActions({ alert }: HeaderActionsProps) {
<EuiButtonEmpty
size="s"
color="text"
disabled={!alert?.fields[ALERT_RULE_UUID]}
disabled={!alert?.fields[ALERT_RULE_UUID] || !rule}
onClick={handleViewRuleDetails}
data-test-subj="view-rule-details-button"
>

View file

@ -27279,7 +27279,6 @@
"xpack.observability.enableInfrastructureHostsViewDescription": "{betaLabel} Activez la vue \"Hôtes\" dans lapplication \"Infrastructure\".",
"xpack.observability.inspector.stats.queryTimeValue": "{queryTime} ms",
"xpack.observability.pages.alertDetails.pageTitle.title": "{ruleCategory} {ruleCategory, select, Anomaly {détecté} Inventory {seuil dépassé} other {dépassé}}",
"xpack.observability.ruleDetails.ruleLoadError": "Impossible de charger la règle. Raison : {message}",
"xpack.observability.slo.alerting.burnRate.reason": "{actionGroupName} : Le taux d'avancement pour le (les) dernier(s) {longWindowDuration} est de {longWindowBurnRate} et pour le (les) dernier(s) {shortWindowDuration} est de {shortWindowBurnRate}. Alerter si supérieur à {burnRateThreshold} pour les deux fenêtres",
"xpack.observability.slo.burnRateWindow.thresholdTip": "Le seuil est {target}x",
"xpack.observability.slo.clone.errorNotification": "Échec du clonage de {name}",

View file

@ -27279,7 +27279,6 @@
"xpack.observability.enableInfrastructureHostsViewDescription": "{betaLabel}インフラアプリでホストビューを有効にします。",
"xpack.observability.inspector.stats.queryTimeValue": "{queryTime}ms",
"xpack.observability.pages.alertDetails.pageTitle.title": "{ruleCategory} {ruleCategory, select, Anomaly {が検出されました} Inventory {しきい値を超えました} other {を超えました}}",
"xpack.observability.ruleDetails.ruleLoadError": "ルールを読み込めません。理由:{message}",
"xpack.observability.slo.alerting.burnRate.reason": "{actionGroupName}:過去{longWindowDuration}のバーンレートは{longWindowBurnRate}で、過去{shortWindowDuration}のバーンレートは{shortWindowBurnRate}です。両期間とも{burnRateThreshold}を超えたらアラート",
"xpack.observability.slo.burnRateWindow.thresholdTip": "しきい値は{target}xです",
"xpack.observability.slo.clone.errorNotification": "{name}を複製できませんでした",

View file

@ -27277,7 +27277,6 @@
"xpack.observability.enableInfrastructureHostsViewDescription": "{betaLabel} 在 Infrastructure 应用中启用主机视图。",
"xpack.observability.inspector.stats.queryTimeValue": "{queryTime}ms",
"xpack.observability.pages.alertDetails.pageTitle.title": "{ruleCategory} {ruleCategory, select, Anomaly {已检测到} Inventory {超出阈值} other {超出}}",
"xpack.observability.ruleDetails.ruleLoadError": "无法加载规则。原因:{message}",
"xpack.observability.slo.alerting.burnRate.reason": "{actionGroupName}:过去 {longWindowDuration} 的消耗速度为 {longWindowBurnRate} 且过去 {shortWindowDuration} 为 {shortWindowBurnRate}。两个窗口超出 {burnRateThreshold} 时告警",
"xpack.observability.slo.burnRateWindow.thresholdTip": "阈值为 {target}x",
"xpack.observability.slo.clone.errorNotification": "无法克隆 {name}",