import { useId, useMemo, useState } from "react"; import { Link, useNavigate } from "@tanstack/react-router"; import { useAtomSet, useAtomValue } from "@effect/atom-react"; import * as Atom from "effect/unstable/reactivity/Atom"; import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"; import { ArrowLeftIcon, BoxIcon, PlugIcon, PlusIcon, SearchIcon, Trash2Icon } from "lucide-react"; import { createPluginAtomClient, useIntegrationPlugins, type IntegrationPlugin, type PluginPageProps, } from "@executor-js/sdk/client"; import { matchPattern, type EffectivePolicy, type Integration, type Owner, type ToolAddress, type ToolPolicyAction, } from "@executor-js/sdk/shared"; import { integrationsOptimisticAtom, toolsAllAtom } from "@executor-js/react/api/atoms"; import { ReactivityKey } from "@executor-js/react/api/reactivity-keys"; import { useOrganizationSlug } from "@executor-js/react/api/organization-context"; import { getExecutorApiBaseUrl, getExecutorOrganizationHeaders, getExecutorServerAuthorizationHeader, } from "@executor-js/react/api/server-connection"; import { ownerLabel, useOwnerDisplay } from "@executor-js/react/api/owner-display"; import { Badge } from "@executor-js/react/components/badge"; import { Button } from "@executor-js/react/components/button"; import { CopyButton } from "@executor-js/react/components/copy-button"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@executor-js/react/components/alert-dialog"; import { IntegrationFavicon, integrationPresetIconUrl, } from "@executor-js/react/components/integration-favicon"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@executor-js/react/components/dialog"; import { Input } from "@executor-js/react/components/input"; import { Label } from "@executor-js/react/components/label"; import { Skeleton } from "@executor-js/react/components/skeleton"; import { ToolDetail, ToolDetailEmpty } from "@executor-js/react/components/tool-detail"; import { ToolTree, type ToolSummary } from "@executor-js/react/components/tool-tree"; import { cn } from "@executor-js/react/lib/utils"; import { ToolkitsApi, type ToolkitConnectionResponse, type ToolkitPolicyResponse, type ToolkitResponse, } from "./shared"; const ToolkitsClient = createPluginAtomClient(ToolkitsApi, { baseUrl: getExecutorApiBaseUrl, authorizationHeader: getExecutorServerAuthorizationHeader, headers: getExecutorOrganizationHeaders, }); const toolkitWriteKeys = [ ReactivityKey.connections, ReactivityKey.policies, ReactivityKey.tools, ] as const; const toolkitsAtom = ToolkitsClient.query("toolkits", "list", { timeToLive: "30 seconds", reactivityKeys: [ReactivityKey.policies], }); const toolkitPoliciesAtom = Atom.family((toolkitId: string) => ToolkitsClient.query("toolkits", "listPolicies", { params: { toolkitId }, timeToLive: "30 seconds", reactivityKeys: [ReactivityKey.policies], }), ); const toolkitConnectionsAtom = Atom.family((toolkitId: string) => ToolkitsClient.query("toolkits", "listConnections", { params: { toolkitId }, timeToLive: "30 seconds", reactivityKeys: [ReactivityKey.connections], }), ); const createToolkit = ToolkitsClient.mutation("toolkits", "create"); const removeToolkit = ToolkitsClient.mutation("toolkits", "remove"); const createToolkitPolicy = ToolkitsClient.mutation("toolkits", "createPolicy"); const updateToolkitPolicy = ToolkitsClient.mutation("toolkits", "updatePolicy"); const removeToolkitPolicy = ToolkitsClient.mutation("toolkits", "removePolicy"); const createToolkitConnection = ToolkitsClient.mutation("toolkits", "createConnection"); const removeToolkitConnection = ToolkitsClient.mutation("toolkits", "removeConnection"); type ToolRow = { readonly address: ToolAddress; readonly integration: string; readonly owner?: Owner; readonly connection?: string; readonly name: string; readonly description?: string; readonly requiresApproval?: boolean; readonly static?: boolean; }; const comparePolicy = (a: ToolkitPolicyResponse, b: ToolkitPolicyResponse): number => { if (a.position < b.position) return -1; if (a.position > b.position) return 1; return a.id < b.id ? -1 : a.id > b.id ? 1 : 0; }; const pluginDefaultPolicy = (requiresApproval: boolean | undefined): EffectivePolicy => requiresApproval ? { action: "require_approval", source: "plugin-default" } : { action: "approve", source: "plugin-default" }; const isLegacyConnectionPolicy = (policy: ToolkitPolicyResponse): boolean => { if (policy.action !== "approve") return false; const parts = policy.pattern.split("."); return parts.at(-1) === "*" && (parts.length === 3 || parts.length === 4); }; const resolveToolkitPolicy = ( matchId: string, policies: readonly ToolkitPolicyResponse[], requiresApproval?: boolean, ): EffectivePolicy => { for (const policy of [...policies].sort(comparePolicy)) { if (!matchPattern(policy.pattern, matchId)) continue; return { action: policy.action, source: "user", pattern: policy.pattern, policyId: policy.id, }; } return pluginDefaultPolicy(requiresApproval); }; const toolMatchId = (tool: ToolRow): string => tool.static ? String(tool.address) : String(tool.address).replace(/^tools\./, ""); const toolCanAppearInToolkit = (toolkit: ToolkitResponse, tool: ToolRow): boolean => toolkit.owner === "user" || tool.static === true || tool.owner !== "user"; const toolkitUrlFor = (orgSlug: string | undefined, slug: string): string => { const path = orgSlug ? `/${orgSlug}/mcp/toolkits/${slug}` : `/mcp/toolkits/${slug}`; if (typeof window === "undefined") return path; return `${window.location.origin}${path}`; }; const identityPattern = (displayPattern: string): string => displayPattern; const compareToolkitRows = (a: ToolkitResponse, b: ToolkitResponse): number => { if (a.updatedAt !== b.updatedAt) return b.updatedAt - a.updatedAt; return a.name.localeCompare(b.name); }; const toolkitByRouteSlug = ( toolkits: readonly ToolkitResponse[], slug: string, ): ToolkitResponse | null => { const matches = toolkits.filter((toolkit) => toolkit.slug === slug); return matches.find((toolkit) => toolkit.owner === "org") ?? matches[0] ?? null; }; const toolkitCardStyle = { minHeight: "9rem" }; const toolkitShelfStyle = { minHeight: "28.5rem" }; const toolkitGridContainerStyle = { maxWidth: "80rem" }; const toolkitToolTreeStyle = { width: "24rem" }; const neutralToolkitIconClass = "border-border/70 bg-muted/30 text-muted-foreground"; type ToolkitConnectionGroup = { readonly id: string; readonly owner: Owner; readonly integration: string; readonly connection: string; readonly patterns: readonly string[]; readonly tools: readonly ToolRow[]; }; type IntegrationMeta = { readonly name: string; readonly sourceId: string; readonly icon?: string | null; readonly url?: string; }; const toolOwner = (tool: ToolRow): Owner => (tool.static ? "org" : (tool.owner ?? "org")); const toolConnectionName = (tool: ToolRow): string => { if (tool.connection && tool.connection.length > 0) return tool.connection; return tool.static ? "built-in" : "default"; }; const policyPrefixForTool = (tool: ToolRow): string => { const matchId = toolMatchId(tool); const integration = String(tool.integration); if (tool.connection && tool.connection.length > 0) { const connection = String(tool.connection); if (tool.owner) { const ownerConnectionPrefix = `${integration}.${tool.owner}.${connection}`; if (matchId === ownerConnectionPrefix || matchId.startsWith(`${ownerConnectionPrefix}.`)) { return ownerConnectionPrefix; } } const connectionPrefix = `${integration}.${connection}`; if (matchId === connectionPrefix || matchId.startsWith(`${connectionPrefix}.`)) { return connectionPrefix; } } const name = String(tool.name); if (name.length > 0 && matchId.endsWith(`.${name}`)) { return matchId.slice(0, -name.length - 1); } const segments = matchId.split("."); return segments.length > 1 ? segments.slice(0, -1).join(".") : matchId; }; const connectionPatternForTool = (tool: ToolRow): string => `${policyPrefixForTool(tool)}.*`; const compareConnectionGroups = (a: ToolkitConnectionGroup, b: ToolkitConnectionGroup): number => { const ownerRank = (owner: Owner) => (owner === "org" ? 0 : 1); return ( ownerRank(a.owner) - ownerRank(b.owner) || a.integration.localeCompare(b.integration) || a.connection.localeCompare(b.connection) || a.id.localeCompare(b.id) ); }; const patternSubsumes = (candidate: string, covered: string): boolean => { if (candidate === covered) return true; if (!candidate.endsWith(".*")) return false; const prefix = candidate.slice(0, -1); return covered.startsWith(prefix); }; const reducePolicyPatterns = (patterns: readonly string[]): readonly string[] => { const unique = [...new Set(patterns)].sort((a, b) => a.localeCompare(b)); return unique.filter( (pattern) => !unique.some((candidate) => candidate !== pattern && patternSubsumes(candidate, pattern)), ); }; const buildConnectionGroups = (tools: readonly ToolRow[]): readonly ToolkitConnectionGroup[] => { const groups = new Map(); for (const tool of tools) { const owner = toolOwner(tool); const key = `${owner}:${tool.integration}:${toolConnectionName(tool)}`; const existing = groups.get(key); if (existing) { existing.tools.push(tool); continue; } groups.set(key, { id: key, owner, integration: String(tool.integration), connection: toolConnectionName(tool), patterns: [], tools: [tool], }); } return [...groups.values()] .map((group) => { const sortedTools = [...group.tools].sort(compareTools); return { ...group, patterns: reducePolicyPatterns(sortedTools.map(connectionPatternForTool)), tools: sortedTools, }; }) .sort(compareConnectionGroups); }; const compareTools = (a: ToolRow, b: ToolRow): number => String(a.name).localeCompare(String(b.name)) || toolMatchId(a).localeCompare(toolMatchId(b)); const connectionTitle = (group: ToolkitConnectionGroup): string => `${ownerLabel(group.owner)} ${group.integration} / ${group.connection}`; const connectionTitleForHost = (group: ToolkitConnectionGroup, showOwnerLabels: boolean): string => showOwnerLabels ? connectionTitle(group) : `${group.integration} / ${group.connection}`; const connectionDisplayTitle = (group: ToolkitConnectionGroup, meta: IntegrationMeta): string => group.connection === "built-in" || group.connection === "default" ? meta.name : group.connection; const connectionDisplaySubtitle = (group: ToolkitConnectionGroup, meta: IntegrationMeta): string => group.connection === "built-in" || group.connection === "default" ? `${group.tools.length} ${group.tools.length === 1 ? "tool" : "tools"}` : `${meta.name} · ${group.tools.length} ${group.tools.length === 1 ? "tool" : "tools"}`; const connectionDisplaySubtitleForHost = ( group: ToolkitConnectionGroup, meta: IntegrationMeta, showOwnerLabels: boolean, ): string => { const subtitle = connectionDisplaySubtitle(group, meta); return showOwnerLabels ? `${ownerLabel(group.owner)} · ${subtitle}` : subtitle; }; const integrationMetaFor = ( group: ToolkitConnectionGroup, integrations: readonly Integration[], integrationPlugins: readonly IntegrationPlugin[], ): IntegrationMeta => { const integration = integrations.find((row) => String(row.slug) === group.integration); const fallbackName = group.integration .replace(/[_-]/g, " ") .replace(/\b\w/g, (character) => character.toUpperCase()); const source = { id: group.integration, kind: integration?.kind ?? group.integration, name: integration?.name ?? fallbackName, url: integration?.displayUrl, }; return { name: source.name, sourceId: group.integration, icon: integrationPresetIconUrl(source, integrationPlugins), ...(source.url ? { url: source.url } : {}), }; }; type ConfiguredConnectionView = { readonly id: string; readonly title: string; readonly subtitle: string; readonly pattern: string; readonly sourceId: string; readonly icon?: string | null; readonly url?: string; }; const configuredConnectionViews = ( connections: readonly ToolkitConnectionResponse[], connectionGroups: readonly ToolkitConnectionGroup[], integrations: readonly Integration[], integrationPlugins: readonly IntegrationPlugin[], showOwnerLabels: boolean, ): readonly ConfiguredConnectionView[] => connections.map((connection) => { const group = connectionGroups.find((candidate) => candidate.patterns.includes(connection.pattern), ); if (!group) { return { id: connection.id, title: connection.pattern, subtitle: "Configured pattern", pattern: connection.pattern, sourceId: connection.pattern.split(".")[0] ?? "toolkit", }; } const meta = integrationMetaFor(group, integrations, integrationPlugins); return { id: connection.id, title: connectionDisplayTitle(group, meta), subtitle: connectionDisplaySubtitleForHost(group, meta, showOwnerLabels), pattern: connection.pattern, sourceId: meta.sourceId, icon: meta.icon, ...(meta.url ? { url: meta.url } : {}), }; }); const legacyConnectionPolicyIds = ( policies: readonly ToolkitPolicyResponse[], connectionGroups: readonly ToolkitConnectionGroup[], connections: readonly ToolkitConnectionResponse[], ): ReadonlySet => { const persistedPatterns = new Set(connections.map((connection) => connection.pattern)); const connectionPatterns = new Set(connectionGroups.flatMap((group) => group.patterns)); return new Set( policies .filter( (policy) => isLegacyConnectionPolicy(policy) && connectionPatterns.has(policy.pattern) && !persistedPatterns.has(policy.pattern), ) .map((policy) => policy.id), ); }; const configuredConnectionPatterns = ( connections: readonly ToolkitConnectionResponse[], policies: readonly ToolkitPolicyResponse[], legacyPolicyIds: ReadonlySet, ): ReadonlySet => new Set([ ...connections.map((connection) => connection.pattern), ...policies.filter((policy) => legacyPolicyIds.has(policy.id)).map((policy) => policy.pattern), ]); function ToolkitConnectionIconStack(props: { connections: readonly ConfiguredConnectionView[] }) { const visibleConnections = props.connections.slice(0, 3); if (visibleConnections.length === 0) { return (
); } return (
{visibleConnections.map((connection) => ( ))}
); } const connectionCountLabel = (count: number): string => count === 0 ? "No connections" : `${count} ${count === 1 ? "connection" : "connections"}`; function ToolkitTile(props: { showOwnerLabels: boolean; toolkit: ToolkitResponse }) { const toolkit = props.toolkit; const tools = useAtomValue(toolsAllAtom); const integrations = useAtomValue(integrationsOptimisticAtom); const connections = useAtomValue(toolkitConnectionsAtom(toolkit.id)); const integrationPlugins = useIntegrationPlugins(); const visibleTools = useMemo( () => AsyncResult.isSuccess(tools) ? (tools.value as readonly ToolRow[]).filter((tool) => toolCanAppearInToolkit(toolkit, tool), ) : [], [toolkit, tools], ); const connectionGroups = useMemo(() => buildConnectionGroups(visibleTools), [visibleTools]); const connectionRows = AsyncResult.isSuccess(connections) ? connections.value.connections : []; const integrationRows = AsyncResult.isSuccess(integrations) ? (integrations.value as readonly Integration[]) : []; const tileDataReady = AsyncResult.isSuccess(connections) && AsyncResult.isSuccess(tools) && AsyncResult.isSuccess(integrations); const configuredConnections = tileDataReady ? configuredConnectionViews( connectionRows, connectionGroups, integrationRows, integrationPlugins, props.showOwnerLabels, ) : []; return (
{tileDataReady ? ( ) : ( )}
{toolkit.name}
{tileDataReady ? connectionCountLabel(configuredConnections.length) : "Loading"}
); } const addToolkitScopeLabel = (owner: Owner, showOwnerLabels: boolean): string => showOwnerLabels ? (owner === "org" ? "workspace" : "personal") : ""; const addToolkitTitle = (owner: Owner, showOwnerLabels: boolean): string => showOwnerLabels ? owner === "org" ? "New workspace toolkit" : "New personal toolkit" : "New toolkit"; function CreateToolkitDialog(props: { owner: Owner; showOwnerLabels: boolean; open: boolean; onOpenChange: (open: boolean) => void; onCreate: (input: { owner: Owner; name: string }) => Promise; }) { const inputId = useId(); const [name, setName] = useState(""); const trimmed = name.trim(); const title = addToolkitTitle(props.owner, props.showOwnerLabels); const submit = async () => { if (!trimmed) return; await props.onCreate({ owner: props.owner, name: trimmed }); setName(""); props.onOpenChange(false); }; return ( { props.onOpenChange(nextOpen); if (!nextOpen) setName(""); }} >
{ event.preventDefault(); void submit(); }} > {title} Group tools and expose them at a dedicated MCP URL.
setName(event.target.value)} placeholder="e.g. Support tools" autoFocus className="h-9" />
); } function AddToolkitCard(props: { owner: Owner; showOwnerLabels: boolean; onClick: () => void }) { const scopeLabel = addToolkitScopeLabel(props.owner, props.showOwnerLabels); return ( ); } function ToolkitSection(props: { owner: Owner; title?: string; showOwnerLabels: boolean; toolkits: readonly ToolkitResponse[]; onCreate: (input: { owner: Owner; name: string }) => Promise; }) { const rows = [...props.toolkits].sort(compareToolkitRows); const [createOpen, setCreateOpen] = useState(false); const openCreate = () => setCreateOpen(true); return (
{props.title ? (

{props.title}

) : null}
{rows.map((toolkit) => ( ))}
); } function ToolkitGrid(props: { toolkits: readonly ToolkitResponse[]; onCreate: (input: { owner: Owner; name: string }) => Promise; }) { const ownerDisplay = useOwnerDisplay(); // Toolkit shelves are grouped by owner; the selected toolkit owns the page. const workspaceToolkits = props.toolkits.filter((toolkit) => toolkit.owner === "org"); const personalToolkits = props.toolkits.filter((toolkit) => toolkit.owner === "user"); if (!ownerDisplay.showOwnerLabels) { return (
); } return (
); } function ToolkitContentsEmpty(props: { onManageConnections: () => void }) { return (

No connections added

Add a connection to decide what this toolkit exposes.

); } function ToolkitToolsPanel(props: { tools: readonly ToolSummary[]; selectedToolId: string | null; policies: readonly ToolkitPolicyResponse[]; onManageConnections: () => void; onSelectTool: (toolId: string) => void; onSetPolicy: (pattern: string, action: ToolPolicyAction) => void; onClearPolicy: (pattern: string) => void; }) { return (
{props.tools.length === 0 ? ( ) : ( )}
); } function AddConnectionDialog(props: { open: boolean; groups: readonly ToolkitConnectionGroup[]; configuredConnections: readonly ConfiguredConnectionView[]; hiddenPersonalConnectionCount: number; integrations: readonly Integration[]; integrationPlugins: readonly IntegrationPlugin[]; showOwnerLabels: boolean; onOpenChange: (open: boolean) => void; onAddPatterns: (patterns: readonly string[]) => Promise | void; onRemoveConnection: (connectionId: string) => Promise | void; }) { const searchId = useId(); const [query, setQuery] = useState(""); const trimmedQuery = query.trim().toLowerCase(); const filteredGroups = useMemo(() => { if (!trimmedQuery) return props.groups; return props.groups.filter((group) => { const corpus = [ connectionTitle(group), ...group.patterns, ownerLabel(group.owner), ...group.tools.flatMap((tool) => [tool.name, tool.description ?? ""]), ] .join(" ") .toLowerCase(); return corpus.includes(trimmedQuery); }); }, [props.groups, trimmedQuery]); const addConnection = async (patterns: readonly string[]) => { await props.onAddPatterns(patterns); }; const removeConnection = async (connectionId: string) => { await props.onRemoveConnection(connectionId); }; return ( { props.onOpenChange(nextOpen); if (!nextOpen) { setQuery(""); } }} >
Manage connections Choose which connected accounts this toolkit can use.
setQuery(event.target.value)} placeholder="Search connections" className="h-8 min-w-0 border-0 bg-transparent px-0 text-xs shadow-none focus-visible:ring-0" />
{props.hiddenPersonalConnectionCount > 0 ? (

You have {props.hiddenPersonalConnectionCount} personal{" "} {props.hiddenPersonalConnectionCount === 1 ? "connection" : "connections"} that{" "} {props.hiddenPersonalConnectionCount === 1 ? "is" : "are"} not shown because this is a shared toolkit.

) : null}
Connections {filteredGroups.length}
{filteredGroups.length === 0 ? (
No connections match.
) : (
{filteredGroups.map((group) => { const title = connectionTitleForHost(group, props.showOwnerLabels); const configuredConnection = props.configuredConnections.find((connection) => group.patterns.includes(connection.pattern), ); const added = configuredConnection !== undefined; const meta = integrationMetaFor( group, props.integrations, props.integrationPlugins, ); return (
{connectionDisplayTitle(group, meta)} {props.showOwnerLabels ? ( {ownerLabel(group.owner)} ) : null}
{connectionDisplaySubtitle(group, meta)}
); })}
)}
); } function ToolkitHeader(props: { toolkit: ToolkitResponse; showOwnerLabels: boolean; mcpUrl: string; onBack: () => void; onManageConnections: () => void; onRemove: () => void; }) { return (

{props.toolkit.name}

{props.showOwnerLabels ? ( {ownerLabel(props.toolkit.owner)} ) : null}
MCP {props.mcpUrl}
Delete {props.toolkit.name}? This removes the toolkit and its dedicated MCP endpoint. Connections are not deleted. Cancel Delete
); } function ToolkitWorkspace(props: { toolkit: ToolkitResponse; showOwnerLabels: boolean; policies: readonly ToolkitPolicyResponse[]; connections: readonly ToolkitConnectionResponse[]; tools: readonly ToolRow[]; integrations: readonly Integration[]; integrationPlugins: readonly IntegrationPlugin[]; mcpUrl: string; onBack: () => void; onRemoveToolkit: () => void; onAddConnection: (pattern: string) => Promise | void; onRemoveConnection: (connectionId: string) => Promise | void; onSetPolicy: (pattern: string, action: ToolPolicyAction) => Promise | void; onClearPolicy: (pattern: string) => Promise | void; }) { const [addOpen, setAddOpen] = useState(false); const [selectedToolId, setSelectedToolId] = useState(null); const visibleTools = useMemo( () => props.tools.filter((tool) => toolCanAppearInToolkit(props.toolkit, tool)), [props.toolkit, props.tools], ); const connectionGroups = useMemo(() => buildConnectionGroups(visibleTools), [visibleTools]); const hiddenPersonalConnectionCount = useMemo(() => { if (props.toolkit.owner !== "org") return 0; return buildConnectionGroups(props.tools.filter((tool) => toolOwner(tool) === "user")).length; }, [props.toolkit.owner, props.tools]); const configuredConnections = useMemo( () => configuredConnectionViews( props.connections, connectionGroups, props.integrations, props.integrationPlugins, props.showOwnerLabels, ), [ connectionGroups, props.connections, props.integrationPlugins, props.integrations, props.showOwnerLabels, ], ); const legacyPolicyIds = useMemo( () => legacyConnectionPolicyIds(props.policies, connectionGroups, props.connections), [connectionGroups, props.connections, props.policies], ); const accessPolicies = useMemo( () => props.policies.filter((policy) => !legacyPolicyIds.has(policy.id)), [legacyPolicyIds, props.policies], ); const connectionPatterns = useMemo( () => configuredConnectionPatterns(props.connections, props.policies, legacyPolicyIds), [legacyPolicyIds, props.connections, props.policies], ); const configuredToolIds = useMemo(() => { const ids = new Set(); for (const tool of visibleTools) { const id = toolMatchId(tool); if ([...connectionPatterns].some((pattern) => matchPattern(pattern, id))) ids.add(id); } return ids; }, [connectionPatterns, visibleTools]); const configuredTools = useMemo( () => visibleTools.filter((tool) => configuredToolIds.has(toolMatchId(tool))).sort(compareTools), [visibleTools, configuredToolIds], ); const toolkitTools: ToolSummary[] = useMemo( () => configuredTools.map((tool) => { const id = toolMatchId(tool); return { id, name: id, description: tool.description, policy: resolveToolkitPolicy(id, accessPolicies, tool.requiresApproval), owner: toolOwner(tool), connection: toolConnectionName(tool), integration: String(tool.integration), }; }), [accessPolicies, configuredTools], ); const selectedTool = selectedToolId ? (configuredTools.find((tool) => toolMatchId(tool) === selectedToolId) ?? null) : null; const selectedToolPolicy = selectedTool ? (toolkitTools.find((tool) => tool.id === selectedToolId)?.policy ?? null) : null; return (
setAddOpen(true)} onRemove={props.onRemoveToolkit} />
setAddOpen(true)} onSelectTool={setSelectedToolId} onSetPolicy={(pattern, action) => void props.onSetPolicy(pattern, action)} onClearPolicy={(pattern) => void props.onClearPolicy(pattern)} />
{selectedTool && selectedToolPolicy ? ( ) : ( 0} /> )}
{ for (const pattern of patterns) { await props.onAddConnection(pattern); } }} onRemoveConnection={props.onRemoveConnection} />
); } function ToolkitTileSkeleton() { return ( ); } function ToolkitSectionSkeleton(props: { title?: string }) { return (
{props.title ? (

{props.title}

) : null}
); } function ToolkitGridSkeleton(props: { showOwnerLabels: boolean }) { return (
{props.showOwnerLabels ? ( <> ) : ( )}
); } function ToolkitDetailSkeleton() { return (
{Array.from({ length: 9 }).map((_, index) => (
))}
); } function ToolkitDetailView(props: { toolkit: ToolkitResponse; showOwnerLabels: boolean; tools: readonly ToolRow[]; integrations: readonly Integration[]; integrationPlugins: readonly IntegrationPlugin[]; orgSlug?: string; onBack: () => void; onRemoveToolkit: (toolkit: ToolkitResponse) => void; }) { const policies = useAtomValue(toolkitPoliciesAtom(props.toolkit.id)); const connections = useAtomValue(toolkitConnectionsAtom(props.toolkit.id)); const doCreatePolicy = useAtomSet(createToolkitPolicy, { mode: "promiseExit" }); const doUpdatePolicy = useAtomSet(updateToolkitPolicy, { mode: "promiseExit" }); const doRemovePolicy = useAtomSet(removeToolkitPolicy, { mode: "promiseExit" }); const doCreateConnection = useAtomSet(createToolkitConnection, { mode: "promiseExit" }); const doRemoveConnection = useAtomSet(removeToolkitConnection, { mode: "promiseExit" }); const policyRows = AsyncResult.isSuccess(policies) ? policies.value.policies : []; const connectionRows = AsyncResult.isSuccess(connections) ? connections.value.connections : []; const setPolicyHandler = async (pattern: string, action: ToolPolicyAction) => { const existing = policyRows.find((policy) => policy.pattern === pattern); if (existing) { await doUpdatePolicy({ params: { toolkitId: props.toolkit.id, policyId: existing.id }, payload: { action }, reactivityKeys: toolkitWriteKeys, }); return; } await doCreatePolicy({ params: { toolkitId: props.toolkit.id }, payload: { pattern, action }, reactivityKeys: toolkitWriteKeys, }); }; const addConnectionHandler = async (pattern: string) => { await doCreateConnection({ params: { toolkitId: props.toolkit.id }, payload: { pattern }, reactivityKeys: toolkitWriteKeys, }); }; const removeConnectionHandler = async (connectionId: string) => { await doRemoveConnection({ params: { toolkitId: props.toolkit.id, connectionId }, reactivityKeys: toolkitWriteKeys, }); }; const clearPolicyHandler = async (pattern: string) => { const existing = policyRows.find((policy) => policy.pattern === pattern); if (!existing) return; await doRemovePolicy({ params: { toolkitId: props.toolkit.id, policyId: existing.id }, reactivityKeys: toolkitWriteKeys, }); }; if (AsyncResult.isFailure(policies) || AsyncResult.isFailure(connections)) { return
Failed to load toolkit
; } if (!AsyncResult.isSuccess(policies) || !AsyncResult.isSuccess(connections)) { return ; } return ( props.onRemoveToolkit(props.toolkit)} onAddConnection={addConnectionHandler} onRemoveConnection={removeConnectionHandler} onSetPolicy={setPolicyHandler} onClearPolicy={clearPolicyHandler} /> ); } export function ToolkitsPage(props: PluginPageProps) { const navigate = useNavigate(); const organizationSlug = useOrganizationSlug(); const ownerDisplay = useOwnerDisplay(); const integrationPlugins = useIntegrationPlugins(); const toolkits = useAtomValue(toolkitsAtom); const tools = useAtomValue(toolsAllAtom); const integrations = useAtomValue(integrationsOptimisticAtom); const doCreateToolkit = useAtomSet(createToolkit, { mode: "promiseExit" }); const doRemoveToolkit = useAtomSet(removeToolkit, { mode: "promiseExit" }); const selectedToolkitSlug = props.params.toolkitSlug ?? null; const toolkitRows = AsyncResult.isSuccess(toolkits) ? toolkits.value.toolkits : []; const selectedToolkit = selectedToolkitSlug === null ? null : toolkitByRouteSlug(toolkitRows, selectedToolkitSlug); const toolRows = AsyncResult.isSuccess(tools) ? (tools.value as readonly ToolRow[]) : []; const integrationRows = AsyncResult.isSuccess(integrations) ? (integrations.value as readonly Integration[]) : []; const toolkitsReady = AsyncResult.isSuccess(toolkits); const toolkitsFailed = AsyncResult.isFailure(toolkits); const toolsReady = AsyncResult.isSuccess(tools); const toolsFailed = AsyncResult.isFailure(tools); const navigateToIndex = () => navigate({ to: "/{-$orgSlug}/toolkits", }); const createToolkitHandler = async (input: { owner: Owner; name: string }) => { await doCreateToolkit({ payload: input, reactivityKeys: toolkitWriteKeys, }); }; const removeToolkitHandler = async (toolkit: ToolkitResponse) => { await doRemoveToolkit({ params: { toolkitId: toolkit.id }, reactivityKeys: toolkitWriteKeys, }); await navigateToIndex(); }; return (
{selectedToolkitSlug === null ? (

Toolkits

{AsyncResult.isSuccess(toolkits) && ( {toolkitRows.length} {toolkitRows.length === 1 ? "toolkit" : "toolkits"} )}
) : null} {selectedToolkitSlug !== null && !toolkitsReady ? ( toolkitsFailed ? (
Failed to load toolkit
) : ( ) ) : !toolkitsReady ? ( toolkitsFailed ? (
Failed to load toolkits
) : ( ) ) : selectedToolkit ? ( toolsFailed ? (
Failed to load toolkit tools
) : !toolsReady ? ( ) : ( void navigateToIndex()} onRemoveToolkit={removeToolkitHandler} /> ) ) : selectedToolkitSlug !== null ? (
Toolkit not found
) : ( )}
); }