import { useParams } from 'common' import AlertError from 'components/ui/AlertError' import CodeEditor from 'components/ui/CodeEditor/CodeEditor' import SchemaSelector from 'components/ui/SchemaSelector' import { useDatabaseIndexDeleteMutation } from 'data/database-indexes/index-delete-mutation' import { useIndexesQuery, type DatabaseIndex } 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 { sortBy } from 'lodash' import { AlertCircle, Search, Trash } from 'lucide-react' import { parseAsBoolean, parseAsString, useQueryState } from 'nuqs' import { useEffect } from 'react' import { toast } from 'sonner' import { Button, Card, SidePanel, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from 'ui' import { Input } from 'ui-patterns/DataInputs/Input' import { ConfirmationModal } from 'ui-patterns/Dialogs/ConfirmationModal' import { GenericSkeletonLoader, ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' import { ProtectedSchemaWarning } from '../ProtectedSchemaWarning' import { CreateIndexSidePanel } from './CreateIndexSidePanel' const Indexes = () => { const { data: project } = useSelectedProjectQuery() const { schema: urlSchema, table } = useParams() const [search, setSearch] = useQueryState('search', parseAsString.withDefault('')) const { selectedSchema, setSelectedSchema } = useQuerySchemaState() const { data: allIndexes, error: indexesError, isPending: isLoadingIndexes, isSuccess: isSuccessIndexes, isError: isErrorIndexes, } = useIndexesQuery({ schema: selectedSchema, projectRef: project?.ref, connectionString: project?.connectionString, }) const [showCreateIndex, setShowCreateIndex] = useQueryState( 'new', parseAsBoolean.withDefault(false) ) const [editIndexId, setEditIndexId] = useQueryState('edit', parseAsString) const selectedIndex = allIndexes?.find((idx) => idx.name === editIndexId) const [deleteIndexId, setDeleteIndexId] = useQueryState('delete', parseAsString) const selectedIndexToDelete = allIndexes?.find((idx) => idx.name === deleteIndexId) const { data: schemas, isPending: isLoadingSchemas, isSuccess: isSuccessSchemas, isError: isErrorSchemas, } = useSchemasQuery({ projectRef: project?.ref, connectionString: project?.connectionString, }) const { mutate: deleteIndex, isPending: isExecuting, isSuccess: isSuccessDelete, } = useDatabaseIndexDeleteMutation({ onSuccess: async () => { setDeleteIndexId(null) 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]) useEffect(() => { if (isSuccessIndexes && !!editIndexId && !selectedIndex) { toast('Index not found') setEditIndexId(null) } }, [isSuccessIndexes, editIndexId, selectedIndex, setEditIndexId]) useEffect(() => { if (isSuccessIndexes && !!deleteIndexId && !selectedIndexToDelete && !isSuccessDelete) { toast('Index not found') setDeleteIndexId(null) } }, [isSuccessIndexes, deleteIndexId, selectedIndexToDelete, isSuccessDelete, setDeleteIndexId]) return ( <>
Failed to load schemas
{selectedIndex?.name}
>
}
onCancel={() => setEditIndexId(null)}
>
{selectedIndexToDelete?.name}
>
}
confirmLabel="Confirm delete"
confirmLabelLoading="Deleting..."
onConfirm={() =>
selectedIndexToDelete !== undefined ? onConfirmDeleteIndex(selectedIndexToDelete) : {}
}
onCancel={() => setDeleteIndexId(null)}
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.',
}}
>