import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { Agent } from "@paperclipai/shared"; import { describeError } from "@/api/errors"; import { toolsApi } from "@/api/tools"; import { QueryErrorState, useQueryView } from "@/components/QueryView"; import { queryKeys } from "@/lib/queryKeys"; import { AgentMultiSelect } from "@/components/AgentMultiSelect"; import { RadioCardGroup } from "@/components/ui/radio-card"; export function EmailConnectionAccess({ companyId, connectionId, agents, }: { companyId: string; connectionId: string; agents: Agent[]; }) { const cache = useQueryClient(); const grants = useQuery({ queryKey: queryKeys.tools.connectionGrants(connectionId), queryFn: () => toolsApi.listConnectionGrants(connectionId), }); const installs = useQuery({ queryKey: queryKeys.tools.connectionInstalls(connectionId), queryFn: () => toolsApi.getConnectionInstalls(connectionId), }); const save = useMutation({ mutationFn: ( next: Array<{ targetType: "company" | "agent"; targetId: string }>, ) => toolsApi.putConnectionInstalls(connectionId, next), onSuccess: () => { void cache.invalidateQueries({ queryKey: queryKeys.tools.connectionInstalls(connectionId), }); }, }); const grantsView = useQueryView(grants); const installsView = useQueryView(installs); const failedView = [grantsView, installsView].find((view) => view.kind === "error"); if (failedView) return ( ); if (grants.isLoading || installs.isLoading || grantsView.kind === "reconnecting" || installsView.kind === "reconnecting") return

Loading access…

; const active = grants.data?.grants.filter((g) => g.status === "active") ?? []; const everyone = active.some((g) => g.kind === "organization"); const personal = active.find((g) => g.kind === "user"); const humanLabel = everyone ? "Any human in the organization" : personal ? personal.subjectUserId === grants.data?.currentUserId ? "Just me" : "Only the credential owner" : "Access revoked"; const allAgents = installs.data?.installs.some((i) => i.targetType === "company") ?? false; const selected = new Set( installs.data?.installs .filter((i) => i.targetType === "agent") .map((i) => i.targetId), ); const disabled = !grants.data?.capabilities.canConfigure || save.isPending; return (

Which humans can use this credential?

{humanLabel}

Which agents can use this connection?

save.mutate( value === "all" ? [{ targetType: "company", targetId: companyId }] : Array.from(selected, (targetId) => ({ targetType: "agent", targetId, })), ) } /> {!allAgents && ( a.status !== "terminated")} selectedAgentIds={selected} disabled={disabled} onSave={(ids) => save.mutate( Array.from(ids, (targetId) => ({ targetType: "agent", targetId, })), ) } /> )}

Removing an assigned agent stops receiving and sending from its inbox.

{save.error && (

{describeError(save.error).body}

)}
); }