feat: initialize backend database service architecture and implement frontend schema explorer components
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import { Box, Paper, Typography, CircularProgress } from '@mui/material';
|
||||
import DataGrid, {
|
||||
Column,
|
||||
@@ -10,40 +10,65 @@ import DataGrid, {
|
||||
Export
|
||||
} from 'devextreme-react/data-grid';
|
||||
import { useAppStore } from '../store/useAppStore';
|
||||
import { SchemaService } from '../services/api';
|
||||
import api, { SchemaService } from '../services/api';
|
||||
|
||||
import CustomStore from 'devextreme/data/custom_store';
|
||||
|
||||
const MainContent: React.FC = () => {
|
||||
const { activeTable, activeDatabase } = useAppStore();
|
||||
const [data, setData] = useState<any[]>([]);
|
||||
const [columns, setColumns] = useState<any[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loadingSchema, setLoadingSchema] = useState(false);
|
||||
|
||||
// Define data source with CustomStore for Remote Operations
|
||||
const dataSource = useMemo(() => {
|
||||
if (!activeTable || !activeDatabase) return null;
|
||||
|
||||
return new CustomStore({
|
||||
key: 'id', // Ideally this should be the primary key from schema
|
||||
load: async (loadOptions: any) => {
|
||||
try {
|
||||
const params = {
|
||||
skip: loadOptions.skip || 0,
|
||||
take: loadOptions.take || 100,
|
||||
requireTotalCount: loadOptions.requireTotalCount,
|
||||
database: activeDatabase,
|
||||
};
|
||||
|
||||
const response = await SchemaService.getTableData(activeTable, params);
|
||||
|
||||
return {
|
||||
data: response.data.data,
|
||||
totalCount: response.data.totalCount,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Data loading error', error);
|
||||
throw 'Data Loading Error';
|
||||
}
|
||||
}
|
||||
});
|
||||
}, [activeTable, activeDatabase]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTableData = async () => {
|
||||
const fetchSchema = async () => {
|
||||
if (!activeTable || !activeDatabase) return;
|
||||
|
||||
setLoading(true);
|
||||
setLoadingSchema(true);
|
||||
try {
|
||||
// Fetch schema for columns
|
||||
const schemaRes = await SchemaService.getTableSchema(activeTable);
|
||||
const schemaRes = await SchemaService.getTableSchema(activeTable, activeDatabase);
|
||||
const cols = schemaRes.data.map((col: any) => ({
|
||||
dataField: col.Field,
|
||||
caption: col.Field,
|
||||
dataType: mapSqlTypeToDxType(col.Type)
|
||||
}));
|
||||
setColumns(cols);
|
||||
|
||||
// Fetch actual data
|
||||
const dataRes = await SchemaService.getTableData(activeTable, activeDatabase);
|
||||
setData(dataRes.data);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch table data', error);
|
||||
console.error('Failed to fetch table schema', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setLoadingSchema(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchTableData();
|
||||
fetchSchema();
|
||||
}, [activeTable, activeDatabase]);
|
||||
|
||||
// Helper to map SQL types to DevExtreme types
|
||||
@@ -72,13 +97,14 @@ const MainContent: React.FC = () => {
|
||||
</Box>
|
||||
|
||||
<Paper sx={{ height: 'calc(100vh - 180px)', borderRadius: 2, overflow: 'hidden' }}>
|
||||
{loading ? (
|
||||
{loadingSchema ? (
|
||||
<Box sx={{ display: 'flex', height: '100%', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
) : (
|
||||
<DataGrid
|
||||
dataSource={data}
|
||||
dataSource={dataSource}
|
||||
remoteOperations={true}
|
||||
showBorders={true}
|
||||
focusedRowEnabled={true}
|
||||
columnAutoWidth={true}
|
||||
@@ -86,7 +112,7 @@ const MainContent: React.FC = () => {
|
||||
rowAlternationEnabled={true}
|
||||
height="100%"
|
||||
>
|
||||
<Scrolling mode="virtual" />
|
||||
<Scrolling mode="virtual" rowRenderingMode="virtual" />
|
||||
<FilterRow visible={true} />
|
||||
<HeaderFilter visible={true} />
|
||||
<SearchPanel visible={true} width={240} placeholder="Search..." />
|
||||
|
||||
Reference in New Issue
Block a user