fix(ui): import agent button

This commit is contained in:
null 2026-05-21 00:19:42 -05:00
parent c440f98381
commit 184d86c58a
1 changed files with 134 additions and 4 deletions

View File

@ -9,9 +9,25 @@ import { useAuth } from "@/auth/clerk";
import { useQueryClient } from "@tanstack/react-query";
import { AgentsTable } from "@/components/agents/AgentsTable";
import { GatewayAgentImportDialog } from "@/components/gateways/GatewayAgentImportDialog";
import { DashboardPageLayout } from "@/components/templates/DashboardPageLayout";
import { Button } from "@/components/ui/button";
import { ConfirmActionDialog } from "@/components/ui/confirm-action-dialog";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { ApiError } from "@/api/mutator";
import {
@ -25,7 +41,12 @@ import {
getListBoardsApiV1BoardsGetQueryKey,
useListBoardsApiV1BoardsGet,
} from "@/api/generated/boards/boards";
import { type AgentRead } from "@/api/generated/model";
import {
type listGatewaysApiV1GatewaysGetResponse,
getListGatewaysApiV1GatewaysGetQueryKey,
useListGatewaysApiV1GatewaysGet,
} from "@/api/generated/gateways/gateways";
import { type AgentRead, type GatewayRead } from "@/api/generated/model";
import { createOptimisticListDeleteMutation } from "@/lib/list-delete";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import { useUrlSorting } from "@/lib/use-url-sorting";
@ -52,9 +73,13 @@ export default function AgentsPage() {
});
const [deleteTarget, setDeleteTarget] = useState<AgentRead | null>(null);
const [importGatewayPickerOpen, setImportGatewayPickerOpen] = useState(false);
const [selectedGatewayId, setSelectedGatewayId] = useState<string>("");
const [importTarget, setImportTarget] = useState<GatewayRead | null>(null);
const boardsKey = getListBoardsApiV1BoardsGetQueryKey();
const agentsKey = getListAgentsApiV1AgentsGetQueryKey();
const gatewaysKey = getListGatewaysApiV1GatewaysGetQueryKey();
const boardsQuery = useListBoardsApiV1BoardsGet<
listBoardsApiV1BoardsGetResponse,
@ -77,6 +102,16 @@ export default function AgentsPage() {
refetchOnMount: "always",
},
});
const gatewaysQuery = useListGatewaysApiV1GatewaysGet<
listGatewaysApiV1GatewaysGetResponse,
ApiError
>(undefined, {
query: {
enabled: Boolean(isSignedIn && isAdmin),
refetchInterval: 30_000,
refetchOnMount: "always",
},
});
const boards = useMemo(
() =>
@ -92,6 +127,13 @@ export default function AgentsPage() {
: [],
[agentsQuery.data],
);
const gateways = useMemo(
() =>
gatewaysQuery.data?.status === 200
? (gatewaysQuery.data.data.items ?? [])
: [],
[gatewaysQuery.data],
);
const deleteMutation = useDeleteAgentApiV1AgentsAgentIdDelete<
ApiError,
@ -121,6 +163,26 @@ export default function AgentsPage() {
deleteMutation.mutate({ agentId: deleteTarget.id });
};
const handleImportAgentsClick = () => {
if (gateways.length === 1) {
setImportTarget(gateways[0]);
return;
}
setImportGatewayPickerOpen(true);
};
const handleOpenImportForSelectedGateway = () => {
const gateway = gateways.find((item) => item.id === selectedGatewayId);
if (!gateway) return;
setImportGatewayPickerOpen(false);
setImportTarget(gateway);
};
const handleImported = async () => {
await queryClient.invalidateQueries({ queryKey: agentsKey });
await queryClient.invalidateQueries({ queryKey: gatewaysKey });
};
return (
<>
<DashboardPageLayout
@ -133,9 +195,18 @@ export default function AgentsPage() {
description={`${agents.length} agent${agents.length === 1 ? "" : "s"} total.`}
headerActions={
agents.length > 0 ? (
<Button onClick={() => router.push("/agents/new")}>
New agent
</Button>
<div className="flex items-center gap-2">
<Button
variant="outline"
onClick={handleImportAgentsClick}
disabled={gateways.length === 0}
>
Import agents
</Button>
<Button onClick={() => router.push("/agents/new")}>
New agent
</Button>
</div>
) : null
}
isAdmin={isAdmin}
@ -187,6 +258,65 @@ export default function AgentsPage() {
onConfirm={handleDelete}
isConfirming={deleteMutation.isPending}
/>
<Dialog
open={importGatewayPickerOpen}
onOpenChange={(open) => {
setImportGatewayPickerOpen(open);
if (!open) {
setSelectedGatewayId("");
}
}}
>
<DialogContent>
<DialogHeader>
<DialogTitle>Import Agents</DialogTitle>
<DialogDescription>
Select a gateway to open the agent import screen.
</DialogDescription>
</DialogHeader>
<div className="space-y-2">
<p className="text-sm font-medium text-foreground">Gateway</p>
<Select value={selectedGatewayId} onValueChange={setSelectedGatewayId}>
<SelectTrigger>
<SelectValue placeholder="Select a gateway" />
</SelectTrigger>
<SelectContent>
{gateways.map((gateway) => (
<SelectItem key={gateway.id} value={gateway.id}>
{gateway.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<DialogFooter>
<Button
variant="outline"
onClick={() => setImportGatewayPickerOpen(false)}
>
Cancel
</Button>
<Button
onClick={handleOpenImportForSelectedGateway}
disabled={!selectedGatewayId}
>
Continue
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<GatewayAgentImportDialog
open={Boolean(importTarget)}
onOpenChange={(open) => {
if (!open) {
setImportTarget(null);
}
}}
gateway={importTarget}
onImported={handleImported}
/>
</>
);
}