Files
madbase/control-plane-ui/src/pages/Database.tsx
Vlad Durnea a66d908eff
Some checks failed
CI / podman-build (push) Has been cancelled
CI / rust (push) Has been cancelled
chore: full stack stability and migration fixes, plus react UI progress
2026-03-18 09:01:38 +02:00

133 lines
4.6 KiB
TypeScript

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>
)
}