import { useQueryClient } from '@tanstack/react-query' import { isEmpty } from 'lodash' import { Edit, Trash } from 'lucide-react' import { useState } from 'react' import { toast } from 'sonner' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import { FormSection, FormSectionContent, FormSectionLabel } from 'components/ui/Forms/FormSection' import { invalidateSchemasQuery } from 'data/database/schemas-query' import { useFDWCreateMutation } from 'data/fdw/fdw-create-mutation' import { Button, Form, Input, SheetFooter, SheetHeader, SheetTitle } from 'ui' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import InputField from './InputField' import { WrapperMeta } from './Wrappers.types' import { makeValidateRequired } from './Wrappers.utils' import WrapperTableEditor from './WrapperTableEditor' export interface CreateWrapperSheetProps { isClosing: boolean wrapperMeta: WrapperMeta setIsClosing: (v: boolean) => void onClose: () => void } const FORM_ID = 'create-wrapper-form' export const CreateWrapperSheet = ({ wrapperMeta, isClosing, setIsClosing, onClose, }: CreateWrapperSheetProps) => { const queryClient = useQueryClient() const { project } = useProjectContext() const [newTables, setNewTables] = useState([]) const [isEditingTable, setIsEditingTable] = useState(false) const [selectedTableToEdit, setSelectedTableToEdit] = useState() const [formErrors, setFormErrors] = useState<{ [k: string]: string }>({}) const { mutate: createFDW, isLoading: isCreating } = useFDWCreateMutation({ onSuccess: () => { toast.success(`Successfully created ${wrapperMeta?.label} foreign data wrapper`) setNewTables([]) const hasNewSchema = newTables.some((table) => table.is_new_schema) if (hasNewSchema) invalidateSchemasQuery(queryClient, project?.ref) onClose() }, }) const initialValues = { wrapper_name: '', server_name: '', ...Object.fromEntries( wrapperMeta.server.options.map((option) => [option.name, option.defaultValue ?? '']) ), } const onUpdateTable = (values: any) => { setNewTables((prev) => { // if the new values have tableIndex, we are editing an existing table if (values.tableIndex !== undefined) { const tableIndex = values.tableIndex const newTables = [...prev] delete values.tableIndex newTables[tableIndex] = values return newTables } return [...prev, values] }) setIsEditingTable(false) setSelectedTableToEdit(undefined) } const onSubmit = async (values: any) => { const validate = makeValidateRequired(wrapperMeta.server.options) const errors: any = validate(values) const { wrapper_name } = values if (wrapper_name.length === 0) errors.name = 'Please provide a name for your wrapper' if (newTables.length === 0) errors.tables = 'Please add at least one table' if (!isEmpty(errors)) return setFormErrors(errors) createFDW({ projectRef: project?.ref, connectionString: project?.connectionString, wrapperMeta, formState: { ...values, server_name: `${wrapper_name}_server` }, tables: newTables, }) } return ( <>
{({ handleReset, values, initialValues }: any) => { const hasChanges = JSON.stringify(values) !== JSON.stringify(initialValues) const onClosePanel = () => { if (hasChanges) { setIsClosing(true) } else { onClose() } } // if the form hasn't been touched and the user clicked esc or the backdrop, close the sheet if (!hasChanges && isClosing) { onClose() } return ( <> Create a {wrapperMeta.label} wrapper
Wrapper Configuration}> 0 ? ( <> Your wrapper's server name will be{' '} {values.wrapper_name}_server ) : ( '' ) } /> {wrapperMeta.label} Configuration} > {wrapperMeta.server.options .filter((option) => !option.hidden) .map((option) => ( ))}

Foreign Tables

You can query your data from these foreign tables after the wrapper is created

} > {newTables.length === 0 ? (
) : (
{newTables.map((table, i) => (

{table.schema_name}.{table.table_name}

Columns:{' '} {table.columns.map((column: any) => column.name).join(', ')}

))}
)} {newTables.length > 0 && (
)} {newTables.length === 0 && formErrors.tables && (

{formErrors.tables}

)}
) }}
setIsClosing(false)} onConfirm={() => onClose()} >

There are unsaved changes. Are you sure you want to close the panel? Your changes will be lost.

{ setSelectedTableToEdit(undefined) setIsEditingTable(false) }} onSave={onUpdateTable} initialData={selectedTableToEdit} /> ) }