feat(#117): agent-count toasts and persistent error toast dismiss
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@ import {
|
||||
} from '@cameleer/design-system';
|
||||
import type { Column } from '@cameleer/design-system';
|
||||
import { useApplicationConfig, useUpdateApplicationConfig } from '../../api/queries/commands';
|
||||
import type { ApplicationConfig, TapDefinition } from '../../api/queries/commands';
|
||||
import type { ApplicationConfig, TapDefinition, ConfigUpdateResponse } from '../../api/queries/commands';
|
||||
import { useRouteCatalog } from '../../api/queries/catalog';
|
||||
import type { AppCatalogEntry, RouteSummary } from '../../api/types';
|
||||
import styles from './AppConfigDetailPage.module.css';
|
||||
@@ -153,12 +153,17 @@ export default function AppConfigDetailPage() {
|
||||
routeRecording: routeRecordingDraft,
|
||||
} as ApplicationConfig;
|
||||
updateConfig.mutate(updated, {
|
||||
onSuccess: (saved) => {
|
||||
onSuccess: (saved: ConfigUpdateResponse) => {
|
||||
setEditing(false);
|
||||
toast({ title: 'Config saved', description: `${appId} updated to v${saved.config.version}`, variant: 'success' });
|
||||
if (saved.pushResult.success) {
|
||||
toast({ title: 'Config saved', description: `${appId} updated to v${saved.config.version} — pushed to ${saved.pushResult.total}/${saved.pushResult.total} agents`, variant: 'success' });
|
||||
} else {
|
||||
const failed = [...saved.pushResult.responses.filter(r => r.status !== 'SUCCESS').map(r => r.agentId), ...saved.pushResult.timedOut];
|
||||
toast({ title: 'Config saved — partial push failure', description: `${saved.pushResult.responded}/${saved.pushResult.total} responded. Failed: ${failed.join(', ')}`, variant: 'warning', duration: 86_400_000 });
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
toast({ title: 'Save failed', description: 'Could not update configuration', variant: 'error' });
|
||||
toast({ title: 'Save failed', description: 'Could not update configuration', variant: 'error', duration: 86_400_000 });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from '@cameleer/design-system';
|
||||
import type { Column } from '@cameleer/design-system';
|
||||
import { useAllApplicationConfigs, useApplicationConfig, useUpdateApplicationConfig, useProcessorRouteMapping } from '../../api/queries/commands';
|
||||
import type { ApplicationConfig, TapDefinition } from '../../api/queries/commands';
|
||||
import type { ApplicationConfig, TapDefinition, ConfigUpdateResponse } from '../../api/queries/commands';
|
||||
import { useRouteCatalog } from '../../api/queries/catalog';
|
||||
import type { AppCatalogEntry, RouteSummary } from '../../api/types';
|
||||
import styles from './AppConfigPage.module.css';
|
||||
@@ -141,8 +141,16 @@ function AppConfigDetail({ appId, onClose }: { appId: string; onClose: () => voi
|
||||
if (!config || !form) return;
|
||||
const updated = { ...config, ...form, tracedProcessors: tracedDraft, routeRecording: routeRecordingDraft } as ApplicationConfig;
|
||||
updateConfig.mutate(updated, {
|
||||
onSuccess: (saved) => { setEditing(false); toast({ title: 'Config saved', description: `${appId} updated to v${saved.config.version}`, variant: 'success' }); },
|
||||
onError: () => { toast({ title: 'Save failed', description: 'Could not update configuration', variant: 'error' }); },
|
||||
onSuccess: (saved: ConfigUpdateResponse) => {
|
||||
setEditing(false);
|
||||
if (saved.pushResult.success) {
|
||||
toast({ title: 'Config saved', description: `${appId} updated to v${saved.config.version} — pushed to ${saved.pushResult.total}/${saved.pushResult.total} agents`, variant: 'success' });
|
||||
} else {
|
||||
const failed = [...saved.pushResult.responses.filter(r => r.status !== 'SUCCESS').map(r => r.agentId), ...saved.pushResult.timedOut];
|
||||
toast({ title: 'Config saved — partial push failure', description: `${saved.pushResult.responded}/${saved.pushResult.total} responded. Failed: ${failed.join(', ')}`, variant: 'warning', duration: 86_400_000 });
|
||||
}
|
||||
},
|
||||
onError: () => { toast({ title: 'Save failed', description: 'Could not update configuration', variant: 'error', duration: 86_400_000 }); },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ export default function GroupsTab() {
|
||||
setNewName('');
|
||||
setNewParent('');
|
||||
} catch {
|
||||
toast({ title: 'Failed to create group', variant: 'error' });
|
||||
toast({ title: 'Failed to create group', variant: 'error', duration: 86_400_000 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ export default function GroupsTab() {
|
||||
if (selectedId === deleteTarget.id) setSelectedId(null);
|
||||
setDeleteTarget(null);
|
||||
} catch {
|
||||
toast({ title: 'Failed to delete group', variant: 'error' });
|
||||
toast({ title: 'Failed to delete group', variant: 'error', duration: 86_400_000 });
|
||||
setDeleteTarget(null);
|
||||
}
|
||||
}
|
||||
@@ -153,7 +153,7 @@ export default function GroupsTab() {
|
||||
});
|
||||
toast({ title: 'Group renamed', variant: 'success' });
|
||||
} catch {
|
||||
toast({ title: 'Failed to rename group', variant: 'error' });
|
||||
toast({ title: 'Failed to rename group', variant: 'error', duration: 86_400_000 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ export default function GroupsTab() {
|
||||
});
|
||||
toast({ title: 'Member removed', variant: 'success' });
|
||||
} catch {
|
||||
toast({ title: 'Failed to remove member', variant: 'error' });
|
||||
toast({ title: 'Failed to remove member', variant: 'error', duration: 86_400_000 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ export default function GroupsTab() {
|
||||
});
|
||||
toast({ title: 'Member added', variant: 'success' });
|
||||
} catch {
|
||||
toast({ title: 'Failed to add member', variant: 'error' });
|
||||
toast({ title: 'Failed to add member', variant: 'error', duration: 86_400_000 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,7 +195,7 @@ export default function GroupsTab() {
|
||||
});
|
||||
toast({ title: 'Role assigned', variant: 'success' });
|
||||
} catch {
|
||||
toast({ title: 'Failed to assign role', variant: 'error' });
|
||||
toast({ title: 'Failed to assign role', variant: 'error', duration: 86_400_000 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,7 @@ export default function GroupsTab() {
|
||||
});
|
||||
toast({ title: 'Role removed', variant: 'success' });
|
||||
} catch {
|
||||
toast({ title: 'Failed to remove role', variant: 'error' });
|
||||
toast({ title: 'Failed to remove role', variant: 'error', duration: 86_400_000 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ export default function OidcConfigPage() {
|
||||
toast({ title: 'Settings saved', description: 'OIDC configuration updated successfully.', variant: 'success' });
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
toast({ title: 'Save failed', description: e.message, variant: 'error' });
|
||||
toast({ title: 'Save failed', description: e.message, variant: 'error', duration: 86_400_000 });
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
@@ -94,7 +94,7 @@ export default function OidcConfigPage() {
|
||||
toast({ title: 'Connection test', description: `OIDC provider responded: ${result.status}`, variant: 'success' });
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
toast({ title: 'Connection test failed', description: e.message, variant: 'error' });
|
||||
toast({ title: 'Connection test failed', description: e.message, variant: 'error', duration: 86_400_000 });
|
||||
} finally {
|
||||
setTesting(false);
|
||||
}
|
||||
@@ -109,7 +109,7 @@ export default function OidcConfigPage() {
|
||||
toast({ title: 'Configuration deleted', description: 'OIDC configuration has been removed.', variant: 'warning' });
|
||||
} catch (e: any) {
|
||||
setError(e.message);
|
||||
toast({ title: 'Delete failed', description: e.message, variant: 'error' });
|
||||
toast({ title: 'Delete failed', description: e.message, variant: 'error', duration: 86_400_000 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ export default function RolesTab() {
|
||||
setNewDesc('');
|
||||
},
|
||||
onError: () => {
|
||||
toast({ title: 'Failed to create role', variant: 'error' });
|
||||
toast({ title: 'Failed to create role', variant: 'error', duration: 86_400_000 });
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -92,7 +92,7 @@ export default function RolesTab() {
|
||||
setDeleteTarget(null);
|
||||
},
|
||||
onError: () => {
|
||||
toast({ title: 'Failed to delete role', variant: 'error' });
|
||||
toast({ title: 'Failed to delete role', variant: 'error', duration: 86_400_000 });
|
||||
setDeleteTarget(null);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -135,7 +135,7 @@ export default function UsersTab() {
|
||||
setNewProvider('local');
|
||||
},
|
||||
onError: () => {
|
||||
toast({ title: 'Failed to create user', variant: 'error' });
|
||||
toast({ title: 'Failed to create user', variant: 'error', duration: 86_400_000 });
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -154,7 +154,7 @@ export default function UsersTab() {
|
||||
setDeleteTarget(null);
|
||||
},
|
||||
onError: () => {
|
||||
toast({ title: 'Failed to delete user', variant: 'error' });
|
||||
toast({ title: 'Failed to delete user', variant: 'error', duration: 86_400_000 });
|
||||
setDeleteTarget(null);
|
||||
},
|
||||
});
|
||||
@@ -175,7 +175,7 @@ export default function UsersTab() {
|
||||
setNewPw('');
|
||||
},
|
||||
onError: () => {
|
||||
toast({ title: 'Failed to update password', variant: 'error' });
|
||||
toast({ title: 'Failed to update password', variant: 'error', duration: 86_400_000 });
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -333,6 +333,7 @@ export default function UsersTab() {
|
||||
toast({
|
||||
title: 'Failed to update name',
|
||||
variant: 'error',
|
||||
duration: 86_400_000,
|
||||
}),
|
||||
},
|
||||
)
|
||||
@@ -451,6 +452,7 @@ export default function UsersTab() {
|
||||
toast({
|
||||
title: 'Failed to remove group',
|
||||
variant: 'error',
|
||||
duration: 86_400_000,
|
||||
}),
|
||||
},
|
||||
);
|
||||
@@ -474,6 +476,7 @@ export default function UsersTab() {
|
||||
toast({
|
||||
title: 'Failed to add group',
|
||||
variant: 'error',
|
||||
duration: 86_400_000,
|
||||
}),
|
||||
},
|
||||
);
|
||||
@@ -506,6 +509,7 @@ export default function UsersTab() {
|
||||
toast({
|
||||
title: 'Failed to remove role',
|
||||
variant: 'error',
|
||||
duration: 86_400_000,
|
||||
}),
|
||||
},
|
||||
);
|
||||
@@ -542,6 +546,7 @@ export default function UsersTab() {
|
||||
toast({
|
||||
title: 'Failed to assign role',
|
||||
variant: 'error',
|
||||
duration: 86_400_000,
|
||||
}),
|
||||
},
|
||||
);
|
||||
@@ -583,6 +588,7 @@ export default function UsersTab() {
|
||||
toast({
|
||||
title: 'Failed to remove group',
|
||||
variant: 'error',
|
||||
duration: 86_400_000,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user