feat(web): MS23-P2-006 KillAllDialog confirmation modal
Some checks failed
ci/woodpecker/push/ci Pipeline failed

This commit is contained in:
2026-03-07 14:31:38 -06:00
parent 2c36569f85
commit cd28428cf2
2 changed files with 261 additions and 5 deletions

View File

@@ -4,6 +4,7 @@ import { useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { AgentSession } from "@mosaic/shared";
import { ChevronRight, Loader2, X } from "lucide-react";
import { KillAllDialog } from "@/components/mission-control/KillAllDialog";
import { Badge } from "@/components/ui/badge";
import type { BadgeVariant } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
@@ -36,7 +37,7 @@ interface ProviderSessionGroup {
export interface GlobalAgentRosterProps {
onSelectSession?: (sessionId: string) => void;
selectedSessionId?: string;
selectedSessionId?: string | undefined;
}
function getStatusVariant(status: MissionControlSessionStatus): BadgeVariant {
@@ -87,6 +88,21 @@ async function fetchSessions(): Promise<MissionControlSession[]> {
return Array.isArray(payload) ? payload : payload.sessions;
}
function toKillAllSessions(sessions: MissionControlSession[]): AgentSession[] {
return sessions
.filter(
(session): session is MissionControlSession & { status: AgentSession["status"] } =>
session.status !== "killed"
)
.map((session) => ({
...session,
createdAt:
session.createdAt instanceof Date ? session.createdAt : new Date(session.createdAt),
updatedAt:
session.updatedAt instanceof Date ? session.updatedAt : new Date(session.updatedAt),
}));
}
export function GlobalAgentRoster({
onSelectSession,
selectedSessionId,
@@ -117,6 +133,13 @@ export function GlobalAgentRoster({
[sessionsQuery.data]
);
const killAllSessions = useMemo(
() => toKillAllSessions(sessionsQuery.data ?? []),
[sessionsQuery.data]
);
const totalSessionCount = sessionsQuery.data?.length ?? 0;
const pendingKillSessionId = killMutation.isPending ? killMutation.variables : undefined;
const toggleProvider = (providerId: string): void => {
@@ -128,14 +151,23 @@ export function GlobalAgentRoster({
const isProviderOpen = (providerId: string): boolean => openProviders[providerId] ?? true;
const handleKillAllComplete = (): void => {
void queryClient.invalidateQueries({ queryKey: SESSIONS_QUERY_KEY });
};
return (
<Card className="flex h-full min-h-0 flex-col">
<CardHeader className="pb-2">
<CardTitle className="flex items-center justify-between text-base">
<CardTitle className="flex items-center justify-between gap-2 text-base">
<span>Agent Roster</span>
{sessionsQuery.isFetching && !sessionsQuery.isLoading ? (
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" aria-hidden="true" />
) : null}
<div className="flex items-center gap-2">
{totalSessionCount > 0 ? (
<KillAllDialog sessions={killAllSessions} onComplete={handleKillAllComplete} />
) : null}
{sessionsQuery.isFetching && !sessionsQuery.isLoading ? (
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" aria-hidden="true" />
) : null}
</div>
</CardTitle>
</CardHeader>
<CardContent className="min-h-0 flex-1 px-3 pb-3">