mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-05 03:12:14 +00:00
fix(ui): handle alert form errors (#11623)
This commit is contained in:
@@ -701,6 +701,31 @@ describe("AlertFormModal", () => {
|
||||
expect(errorMessage).toHaveClass("text-text-error-primary");
|
||||
});
|
||||
|
||||
it("should clear the preview error when save shows the form error", async () => {
|
||||
// Given
|
||||
const user = userEvent.setup();
|
||||
alertsActionMocks.seedAlertRule.mockResolvedValue({
|
||||
error: "No alert-compatible filters",
|
||||
});
|
||||
mockRecipientsList();
|
||||
renderCreateModal({ editingAlert: createEditingAlert() });
|
||||
|
||||
// When
|
||||
await user.click(screen.getByRole("button", { name: /^test$/i }));
|
||||
expect(await screen.findByText("Test result")).toBeVisible();
|
||||
await user.click(screen.getByRole("button", { name: /^save$/i }));
|
||||
|
||||
// Then
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByText("Test result")).not.toBeInTheDocument(),
|
||||
);
|
||||
expect(
|
||||
screen.getAllByText(
|
||||
"Apply at least one alert-compatible Findings filter.",
|
||||
),
|
||||
).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("should hydrate advanced edit mode filters and normalize them on save", async () => {
|
||||
// Given
|
||||
const user = userEvent.setup();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { isValidElement, type ReactNode } from "react";
|
||||
import { isValidElement, type ReactNode, useState } from "react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import {
|
||||
@@ -8,6 +8,10 @@ import {
|
||||
ALERT_TRIGGER_KINDS,
|
||||
type AlertRule,
|
||||
} from "@/app/(prowler)/alerts/_types";
|
||||
import type {
|
||||
AlertFormSubmitResult,
|
||||
AlertFormValues,
|
||||
} from "@/app/(prowler)/alerts/_types/alert-form";
|
||||
|
||||
import { AlertsManager } from "../alerts-manager";
|
||||
|
||||
@@ -96,12 +100,32 @@ vi.mock("../alert-form-modal", () => ({
|
||||
open,
|
||||
editingAlert,
|
||||
onOpenChange,
|
||||
onSubmit,
|
||||
}: {
|
||||
open: boolean;
|
||||
editingAlert?: AlertRule | null;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}) =>
|
||||
open ? (
|
||||
onSubmit: (values: AlertFormValues) => Promise<AlertFormSubmitResult>;
|
||||
}) => {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const submit = async () => {
|
||||
const result = await onSubmit({
|
||||
name: "Updated alert",
|
||||
description: "",
|
||||
method: "email",
|
||||
frequency: ALERT_TRIGGER_KINDS.AFTER_SCAN,
|
||||
condition: {
|
||||
op: ALERT_AGGREGATE_OPS.ANY,
|
||||
filter: { severity: ["critical"] },
|
||||
},
|
||||
recipientEmails: [],
|
||||
enabled: true,
|
||||
});
|
||||
setError(result.ok ? null : (result.error ?? null));
|
||||
};
|
||||
|
||||
return open ? (
|
||||
<div
|
||||
role="dialog"
|
||||
aria-label={editingAlert ? "Edit Alert" : "Create Alert"}
|
||||
@@ -109,9 +133,14 @@ vi.mock("../alert-form-modal", () => ({
|
||||
<button type="button" onClick={() => onOpenChange(false)}>
|
||||
Close modal
|
||||
</button>
|
||||
<button type="button" onClick={submit}>
|
||||
Submit alert
|
||||
</button>
|
||||
{editingAlert?.attributes.name}
|
||||
{error && <p>{error}</p>}
|
||||
</div>
|
||||
) : null,
|
||||
) : null;
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../alerts-empty-state", () => ({
|
||||
@@ -259,6 +288,42 @@ describe("AlertsManager", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("shows a manage alerts permission message for edit 403 errors", async () => {
|
||||
// Given
|
||||
const user = userEvent.setup();
|
||||
const alert = makeAlert(true);
|
||||
actionMocks.updateAlert.mockResolvedValue({
|
||||
error: "You do not have permission to perform this action.",
|
||||
status: 403,
|
||||
});
|
||||
render(
|
||||
<AlertsManager
|
||||
alerts={[alert]}
|
||||
loadError={null}
|
||||
providers={[]}
|
||||
completedScanIds={[]}
|
||||
scanDetails={[]}
|
||||
uniqueRegions={[]}
|
||||
uniqueServices={[]}
|
||||
uniqueResourceTypes={[]}
|
||||
uniqueCategories={[]}
|
||||
uniqueGroups={[]}
|
||||
initialEditingAlert={alert}
|
||||
/>,
|
||||
);
|
||||
|
||||
// When
|
||||
await user.click(screen.getByRole("button", { name: /submit alert/i }));
|
||||
|
||||
// Then
|
||||
expect(
|
||||
await screen.findByText(
|
||||
"You don't have permission to manage alerts. Ask an administrator to update your role.",
|
||||
),
|
||||
).toBeVisible();
|
||||
expect(toastMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows a success toast after disabling an alert", async () => {
|
||||
// Given
|
||||
const user = userEvent.setup();
|
||||
|
||||
@@ -451,6 +451,7 @@ const AlertFormModalContent = ({
|
||||
? await seedAlertRule(pendingFilters)
|
||||
: null;
|
||||
if (seedResult?.error) {
|
||||
setPreview(null);
|
||||
setErrors({ root: ALERT_SEED_ERROR });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ interface AlertsManagerProps {
|
||||
|
||||
const ALERTS_FINDINGS_HREF =
|
||||
"/findings?filter[muted]=false&filter[status__in]=FAIL";
|
||||
const ALERTS_PERMISSION_ERROR =
|
||||
"You don't have permission to manage alerts. Ask an administrator to update your role.";
|
||||
|
||||
export const AlertsManager = ({
|
||||
alerts,
|
||||
@@ -108,7 +110,12 @@ export const AlertsManager = ({
|
||||
}
|
||||
const payload = toAlertPayload(values);
|
||||
const result = await updateAlert(editingAlert.id, payload);
|
||||
if (result?.error) return { ok: false, error: result.error };
|
||||
if (result?.error) {
|
||||
return {
|
||||
ok: false,
|
||||
error: result.status === 403 ? ALERTS_PERMISSION_ERROR : result.error,
|
||||
};
|
||||
}
|
||||
toast({
|
||||
title: "Alert updated",
|
||||
description: result.data.attributes.name,
|
||||
|
||||
Reference in New Issue
Block a user