Confirm before removing audit webhook URLs

The remove (×) button on each configured audit-webhook URL called
handleRemoveWebhook immediately — a single accidental click stopped
audit deliveries to that endpoint, breaking any external
SIEM/SOC/log-aggregation receiver that depends on Pulse's stream.

Add a confirmation Dialog matching the pattern from
APITokenManager (2a24a505e) and SSO Providers panel: clicking the
trash icon now opens "Remove audit webhook?" modal that names the
URL and explains the consequence; the user has to press "Remove
webhook" to actually trigger the delete. Cancel or backdrop-click
dismisses without action.

AgentProfilesPanel and AIProviderConfigurationSection already use
native confirm() for their destructive actions — no change needed
there.
This commit is contained in:
rcourtman
2026-05-10 16:38:58 +01:00
parent d4efc08909
commit 8cb2f2d66b
@@ -1,10 +1,11 @@
import { For, Show, type Component } from 'solid-js';
import { For, Show, createSignal, type Component } from 'solid-js';
import Shield from 'lucide-solid/icons/shield';
import Globe from 'lucide-solid/icons/globe';
import Plus from 'lucide-solid/icons/plus';
import Trash2 from 'lucide-solid/icons/trash-2';
import ExternalLink from 'lucide-solid/icons/external-link';
import { Card } from '@/components/shared/Card';
import { Dialog } from '@/components/shared/Dialog';
import { UpgradeLink } from '@/components/shared/UpgradeLink';
import SettingsPanel from '@/components/shared/SettingsPanel';
import { formControl } from '@/components/shared/Form';
@@ -26,6 +27,7 @@ interface AuditWebhookPanelProps {
}
export const AuditWebhookPanel: Component<AuditWebhookPanelProps> = (props) => {
const [urlToRemove, setUrlToRemove] = createSignal<string | null>(null);
const {
canManage,
handleAddWebhook,
@@ -114,7 +116,7 @@ export const AuditWebhookPanel: Component<AuditWebhookPanelProps> = (props) => {
</span>
</div>
<button
onClick={() => handleRemoveWebhook(url)}
onClick={() => setUrlToRemove(url)}
disabled={!canManage()}
class="p-2 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900 rounded-md transition-colors"
title="Remove webhook endpoint"
@@ -169,6 +171,48 @@ export const AuditWebhookPanel: Component<AuditWebhookPanelProps> = (props) => {
</div>
</div>
</Card>
{/* Remove confirmation modal — webhook removal stops audit
deliveries to that endpoint, so guard the action behind
an explicit confirm. */}
<Show when={urlToRemove()}>
<Dialog
isOpen={true}
onClose={() => setUrlToRemove(null)}
panelClass="max-w-md"
ariaLabel="Remove audit webhook"
>
<div class="w-full p-6">
<h3 class="text-lg font-semibold text-base-content mb-2">Remove audit webhook?</h3>
<p class="text-sm text-muted mb-4">
This stops audit events from being delivered to{' '}
<span class="font-medium text-base-content break-all">{urlToRemove()}</span>. Any
external receiver using this URL will stop receiving Pulse audit traffic. You can
add the URL back later if needed.
</p>
<div class="flex justify-end gap-3">
<button
type="button"
onClick={() => setUrlToRemove(null)}
class="px-4 py-2 text-sm font-medium text-base-content border border-border rounded-md hover:bg-surface-hover"
>
Cancel
</button>
<button
type="button"
onClick={() => {
const url = urlToRemove();
setUrlToRemove(null);
if (url) void handleRemoveWebhook(url);
}}
class="px-4 py-2 text-sm font-medium bg-red-600 text-white rounded-md hover:bg-red-700"
>
Remove webhook
</button>
</div>
</div>
</Dialog>
</Show>
</div>
);
};