import { useEffect, useState } from "react"; import { getExecutorApiBaseUrl, useExecutorMutation, useWorkspaceRequestContext, } from "@executor/react"; import type { SecretStoreCreateFormProps, } from "@executor/react/plugins"; import { Alert, Button, Input, Label, Select, } from "@executor/react/plugins"; import { type OnePasswordDiscoverVaultsInput, type OnePasswordDiscoverVaultsResult, type OnePasswordStoreAuth, type OnePasswordVault, } from "@executor/plugin-onepassword-shared"; export function OnePasswordSecretStoreCreateForm( props: SecretStoreCreateFormProps, ) { const workspace = useWorkspaceRequestContext(); const [name, setName] = useState(""); const [authKind, setAuthKind] = useState<"desktop-app" | "service-account">( "desktop-app", ); const [accountName, setAccountName] = useState(""); const [vaultId, setVaultId] = useState(""); const [tokenSecretId, setTokenSecretId] = useState(""); const [discoveredVaults, setDiscoveredVaults] = useState>( [], ); const [error, setError] = useState(null); const discoverVaultsMutation = useExecutorMutation< OnePasswordDiscoverVaultsInput, OnePasswordDiscoverVaultsResult >(async (payload) => { if (!workspace.enabled) { throw new Error("Workspace is still loading."); } const response = await fetch( `${getExecutorApiBaseUrl()}/v1/workspaces/${workspace.workspaceId}/plugins/onepassword/vaults/discover`, { method: "POST", headers: { "content-type": "application/json", }, body: JSON.stringify(payload), }, ); if (!response.ok) { let message = "Failed loading 1Password vaults."; try { const responseError = await response.json() as { message?: string; details?: string; }; message = responseError.message ?? responseError.details ?? message; } catch { // ignore response parsing errors } throw new Error(message); } return await response.json() as OnePasswordDiscoverVaultsResult; }); useEffect(() => { setDiscoveredVaults([]); discoverVaultsMutation.reset(); }, [accountName, authKind, discoverVaultsMutation.reset, tokenSecretId]); const onePasswordAuth = (): OnePasswordStoreAuth | null => { if (authKind === "desktop-app") { const trimmedAccountName = accountName.trim(); if (!trimmedAccountName) { return null; } return { kind: "desktop-app", accountName: trimmedAccountName, }; } if (!tokenSecretId) { return null; } return { kind: "service-account", tokenSecretRef: { secretId: tokenSecretId as Extract< OnePasswordStoreAuth, { kind: "service-account" } >["tokenSecretRef"]["secretId"], }, }; }; const handleDiscoverVaults = async () => { setError(null); const auth = onePasswordAuth(); if (!auth) { setError( authKind === "desktop-app" ? "Enter your 1Password account name before loading vaults." : "Select a service-account token secret before loading vaults.", ); return; } try { const result = await discoverVaultsMutation.mutateAsync({ auth }); setDiscoveredVaults(result.vaults); if (!vaultId.trim() && result.vaults.length > 0) { setVaultId(result.vaults[0]!.id); } if (result.vaults.length === 0) { setError("No accessible vaults were returned for this 1Password account."); } } catch (cause) { setDiscoveredVaults([]); setError( cause instanceof Error ? cause.message : "Failed loading 1Password vaults.", ); } }; const handleSubmit = async () => { setError(null); const trimmedName = name.trim(); if (!trimmedName) { setError("Store name is required."); return; } if (authKind === "desktop-app" && !accountName.trim()) { setError("Account name is required for desktop app auth."); return; } if (!vaultId.trim()) { setError("Vault ID is required."); return; } if (authKind === "service-account" && !tokenSecretId) { setError("Select a secret that contains the 1Password service account token."); return; } try { await props.onSubmit({ name: trimmedName, config: { vaultId: vaultId.trim(), auth: onePasswordAuth()!, }, }); } catch (cause) { setError( cause instanceof Error ? cause.message : "Failed creating secret store.", ); } }; return (
{error && ( {error} )}
setName(event.target.value)} placeholder="Team 1Password" autoFocus />
{authKind === "desktop-app" ? (
setAccountName(event.target.value)} placeholder="my.1password.com" />
Use the account shown in the 1Password desktop app sidebar or the account UUID from op account list --format json.
) : (
Use this for remote or headless automation. Desktop app auth is better for local Executor use.
)} {discoveredVaults.length > 0 && (
Pick from the vaults visible to this account, or override the id below.
)}
setVaultId(event.target.value)} placeholder="vlt_..." className="font-mono text-[12px]" />
); }