import { zodResolver } from '@hookform/resolvers/zod' import { Check, ChevronsUpDown, XIcon } from 'lucide-react' import { useEffect, useId, useMemo, useState } from 'react' import { Control, FieldValues, SubmitHandler, useFieldArray, useForm, useWatch, } from 'react-hook-form' import { Button, cn, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Form, FormControl, FormField, Input, Label, Popover, PopoverContent, PopoverTrigger, ScrollArea, Select, SelectContent, SelectItem, SelectSeparator, SelectTrigger, SelectValue, SidePanel, } from 'ui' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { MultiSelector, MultiSelectorContent, MultiSelectorItem, MultiSelectorList, MultiSelectorTrigger, } from 'ui-patterns/multi-select' import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' import * as z from 'zod' import { ColumnType } from './ColumnType' import type { AvailableColumn, Table, TableOption } from './Wrappers.types' import { getTableFormSchema } from './Wrappers.utils' import { ActionBar } from '@/components/interfaces/TableGridEditor/SidePanelEditor/ActionBar' import { useSchemasQuery } from '@/data/database/schemas-query' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' export type WrapperTableEditorProps = { visible: boolean onCancel: () => void onSave: (values: any) => void tables: Table[] initialData: any } const WrapperTableEditor = ({ visible, onCancel, onSave, tables, initialData, }: WrapperTableEditorProps) => { const [open, setOpen] = useState(false) const listboxId = useId() const [selectedTableIndex, setSelectedTableIndex] = useState('') useEffect(() => { if (initialData && Object.keys(initialData).length > 0) { setSelectedTableIndex(String(initialData.index)) } }, [initialData]) const selectedTable = selectedTableIndex === '' ? undefined : tables[parseInt(selectedTableIndex)] const handleCancel = () => { setSelectedTableIndex('') onCancel() } const onSubmit: SubmitHandler = (values) => { onSave({ ...values, index: parseInt(selectedTableIndex), schema_name: values.schema === 'custom' ? values.schema_name : values.schema, is_new_schema: values.schema === 'custom', }) setSelectedTableIndex('') } return ( Edit foreign table} customFooter={ } >
No targets found 7 ? 'h-[200px]' : ''}> {(tables ?? []).map((table, i) => ( { setSelectedTableIndex(String(i)) setOpen(false) }} onClick={() => { setSelectedTableIndex(String(i)) setOpen(false) }} >

{table.label}

{table.description}

{String(i) === selectedTableIndex && ( )}
))}
{selectedTable && ( )}
) } export default WrapperTableEditor const Option = ({ option, control }: { option: TableOption; control: Control }) => { if (option.type === 'select') { return ( ( )} /> ) } return ( ( )} /> ) } const TableForm = ({ table, onSubmit, initialData, }: { table: Table onSubmit: SubmitHandler initialData: any }) => { const { data: project } = useSelectedProjectQuery() const { data: schemas, isPending: isLoading } = useSchemasQuery({ projectRef: project?.ref, connectionString: project?.connectionString, }) const requiredOptions: TableOption[] = [] const optionalOptions: TableOption[] = [] const nonEditableOptions: TableOption[] = [] table.options.forEach((option) => { if (option.editable) { if (option.required && !option.defaultValue) { requiredOptions.push(option) return } optionalOptions.push(option) return } nonEditableOptions.push(option) }) const defaultValues = useMemo(() => { if (initialData && Object.keys(initialData).length > 0) { const { schema } = initialData const existingSchema = schemas?.find((s) => s.name === schema) return { schema_name: existingSchema ? '' : schema, schema: existingSchema ? existingSchema.name : 'custom', ...Object.fromEntries( table.options.map((option) => [option.name, option.defaultValue ?? '']) ), ...initialData, } } return { table_name: '', columns: table.availableColumns ?? [], schema: 'public', ...Object.fromEntries( table.options.map((option) => [option.name, option.defaultValue ?? '']) ), } }, [initialData, table, schemas]) const formSchema = getTableFormSchema(table) type FormSchema = z.infer const form = useForm({ defaultValues, resolver: zodResolver(formSchema as any), shouldUnregister: true, }) const { fields: columnFields, append: appendColumn, replace: replaceColumns, remove: removeColumn, } = useFieldArray({ control: form.control, name: 'columns', }) const { reset } = form useEffect(() => { reset(defaultValues) // Workaround bug in react-hook-form replaceColumns(defaultValues.columns ?? []) }, [reset, replaceColumns, defaultValues]) const handleSubmit: SubmitHandler = (values) => { const { schema_name, schema, ...valuesWithoutSchema } = values onSubmit({ ...valuesWithoutSchema, // Ensure all options are accounted for. ...Object.fromEntries( table.options.map((option) => [ option.name, values[option.name] ?? option.defaultValue ?? '', ]) ), schema, schema_name: schema === 'custom' ? schema_name : schema, is_new_schema: schema === 'custom', }) reset() } const { errors } = form.formState const schema = useWatch({ name: 'schema', control: form.control }) return (
{isLoading && } ( )} /> {schema === 'custom' && ( ( )} /> )} ( )} /> {requiredOptions.map((option) => (