@@ -374,6 +374,7 @@ export default function AgentsPage() {
374374 const [ expanded , setExpanded ] = useState < string | null > ( null ) ;
375375 const [ activeTab , setActiveTab ] = useState < Record < string , "details" | "activity" > > ( { } ) ;
376376 const [ revoking , setRevoking ] = useState < string | null > ( null ) ;
377+ const [ revokingAll , setRevokingAll ] = useState ( false ) ;
377378 const [ editingAgent , setEditingAgent ] = useState < string | null > ( null ) ;
378379 const [ availableCaps , setAvailableCaps ] = useState < { name : string ; description : string } [ ] > ( [ ] ) ;
379380 const [ selectedCaps , setSelectedCaps ] = useState < Set < string > > ( new Set ( ) ) ;
@@ -459,6 +460,31 @@ export default function AgentsPage() {
459460 }
460461 } ;
461462
463+ const handleRevokeAll = async ( ) => {
464+ const activeAgents = agents . filter ( ( a ) => a . status === "active" ) ;
465+ if ( activeAgents . length === 0 ) return ;
466+ if ( ! window . confirm ( `Revoke all ${ activeAgents . length } active agent${ activeAgents . length !== 1 ? "s" : "" } ? This cannot be undone.` ) ) return ;
467+ setRevokingAll ( true ) ;
468+ try {
469+ await Promise . all (
470+ activeAgents . map ( ( a ) =>
471+ fetch ( "/api/auth/agent/revoke" , {
472+ method : "POST" ,
473+ headers : { "Content-Type" : "application/json" } ,
474+ body : JSON . stringify ( { agent_id : a . agent_id } ) ,
475+ } ) ,
476+ ) ,
477+ ) ;
478+ setAgents ( ( prev ) =>
479+ prev . map ( ( a ) => ( a . status === "active" ? { ...a , status : "revoked" } : a ) ) ,
480+ ) ;
481+ } catch {
482+ /* ignore */
483+ } finally {
484+ setRevokingAll ( false ) ;
485+ }
486+ } ;
487+
462488 const filters = [ "all" , "active" , "pending" , "expired" , "revoked" ] ;
463489 const filteredCount = agents . length ;
464490
@@ -474,6 +500,16 @@ export default function AgentsPage() {
474500 : `${ filteredCount } agent${ filteredCount !== 1 ? "s" : "" } connected` }
475501 </ p >
476502 </ div >
503+ < div className = "flex items-center gap-2" >
504+ { agents . some ( ( a ) => a . status === "active" ) && (
505+ < button
506+ onClick = { handleRevokeAll }
507+ disabled = { revokingAll }
508+ className = "cursor-pointer rounded-lg border border-red-200 px-3 py-1.5 text-[12px] font-medium text-red-600 transition-all hover:bg-red-50 disabled:opacity-50"
509+ >
510+ { revokingAll ? "Revoking..." : "Revoke All" }
511+ </ button >
512+ ) }
477513 < div className = "flex gap-0.5 rounded-lg border border-gray-200 bg-white p-0.5" >
478514 { filters . map ( ( f ) => (
479515 < button
@@ -489,6 +525,7 @@ export default function AgentsPage() {
489525 </ button >
490526 ) ) }
491527 </ div >
528+ </ div >
492529 </ div >
493530
494531 { loading ? (
0 commit comments