feat: implement App layout and server-side paginated DataGrid for table views
This commit is contained in:
Generated
+1
@@ -8,6 +8,7 @@
|
|||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/cache": "^11.14.0",
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.14.1",
|
"@emotion/styled": "^11.14.1",
|
||||||
"@monaco-editor/react": "^4.7.0",
|
"@monaco-editor/react": "^4.7.0",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/cache": "^11.14.0",
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.14.1",
|
"@emotion/styled": "^11.14.1",
|
||||||
"@monaco-editor/react": "^4.7.0",
|
"@monaco-editor/react": "^4.7.0",
|
||||||
|
|||||||
+13
-1
@@ -1,5 +1,7 @@
|
|||||||
import React, { useMemo, useEffect } from 'react';
|
import React, { useMemo, useEffect } from 'react';
|
||||||
import { ThemeProvider, CssBaseline, Box } from '@mui/material';
|
import { ThemeProvider, CssBaseline, Box } from '@mui/material';
|
||||||
|
import { CacheProvider } from '@emotion/react';
|
||||||
|
import createCache from '@emotion/cache';
|
||||||
import { getTheme } from './theme/theme';
|
import { getTheme } from './theme/theme';
|
||||||
import { useAppStore } from './store/useAppStore';
|
import { useAppStore } from './store/useAppStore';
|
||||||
import Sidebar from './components/Sidebar.tsx';
|
import Sidebar from './components/Sidebar.tsx';
|
||||||
@@ -8,6 +10,12 @@ import Header from './components/Header.tsx';
|
|||||||
import Login from './components/Login.tsx';
|
import Login from './components/Login.tsx';
|
||||||
import NavigationRail from './components/NavigationRail.tsx';
|
import NavigationRail from './components/NavigationRail.tsx';
|
||||||
|
|
||||||
|
// Create emotion cache to handle the :first-child warning and ensure proper style injection
|
||||||
|
const cache = createCache({
|
||||||
|
key: 'mui',
|
||||||
|
prepend: true,
|
||||||
|
});
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const { darkMode, connected, activeTab, setActiveTab } = useAppStore();
|
const { darkMode, connected, activeTab, setActiveTab } = useAppStore();
|
||||||
const theme = useMemo(() => getTheme(darkMode ? 'dark' : 'light'), [darkMode]);
|
const theme = useMemo(() => getTheme(darkMode ? 'dark' : 'light'), [darkMode]);
|
||||||
@@ -22,25 +30,29 @@ const App: React.FC = () => {
|
|||||||
|
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
return (
|
return (
|
||||||
|
<CacheProvider value={cache}>
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
<Login />
|
<Login />
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
</CacheProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<CacheProvider value={cache}>
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
<Box sx={{ display: 'flex', height: '100vh', overflow: 'hidden' }}>
|
<Box sx={{ display: 'flex', height: '100vh', overflow: 'hidden' }}>
|
||||||
<NavigationRail activeTab={activeTab} onTabChange={setActiveTab} />
|
<NavigationRail activeTab={activeTab} onTabChange={setActiveTab} />
|
||||||
{activeTab === 'explorer' && <Sidebar />}
|
{activeTab === 'explorer' && <Sidebar />}
|
||||||
<Box sx={{ flexGrow: 1, display: 'flex', flexDirection: 'column' }}>
|
<Box sx={{ flexGrow: 1, display: 'flex', flexDirection: 'column', minWidth: 0, overflow: 'hidden' }}>
|
||||||
<Header />
|
<Header />
|
||||||
<MainContent />
|
<MainContent />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
</CacheProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ const MainContent: React.FC = () => {
|
|||||||
field: col.Field,
|
field: col.Field,
|
||||||
headerName: col.Field,
|
headerName: col.Field,
|
||||||
type: type,
|
type: type,
|
||||||
flex: 1,
|
width: 200,
|
||||||
minWidth: 150,
|
minWidth: 100,
|
||||||
valueGetter: (value: any) => {
|
valueGetter: (value: any) => {
|
||||||
if ((type === 'date' || type === 'dateTime') && value && typeof value === 'string') {
|
if ((type === 'date' || type === 'dateTime') && value && typeof value === 'string') {
|
||||||
return new Date(value);
|
return new Date(value);
|
||||||
@@ -109,14 +109,14 @@ const MainContent: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ flexGrow: 1, p: 3, bgcolor: 'background.default', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
|
<Box sx={{ flexGrow: 1, p: 3, bgcolor: 'background.default', display: 'flex', flexDirection: 'column', width: '100%', minWidth: 0, overflow: 'hidden' }}>
|
||||||
<Box sx={{ mb: 2, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
<Box sx={{ mb: 2, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
<Typography variant="h5" sx={{ fontWeight: 700 }}>
|
<Typography variant="h5" sx={{ fontWeight: 700 }}>
|
||||||
{activeDatabase}.{activeTable}
|
{activeDatabase}.{activeTable}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Paper sx={{ flexGrow: 1, borderRadius: 2, overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
|
<Paper sx={{ flexGrow: 1, borderRadius: 2, overflow: 'hidden', display: 'flex', flexDirection: 'column', width: '100%' }}>
|
||||||
{loadingSchema ? (
|
{loadingSchema ? (
|
||||||
<Box sx={{ display: 'flex', height: '100%', alignItems: 'center', justifyContent: 'center' }}>
|
<Box sx={{ display: 'flex', height: '100%', alignItems: 'center', justifyContent: 'center' }}>
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
@@ -133,13 +133,24 @@ const MainContent: React.FC = () => {
|
|||||||
pageSizeOptions={[25, 50, 100]}
|
pageSizeOptions={[25, 50, 100]}
|
||||||
sx={{
|
sx={{
|
||||||
border: 'none',
|
border: 'none',
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
'& .MuiDataGrid-cell:focus': {
|
'& .MuiDataGrid-cell:focus': {
|
||||||
outline: 'none',
|
outline: 'none',
|
||||||
},
|
},
|
||||||
'& .MuiDataGrid-columnHeader:focus': {
|
'& .MuiDataGrid-columnHeader:focus': {
|
||||||
outline: 'none',
|
outline: 'none',
|
||||||
},
|
},
|
||||||
height: '100%',
|
'& .MuiDataGrid-row:nth-of-type(even)': {
|
||||||
|
bgcolor: (theme) => theme.palette.mode === 'light'
|
||||||
|
? 'rgba(0, 0, 0, 0.03)'
|
||||||
|
: 'rgba(255, 255, 255, 0.03)',
|
||||||
|
},
|
||||||
|
'& .MuiDataGrid-row:hover': {
|
||||||
|
bgcolor: (theme) => theme.palette.mode === 'light'
|
||||||
|
? 'rgba(0, 97, 255, 0.08)'
|
||||||
|
: 'rgba(0, 97, 255, 0.15)',
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
loadingOverlay: {
|
loadingOverlay: {
|
||||||
|
|||||||
Reference in New Issue
Block a user