chore: full stack stability and migration fixes, plus react UI progress
This commit is contained in:
132
control-plane-ui/src/pages/Database.tsx
Normal file
132
control-plane-ui/src/pages/Database.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
import React, { useState } from 'react'
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
Paper,
|
||||
Grid,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Divider,
|
||||
CircularProgress,
|
||||
Chip,
|
||||
} from '@mui/material'
|
||||
import {
|
||||
TableChart as TableIcon,
|
||||
Storage as SchemaIcon,
|
||||
ChevronRight as ChevronRightIcon,
|
||||
} from '@mui/icons-material'
|
||||
import { DataGrid, GridColDef } from '@mui/x-data-grid'
|
||||
import { useDatabase } from '../hooks/useDatabase'
|
||||
import { DbTable } from '../services/api'
|
||||
|
||||
export default function Database() {
|
||||
const { tables, isLoadingTables, useTableData } = useDatabase()
|
||||
const [selectedTable, setSelectedTable] = useState<DbTable | null>(null)
|
||||
|
||||
const { data: rows, isLoading: isLoadingData } = useTableData(
|
||||
selectedTable?.schema || null,
|
||||
selectedTable?.name || null
|
||||
)
|
||||
|
||||
const columns: GridColDef[] = rows && rows.length > 0
|
||||
? Object.keys(rows[0]).map(key => ({
|
||||
field: key,
|
||||
headerName: key.charAt(0).toUpperCase() + key.slice(1).replace(/_/g, ' '),
|
||||
flex: 1,
|
||||
minWidth: 150,
|
||||
}))
|
||||
: []
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<Typography variant="h4" gutterBottom>
|
||||
Database Browser
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Explore and manage your project's database tables and data
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Grid container spacing={3}>
|
||||
{/* Table List */}
|
||||
<Grid item xs={12} md={3}>
|
||||
<Paper sx={{ height: 600, overflow: 'auto' }}>
|
||||
<Box sx={{ p: 2, bgcolor: 'background.paper', position: 'sticky', top: 0, zIndex: 1 }}>
|
||||
<Typography variant="h6">Tables</Typography>
|
||||
</Box>
|
||||
<Divider />
|
||||
{isLoadingTables ? (
|
||||
<Box sx={{ p: 3, textAlign: 'center' }}>
|
||||
<CircularProgress size={24} />
|
||||
</Box>
|
||||
) : (
|
||||
<List disablePadding>
|
||||
{tables.map((table) => (
|
||||
<ListItem key={`${table.schema}.${table.name}`} disablePadding>
|
||||
<ListItemButton
|
||||
selected={selectedTable?.name === table.name && selectedTable?.schema === table.schema}
|
||||
onClick={() => setSelectedTable(table)}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<TableIcon color="primary" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={table.name}
|
||||
secondary={table.schema}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
)}
|
||||
</Paper>
|
||||
</Grid>
|
||||
|
||||
{/* Data View */}
|
||||
<Grid item xs={12} md={9}>
|
||||
<Paper sx={{ height: 600, display: 'flex', flexDirection: 'column' }}>
|
||||
{!selectedTable ? (
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', height: '100%', gap: 2 }}>
|
||||
<TableIcon sx={{ fontSize: 64, color: 'text.disabled' }} />
|
||||
<Typography color="text.secondary">Select a table to view data</Typography>
|
||||
</Box>
|
||||
) : (
|
||||
<Box sx={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
|
||||
<Box sx={{ p: 2, display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<SchemaIcon color="action" fontSize="small" />
|
||||
<Typography variant="h6">{selectedTable.schema}.</Typography>
|
||||
<Typography variant="h6" color="primary">{selectedTable.name}</Typography>
|
||||
</Box>
|
||||
<Divider />
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
{isLoadingData ? (
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
) : (
|
||||
<DataGrid
|
||||
rows={rows || []}
|
||||
columns={columns}
|
||||
getRowId={(row) => row.id || row.uuid || JSON.stringify(row)}
|
||||
pageSizeOptions={[10, 25, 50]}
|
||||
initialState={{
|
||||
pagination: {
|
||||
paginationModel: { pageSize: 10 },
|
||||
},
|
||||
}}
|
||||
disableRowSelectionOnClick
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Paper>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user