fix: use ConfirmDialog for dismiss, move warning to top of page
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m20s
CI / docker (push) Successful in 1m8s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 41s

Replace window.confirm with design system ConfirmDialog for the dismiss
action. Move the "No agents connected" section to the top of the Runtime
page using Alert component with warning variant.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-12 16:43:05 +02:00
parent 5724b8459d
commit 5b6543b167

View File

@@ -5,6 +5,7 @@ import {
StatCard, StatusDot, Badge, MonoText,
GroupCard, DataTable, EventFeed,
LogViewer, ButtonGroup, SectionHeader, Toggle, Select, Button, useToast,
Alert, ConfirmDialog,
} from '@cameleer/design-system';
import type { Column, FeedEvent, LogEntry, ButtonGroupItem } from '@cameleer/design-system';
import styles from './AgentHealth.module.css';
@@ -111,6 +112,7 @@ export default function AgentHealth() {
const dismissApp = useDismissApp();
const catalogEntry = catalogApps?.find((a) => a.slug === appId);
const [confirmDismissOpen, setConfirmDismissOpen] = useState(false);
const [configEditing, setConfigEditing] = useState(false);
const [configDraft, setConfigDraft] = useState<Record<string, string | boolean>>({});
@@ -292,6 +294,46 @@ export default function AgentHealth() {
return (
<div className={styles.content}>
{/* No agents warning + dismiss — shown when app-scoped, no agents, admin */}
{appId && agentList.length === 0 && isAdmin && (
<>
<Alert variant="warning" title="No agents connected">
<span>
{catalogEntry?.managed ? 'Managed app' : 'Discovered app'} &mdash; {(catalogEntry?.exchangeCount ?? 0).toLocaleString()} exchanges recorded.
{' '}You can dismiss this application to remove it and all associated data.
</span>
<div style={{ marginTop: 8 }}>
<Button variant="danger" size="sm" disabled={dismissApp.isPending}
onClick={() => setConfirmDismissOpen(true)}>
{dismissApp.isPending ? 'Dismissing\u2026' : 'Dismiss Application'}
</Button>
</div>
</Alert>
<ConfirmDialog
open={confirmDismissOpen}
onClose={() => setConfirmDismissOpen(false)}
onConfirm={() => {
setConfirmDismissOpen(false);
dismissApp.mutate(appId, {
onSuccess: () => {
toast({ title: 'Application dismissed', description: `${appId} and all associated data have been deleted`, variant: 'success' });
navigate('/runtime');
},
onError: (err) => {
toast({ title: 'Dismiss failed', description: err.message, variant: 'error', duration: 86_400_000 });
},
});
}}
title="Dismiss Application"
message={`This will permanently delete "${appId}" and all associated data (${(catalogEntry?.exchangeCount ?? 0).toLocaleString()} exchanges, logs, diagrams).`}
confirmText="This action cannot be undone."
confirmLabel="Dismiss"
variant="danger"
loading={dismissApp.isPending}
/>
</>
)}
{/* Stat strip */}
<div className={styles.statStrip}>
<StatCard
@@ -476,45 +518,6 @@ export default function AgentHealth() {
</div>
)}
{/* Dismiss application card — shown when app-scoped, no agents, admin */}
{appId && agentList.length === 0 && isAdmin && (
<div className={`${sectionStyles.section}`} style={{ marginBottom: 16, padding: '16px 20px' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div>
<strong>No agents connected</strong>
{catalogEntry && (
<span style={{ marginLeft: 8, color: 'var(--text-muted)', fontSize: 13 }}>
{catalogEntry.managed ? 'Managed app' : 'Discovered app'} &mdash; {catalogEntry.exchangeCount.toLocaleString()} exchanges recorded
</span>
)}
</div>
<Button
variant="danger"
size="sm"
disabled={dismissApp.isPending}
onClick={() => {
const count = catalogEntry?.exchangeCount ?? 0;
const ok = window.confirm(
`Dismiss "${appId}" and permanently delete all data (${count.toLocaleString()} exchanges)?\n\nThis action cannot be undone.`
);
if (ok) {
dismissApp.mutate(appId, {
onSuccess: () => {
toast({ title: 'Application dismissed', description: `${appId} and all associated data have been deleted`, variant: 'success' });
navigate('/runtime');
},
onError: (err) => {
toast({ title: 'Dismiss failed', description: err.message, variant: 'error', duration: 86_400_000 });
},
});
}
}}
>
{dismissApp.isPending ? 'Dismissing\u2026' : 'Dismiss Application'}
</Button>
</div>
</div>
)}
{/* Group cards grid */}
<div className={isFullWidth ? styles.groupGridSingle : styles.groupGrid}>