/* Copyright 2026 Marimo. All rights reserved. */
import { zodResolver } from "@hookform/resolvers/zod";
import React from "react";
import { type DefaultValues, type FieldValues, useForm } from "react-hook-form";
import type { z } from "zod";
import { type FormRenderer, ZodForm } from "@/components/forms/form";
import { getDefaults } from "@/components/forms/form-utils";
import { Button } from "@/components/ui/button";
import { FormErrorsBanner } from "@/components/ui/form";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { useCellActions } from "@/core/cells/cells";
import { useLastFocusedCellId } from "@/core/cells/focus";
import { ENV_RENDERER, SecretsProvider } from "./form-renderers";
const RENDERERS: FormRenderer[] = [ENV_RENDERER];
/**
* Grid layout for provider/database selector buttons.
*/
export const SelectorGrid: React.FC<{ children: React.ReactNode }> = ({
children,
}) =>
{children}
;
/**
* A colored button tile for selecting a provider/database.
*/
export const SelectorButton: React.FC<{
name: string;
color: string;
icon: React.ReactNode;
onSelect: () => void;
}> = ({ name, color, icon, onSelect }) => (
);
/**
* Footer with Back/Add buttons and a library picker.
*/
export const ConnectionFormFooter = ({
onBack,
isValid,
libraries,
preferredLibrary,
onLibraryChange,
displayNames,
libraryLabel = "Preferred library",
}: {
onBack: () => void;
isValid: boolean;
libraries: L[];
preferredLibrary: L;
onLibraryChange: (library: L) => void;
displayNames: Record;
libraryLabel?: string;
}) => (
);
/**
* Returns a callback that inserts code into a new cell after the last focused cell.
*/
export function useInsertCode() {
const { createNewCell } = useCellActions();
const lastFocusedCellId = useLastFocusedCellId();
return (code: string) => {
createNewCell({
code,
before: false,
cellId: lastFocusedCellId ?? "__end__",
skipIfCodeExists: true,
});
};
}
/**
* Generic connection form: Zod-driven form with secrets support, a library
* picker, and Back/Add buttons. Used by both database and storage forms.
*/
export const ConnectionForm = ({
schema,
libraries,
preferredLibrary: initialPreferred,
displayNames,
libraryLabel,
generateCode,
onSubmit,
onBack,
}: {
schema: z.ZodType;
libraries: L[];
preferredLibrary: L;
displayNames: Record;
libraryLabel?: string;
generateCode: (values: T, library: L) => string;
onSubmit: () => void;
onBack: () => void;
}) => {
const defaults = getDefaults(schema);
const form = useForm({
defaultValues: defaults as DefaultValues,
resolver: zodResolver(schema),
reValidateMode: "onChange",
});
const [preferredLibrary, setPreferredLibrary] =
React.useState(initialPreferred);
const insertCode = useInsertCode();
const handleSubmit = (values: T) => {
insertCode(generateCode(values, preferredLibrary));
onSubmit();
};
return (
);
};