import { sortBy } from 'lodash' import { AlertCircle, Search, Trash } from 'lucide-react' import { useEffect, useState } from 'react' import { toast } from 'sonner' import { useParams } from 'common' import AlertError from 'components/ui/AlertError' import CodeEditor from 'components/ui/CodeEditor/CodeEditor' import SchemaSelector from 'components/ui/SchemaSelector' import ShimmeringLoader, { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader' import { useDatabaseIndexDeleteMutation } from 'data/database-indexes/index-delete-mutation' import { DatabaseIndex, useIndexesQuery } from 'data/database-indexes/indexes-query' import { useSchemasQuery } from 'data/database/schemas-query' import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { useIsProtectedSchema } from 'hooks/useProtectedSchemas' import { Button, Input, SidePanel, Table, TableBody, TableCell, TableHead, TableRow, TableHeader, Card, } from 'ui' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { ProtectedSchemaWarning } from '../ProtectedSchemaWarning' import CreateIndexSidePanel from './CreateIndexSidePanel' const Indexes = () => { const { data: project } = useSelectedProjectQuery() const { schema: urlSchema, table } = useParams() const [search, setSearch] = useState('') const { selectedSchema, setSelectedSchema } = useQuerySchemaState() const [showCreateIndex, setShowCreateIndex] = useState(false) const [selectedIndex, setSelectedIndex] = useState() const [selectedIndexToDelete, setSelectedIndexToDelete] = useState() const { data: allIndexes, error: indexesError, isLoading: isLoadingIndexes, isSuccess: isSuccessIndexes, isError: isErrorIndexes, } = useIndexesQuery({ schema: selectedSchema, projectRef: project?.ref, connectionString: project?.connectionString, }) const { data: schemas, isLoading: isLoadingSchemas, isSuccess: isSuccessSchemas, isError: isErrorSchemas, } = useSchemasQuery({ projectRef: project?.ref, connectionString: project?.connectionString, }) const { mutate: deleteIndex, isLoading: isExecuting } = useDatabaseIndexDeleteMutation({ onSuccess: async () => { setSelectedIndexToDelete(undefined) toast.success('Successfully deleted index') }, }) const { isSchemaLocked } = useIsProtectedSchema({ schema: selectedSchema }) const sortedIndexes = sortBy(allIndexes ?? [], (index) => index.name.toLocaleLowerCase()) const indexes = search.length > 0 ? sortedIndexes.filter((index) => index.name.includes(search) || index.table.includes(search)) : sortedIndexes const onConfirmDeleteIndex = (index: DatabaseIndex) => { if (!project) return console.error('Project is required') deleteIndex({ projectRef: project.ref, connectionString: project.connectionString, name: index.name, schema: selectedSchema, }) } useEffect(() => { if (urlSchema !== undefined) { const schema = schemas?.find((s) => s.name === urlSchema) if (schema !== undefined) setSelectedSchema(schema.name) } }, [urlSchema, isSuccessSchemas]) useEffect(() => { if (table !== undefined) setSearch(table) }, [table]) return ( <>
{isLoadingSchemas && } {isErrorSchemas && (

Failed to load schemas

)} {isSuccessSchemas && ( )} setSearch(e.target.value)} placeholder="Search for an index" icon={} /> {!isSchemaLocked && ( )}
{isSchemaLocked && } {isLoadingIndexes && } {isErrorIndexes && ( )} {isSuccessIndexes && (
Schema Table Name {sortedIndexes.length === 0 && search.length === 0 && (

No indexes created yet

There are no indexes found in the schema "{selectedSchema}"

)} {sortedIndexes.length === 0 && search.length > 0 && (

No results found

Your search for "{search}" did not return any results

)} {indexes.length > 0 && indexes.map((index) => (

{index.schema}

{index.table}

{index.name}

{!isSchemaLocked && (
))}
)}
Index: {selectedIndex?.name} } onCancel={() => setSelectedIndex(undefined)} >
setShowCreateIndex(false)} /> Confirm to delete index {selectedIndexToDelete?.name} } confirmLabel="Confirm delete" confirmLabelLoading="Deleting..." onConfirm={() => selectedIndexToDelete !== undefined ? onConfirmDeleteIndex(selectedIndexToDelete) : {} } onCancel={() => setSelectedIndexToDelete(undefined)} alert={{ title: 'This action cannot be undone', description: 'Deleting an index that is still in use will cause queries to slow down, and in some cases causing significant performance issues.', }} >
  • Before deleting this index, consider:
    • This index is no longer in use
    • The table which the index is on is not currently in use, as dropping an index requires a short exclusive access lock on the table.
) } export default Indexes