From 5135887c3f5ac52bf205e2c80f31ddd39ce326db Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Thu, 5 Feb 2026 00:35:46 +0530 Subject: [PATCH] feat(page): Refactor agent management UI for improved layout and accessibility --- frontend/src/app/agents/page.tsx | 293 +++++++++++-------------------- 1 file changed, 107 insertions(+), 186 deletions(-) diff --git a/frontend/src/app/agents/page.tsx b/frontend/src/app/agents/page.tsx index aaf346ca..b8364616 100644 --- a/frontend/src/app/agents/page.tsx +++ b/frontend/src/app/agents/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useMemo, useState } from "react"; +import { useMemo, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; @@ -18,7 +18,7 @@ import { useQueryClient } from "@tanstack/react-query"; import { StatusPill } from "@/components/atoms/StatusPill"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; -import { Button } from "@/components/ui/button"; +import { Button, buttonVariants } from "@/components/ui/button"; import { Dialog, DialogContent, @@ -27,13 +27,6 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; import { apiRequest, useAuthedMutation, useAuthedQuery } from "@/lib/api-query"; type Agent = { @@ -53,14 +46,6 @@ type Board = { slug: string; }; -type GatewayStatus = { - connected: boolean; - gateway_url: string; - sessions_count?: number; - sessions?: Record[]; - error?: string; -}; - const parseTimestamp = (value?: string | null) => { if (!value) return null; const hasTz = /[zZ]|[+-]\d\d:\d\d$/.test(value); @@ -104,7 +89,6 @@ export default function AgentsPage() { const queryClient = useQueryClient(); const router = useRouter(); - const [boardId, setBoardId] = useState(""); const [sorting, setSorting] = useState([ { id: "name", desc: false }, ]); @@ -123,27 +107,6 @@ export default function AgentsPage() { const boards = useMemo(() => boardsQuery.data ?? [], [boardsQuery.data]); const agents = useMemo(() => agentsQuery.data ?? [], [agentsQuery.data]); - useEffect(() => { - if (!boardId && boards.length > 0) { - setBoardId(boards[0].id); - } - }, [boardId, boards]); - - const statusPath = boardId - ? `/api/v1/gateways/status?board_id=${boardId}` - : null; - - const gatewayStatusQuery = useAuthedQuery( - ["gateway-status", boardId || "all"], - statusPath, - { - enabled: Boolean(statusPath), - refetchInterval: 15_000, - } - ); - - const gatewayStatus = gatewayStatusQuery.data ?? null; - const deleteMutation = useAuthedMutation( async (agent, token) => apiRequest(`/api/v1/agents/${agent.id}`, { @@ -180,14 +143,6 @@ export default function AgentsPage() { deleteMutation.mutate(deleteTarget); }; - const handleRefresh = async () => { - await Promise.all([ - boardsQuery.refetch(), - agentsQuery.refetch(), - gatewayStatusQuery.refetch(), - ]); - }; - const columns = useMemo[]>( () => { const resolveBoardName = (agent: Agent) => @@ -198,10 +153,12 @@ export default function AgentsPage() { accessorKey: "name", header: "Agent", cell: ({ row }) => ( -
-

{row.original.name}

-

ID {row.original.id}

-
+ +

+ {row.original.name} +

+

ID {row.original.id}

+ ), }, { @@ -213,7 +170,7 @@ export default function AgentsPage() { accessorKey: "openclaw_session_id", header: "Session", cell: ({ row }) => ( - + {truncate(row.original.openclaw_session_id)} ), @@ -222,7 +179,7 @@ export default function AgentsPage() { accessorKey: "board_id", header: "Board", cell: ({ row }) => ( - + {resolveBoardName(row.original)} ), @@ -231,21 +188,16 @@ export default function AgentsPage() { accessorKey: "last_seen_at", header: "Last seen", cell: ({ row }) => ( -
-

- {formatRelative(row.original.last_seen_at)} -

-

- {formatTimestamp(row.original.last_seen_at)} -

-
+ + {formatRelative(row.original.last_seen_at)} + ), }, { accessorKey: "updated_at", header: "Updated", cell: ({ row }) => ( - + {formatTimestamp(row.original.updated_at)} ), @@ -254,24 +206,15 @@ export default function AgentsPage() { id: "actions", header: "", cell: ({ row }) => ( -
event.stopPropagation()} - > - - View - +
Edit +
+
+
+
+

+ Agents +

+

+ {agents.length} agent{agents.length === 1 ? "" : "s"} total. +

+
+ {agents.length > 0 ? ( -
- ) : null} + ) : null} +
- {agentsQuery.error ? ( -
- {agentsQuery.error.message} -
- ) : null} - - {agents.length === 0 && !agentsQuery.isLoading ? ( -
-

No agents yet. Create your first agent to get started.

- -
- ) : ( -
-
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - ))} - - ))} - - - {table.getRowModel().rows.map((row) => ( - router.push(`/agents/${row.original.id}`)} - > +
+
+
- {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext() - )} -
+ + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + ))} + + ))} + + + {agentsQuery.isLoading ? ( + + + + ) : table.getRowModel().rows.length ? ( + table.getRowModel().rows.map((row) => ( + {row.getVisibleCells().map((cell) => ( - ))} - ))} - -
+ {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} +
+ Loading… +
+ {flexRender( cell.column.columnDef.cell, cell.getContext() @@ -394,55 +316,54 @@ export default function AgentsPage() {
-
+ )) + ) : ( + + +
+
+ + + + + + +
+

+ No agents yet +

+

+ Create your first agent to start executing tasks + on this board. +

+ + Create your first agent + +
+ + + )} + +
- )} - -
-
-
-

- Gateway status -

-

- {gatewayStatus?.gateway_url ?? "Gateway URL not set"} -

-
-
- - - - {gatewayStatus?.sessions_count ?? 0} sessions - -
-
- {gatewayStatus?.error ? ( -

{gatewayStatus.error}

- ) : null} - {gatewayStatusQuery.error ? ( -

- {gatewayStatusQuery.error.message} -

- ) : null}
+ + {agentsQuery.error ? ( +

+ {agentsQuery.error.message} +

+ ) : null}