'use client'; import AddIcon from '@mui/icons-material/Add'; import DeleteIcon from '@mui/icons-material/Delete'; import SpeedIcon from '@mui/icons-material/Speed'; import { Box, Button, Checkbox, Chip, FormControl, FormControlLabel, IconButton, InputLabel, List, ListItem, ListItemIcon, ListItemText, MenuItem, Paper, Select, TextField, Tooltip, Typography, } from '@mui/material'; import { useState } from 'react'; import { getFeatureById, getIndexTypes } from '@/utils/featureConfig'; import ConfirmDialog from './ConfirmDialog'; type IndexManagerTabProps = { tables: Array<{ table_name: string }>; onRefresh: () => void; }; export default function IndexManagerTab({ tables, onRefresh, }: IndexManagerTabProps) { const [selectedTable, setSelectedTable] = useState(''); const [indexes, setIndexes] = useState([]); const [availableColumns, setAvailableColumns] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const [success, setSuccess] = useState(''); // Create index form state const [openCreateDialog, setOpenCreateDialog] = useState(false); const [indexName, setIndexName] = useState(''); const [selectedColumns, setSelectedColumns] = useState([]); const [indexType, setIndexType] = useState('BTREE'); const [isUnique, setIsUnique] = useState(false); // Delete confirmation const [deleteIndex, setDeleteIndex] = useState(null); const feature = getFeatureById('index-management'); const INDEX_TYPES = getIndexTypes(); // Fetch indexes for selected table const fetchIndexes = async (tableName: string) => { try { setLoading(true); setError(''); const response = await fetch(`/api/admin/indexes?tableName=${tableName}`); const data = await response.json(); if (response.ok) { setIndexes(data.indexes || []); } else { setError(data.error || 'Failed to fetch indexes'); } } catch (err: any) { setError(err.message || 'Failed to fetch indexes'); } finally { setLoading(false); } }; // Fetch columns for selected table const fetchColumns = async (tableName: string) => { try { const response = await fetch('/api/admin/table-schema', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tableName }), }); if (response.ok) { const data = await response.json(); const cols = data.columns.map((col: any) => col.column_name); setAvailableColumns(cols); } } catch (err) { console.error('Failed to fetch columns:', err); } }; // Handle table selection const handleTableChange = async (tableName: string) => { setSelectedTable(tableName); setIndexes([]); setError(''); setSuccess(''); if (tableName) { await Promise.all([ fetchIndexes(tableName), fetchColumns(tableName), ]); } }; // Handle create index const handleCreateIndex = async () => { if (!indexName || selectedColumns.length === 0) { setError('Index name and at least one column are required'); return; } try { setLoading(true); setError(''); const response = await fetch('/api/admin/indexes', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tableName: selectedTable, indexName, columns: selectedColumns, indexType, unique: isUnique, }), }); const data = await response.json(); if (response.ok) { setSuccess(`Index "${indexName}" created successfully`); setOpenCreateDialog(false); setIndexName(''); setSelectedColumns([]); setIndexType('BTREE'); setIsUnique(false); await fetchIndexes(selectedTable); onRefresh(); } else { setError(data.error || 'Failed to create index'); } } catch (err: any) { setError(err.message || 'Failed to create index'); } finally { setLoading(false); } }; // Handle delete index const handleDeleteIndex = async () => { if (!deleteIndex) return; try { setLoading(true); setError(''); const response = await fetch('/api/admin/indexes', { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ indexName: deleteIndex }), }); const data = await response.json(); if (response.ok) { setSuccess(`Index "${deleteIndex}" dropped successfully`); setDeleteIndex(null); await fetchIndexes(selectedTable); onRefresh(); } else { setError(data.error || 'Failed to drop index'); } } catch (err: any) { setError(err.message || 'Failed to drop index'); } finally { setLoading(false); } }; return ( <> {feature?.name || 'Index Management'} {feature?.description && ( {feature.description} )} {/* Success/Error Messages */} {success && ( {success} )} {error && ( {error} )} {/* Table Selection */} Select Table {selectedTable && ( )} {/* Indexes List */} {selectedTable && indexes.length > 0 && ( Indexes on {selectedTable} {indexes.map(index => ( setDeleteIndex(index.index_name)} > ) )} > {index.index_name} {index.is_primary && } {index.is_unique && !index.is_primary && } )} secondary={`Columns: ${index.columns.join(', ')}`} /> ))} )} {selectedTable && indexes.length === 0 && !loading && ( No indexes found for table "{selectedTable}" )} {/* Create Index Dialog */} {openCreateDialog && ( Create Index on {selectedTable} setIndexName(e.target.value)} sx={{ mt: 2 }} placeholder="e.g., idx_users_email" /> Columns Index Type setIsUnique(e.target.checked)} /> } label="Unique Index" sx={{ mt: 2 }} /> )} {/* Overlay for create dialog */} {openCreateDialog && ( setOpenCreateDialog(false)} /> )} {/* Delete Confirmation Dialog */} setDeleteIndex(null)} /> ); }