import Link from 'next/link' import { useEffect, useMemo, useState } from 'react' import toast from 'react-hot-toast' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import { CodeEditor } from 'components/ui/CodeEditor' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useIndexesQuery } from 'data/database/indexes-query' import { useSchemasQuery } from 'data/database/schemas-query' import { useTableColumnsQuery } from 'data/database/table-columns-query' import { useEntityTypesQuery } from 'data/entity-types/entity-types-infinite-query' import { useExecuteSqlMutation } from 'data/sql/execute-sql-mutation' import { Button, Input, Listbox, SidePanel } from 'ui' import MultiSelect, { MultiSelectOption } from 'ui-patterns/MultiSelect' import { INDEX_TYPES } from './Indexes.constants' interface CreateIndexSidePanelProps { visible: boolean onClose: () => void } const CreateIndexSidePanel = ({ visible, onClose }: CreateIndexSidePanelProps) => { const { project } = useProjectContext() const [selectedSchema, setSelectedSchema] = useState('public') const [selectedEntity, setSelectedEntity] = useState('---') const [selectedColumns, setSelectedColumns] = useState([]) const [selectedIndexType, setSelectedIndexType] = useState(INDEX_TYPES[0].value) const { refetch: refetchIndexes } = useIndexesQuery({ schema: selectedSchema, projectRef: project?.ref, connectionString: project?.connectionString, }) const { data: schemas } = useSchemasQuery({ projectRef: project?.ref, connectionString: project?.connectionString, }) const { data: entities } = useEntityTypesQuery({ schema: selectedSchema, sort: 'alphabetical', search: undefined, projectRef: project?.ref, connectionString: project?.connectionString, }) const { data: tableColumns, isLoading: isLoadingTableColumns, isSuccess: isSuccessTableColumns, } = useTableColumnsQuery({ schema: selectedSchema, table: selectedEntity, projectRef: project?.ref, connectionString: project?.connectionString, }) const { mutate: execute, isLoading: isExecuting } = useExecuteSqlMutation({ onSuccess: async () => { await refetchIndexes() onClose() toast.success(`Successfully created index`) }, onError: (error) => { toast.error(`Failed to create index: ${error.message}`) }, }) const entityTypes = useMemo( () => entities?.pages.flatMap((page) => page.data.entities) || [], [entities?.pages] ) const columns = tableColumns?.result[0]?.columns ?? [] const columnOptions: MultiSelectOption[] = columns.map((column) => { return { id: column.attname, value: column.attname, name: column.attname, disabled: false } }) const generatedSQL = ` CREATE INDEX ON "${selectedSchema}"."${selectedEntity}" USING ${selectedIndexType} (${selectedColumns.join( ', ' )}); `.trim() const onSaveIndex = () => { if (!project) return console.error('Project is required') execute({ projectRef: project.ref, connectionString: project.connectionString, sql: generatedSQL, }) } useEffect(() => { if (visible) { setSelectedSchema('public') setSelectedEntity('---') setSelectedColumns([]) setSelectedIndexType(INDEX_TYPES[0].value) } }, [visible]) useEffect(() => { setSelectedEntity('---') setSelectedColumns([]) setSelectedIndexType(INDEX_TYPES[0].value) }, [selectedSchema]) useEffect(() => { setSelectedColumns([]) setSelectedIndexType(INDEX_TYPES[0].value) }, [selectedEntity]) return ( onSaveIndex()} loading={isExecuting} confirmText="Create index" >
{(schemas ?? []).map((schema) => ( {schema.name} ))} {entityTypes.length === 0 ? (

Select a table

) : ( --- {(entityTypes ?? []).map((entity) => ( {entity.name} ))} )} {selectedEntity !== '---' && (

Select up to 32 columns

{isLoadingTableColumns && } {isSuccessTableColumns && ( )}
)}
{selectedColumns.length > 0 && ( <> {INDEX_TYPES.map((index) => (

{index.name}

{index.description.split('\n').map((x, idx) => (

{x}

))}
))}

Preview of SQL statement

)}
) } export default CreateIndexSidePanel