import { useState } from "react"; import { useAtomSet, useAtomValue, useAtomRefresh, Result } from "@effect-atom/atom-react"; import { secretsAtom, setSecret } from "@executor/react/api/atoms"; import { useScope } from "@executor/react/api/scope-context"; import { SecretPicker, type SecretPickerSecret } from "@executor/react/plugins/secret-picker"; import { SecretId } from "@executor/sdk"; import { Button } from "@executor/react/components/button"; import { Input } from "@executor/react/components/input"; import { Label } from "@executor/react/components/label"; import { Spinner } from "@executor/react/components/spinner"; import { addGraphqlSource } from "./atoms"; import type { HeaderValue } from "../sdk/types"; // --------------------------------------------------------------------------- // Inline secret creation // --------------------------------------------------------------------------- function InlineCreateSecret(props: { headerName: string; suggestedId: string; onCreated: (secretId: string) => void; onCancel: () => void; }) { const [secretId, setSecretId] = useState(props.suggestedId); const [secretName, setSecretName] = useState(props.headerName); const [secretValue, setSecretValue] = useState(""); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const scopeId = useScope(); const doSet = useAtomSet(setSecret, { mode: "promise" }); const refreshSecrets = useAtomRefresh(secretsAtom(scopeId)); const handleSave = async () => { if (!secretId.trim() || !secretValue.trim()) return; setSaving(true); setError(null); try { await doSet({ path: { scopeId }, payload: { id: SecretId.make(secretId.trim()), name: secretName.trim() || secretId.trim(), value: secretValue.trim(), purpose: `Auth header: ${props.headerName}`, }, }); refreshSecrets(); props.onCreated(secretId.trim()); } catch (e) { setError(e instanceof Error ? e.message : "Failed to save secret"); setSaving(false); } }; return (

New secret

setSecretId((e.target as HTMLInputElement).value)} placeholder="my-api-token" className="h-8 text-xs font-mono" />
setSecretName((e.target as HTMLInputElement).value)} placeholder="API Token" className="h-8 text-xs" />
setSecretValue((e.target as HTMLInputElement).value)} placeholder="paste your token or key..." className="h-8 text-xs font-mono" />
{error &&

{error}

}
); } // --------------------------------------------------------------------------- // Auth header row // --------------------------------------------------------------------------- function AuthHeaderRow(props: { selectedSecretId: string | null; onSelect: (secretId: string) => void; existingSecrets: readonly SecretPickerSecret[]; }) { const [creating, setCreating] = useState(false); const { selectedSecretId, onSelect, existingSecrets } = props; if (creating) { return ( { onSelect(id); setCreating(false); }} onCancel={() => setCreating(false)} /> ); } return (
); } // --------------------------------------------------------------------------- // Main component // --------------------------------------------------------------------------- export default function AddGraphqlSource(props: { onComplete: () => void; onCancel: () => void; initialUrl?: string; }) { const [endpoint, setEndpoint] = useState(props.initialUrl ?? ""); const [namespace, setNamespace] = useState(""); const [authSecretId, setAuthSecretId] = useState(null); const [adding, setAdding] = useState(false); const [addError, setAddError] = useState(null); const scopeId = useScope(); const doAdd = useAtomSet(addGraphqlSource, { mode: "promise" }); const secrets = useAtomValue(secretsAtom(scopeId)); const secretList: readonly SecretPickerSecret[] = Result.match(secrets, { onInitial: () => [] as SecretPickerSecret[], onFailure: () => [] as SecretPickerSecret[], onSuccess: ({ value }) => value.map((s) => ({ id: s.id, name: s.name, provider: s.provider ? String(s.provider) : undefined, })), }); const canAdd = endpoint.trim().length > 0; const handleAdd = async () => { setAdding(true); setAddError(null); try { const headers: Record = {}; if (authSecretId) { headers["Authorization"] = { secretId: authSecretId, prefix: "Bearer " }; } await doAdd({ path: { scopeId }, payload: { endpoint: endpoint.trim(), namespace: namespace.trim() || undefined, ...(Object.keys(headers).length > 0 ? { headers } : {}), }, }); props.onComplete(); } catch (e) { setAddError(e instanceof Error ? e.message : "Failed to add source"); setAdding(false); } }; return (

Add GraphQL Source

{/* Endpoint */}
setEndpoint((e.target as HTMLInputElement).value)} placeholder="https://api.example.com/graphql" className="font-mono text-sm" />

The endpoint will be introspected to discover available queries and mutations.

{/* Namespace */}
setNamespace((e.target as HTMLInputElement).value)} placeholder="my_api" className="font-mono text-sm" />

A prefix for the tool names. Derived from the endpoint hostname if not provided.

{/* Authentication */}

Select a secret for the Bearer token sent with every request, including introspection.

{/* Error */} {addError && (

{addError}

)} {/* Actions */}
); }