/* Copyright 2026 Marimo. All rights reserved. */ import { KeyIcon, PlusCircleIcon } from "lucide-react"; import { createContext, type ReactNode, use } from "react"; import { z } from "zod"; import type { FormRenderer } from "@/components/forms/form"; import { FieldOptions } from "@/components/forms/options"; import { useImperativeModal } from "@/components/modal/ImperativeModal"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { NumberField } from "@/components/ui/number-field"; import { SECRETS_REGISTRY } from "@/core/secrets/request-registry"; import { useAsyncData } from "@/hooks/useAsyncData"; import { partition } from "@/utils/arrays"; import { cn } from "@/utils/cn"; import { Functions } from "@/utils/functions"; import { sortProviders, WriteSecretModal, } from "../chrome/panels/write-secret-modal"; import { displaySecret, isSecret, prefixSecret } from "./secrets"; interface SecretsContextType { providerNames: string[]; secretKeys: string[]; loading: boolean; error: Error | undefined; refreshSecrets: () => void; } const SecretsContext = createContext({ providerNames: [], secretKeys: [], loading: false, error: undefined, refreshSecrets: Functions.NOOP, }); export const useSecrets = () => use(SecretsContext); interface SecretsProviderProps { children: ReactNode; } export const SecretsProvider = ({ children }: SecretsProviderProps) => { const { data, isPending, error, refetch: reload, } = useAsyncData(async () => { const result = await SECRETS_REGISTRY.request({}); // Provider names without 'env' provider const providerNames = sortProviders(result.secrets) .filter((provider) => provider.provider !== "env") .map((provider) => provider.name); return { secretKeys: result.secrets.flatMap((secret) => secret.keys).toSorted(), providerNames: providerNames, }; }, []); return ( {children} ); }; export const ENV_RENDERER: FormRenderer = { isMatch: (schema: z.ZodType): schema is z.ZodString | z.ZodNumber => { // string or number with optionsRegex if (schema instanceof z.ZodString || schema instanceof z.ZodNumber) { const { optionRegex } = FieldOptions.parse(schema.description || ""); return Boolean(optionRegex); } return false; }, Component: ({ schema, form, path }) => { const { secretKeys, providerNames, refreshSecrets } = useSecrets(); const { openModal, closeModal } = useImperativeModal(); const { label, description, optionRegex = "", } = FieldOptions.parse(schema.description || ""); const [recommendedKeys, otherKeys] = partition(secretKeys, (key) => new RegExp(optionRegex, "i").test(key), ); return ( ( {label} {description}
{schema instanceof z.ZodString ? ( ) : ( )} { openModal( { refreshSecrets(); field.onChange(prefixSecret(secretKey)); closeModal(); }} onClose={closeModal} />, ); }} > Create a new secret {recommendedKeys.length > 0 && ( <> Recommended )} {recommendedKeys.map((key) => ( field.onChange(prefixSecret(key))} > {displaySecret(key)} ))} {otherKeys.length > 0 && } {otherKeys.map((key) => ( field.onChange(prefixSecret(key))} > {displaySecret(key)} ))}
)} /> ); }, };