diff --git a/src/App.jsx b/src/App.jsx
index 2c7ac84..f7b07ad 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,4 +1,4 @@
-import { useState } from 'react'
+import { useState, useEffect } from 'react'
import './App.css'
import InfiniteCanvas from './components/InfiniteCanvas'
import AdvancedCharts from './components/AdvancedCharts'
@@ -8,6 +8,25 @@ import { FaDatabase, FaChartBar, FaProjectDiagram } from 'react-icons/fa'
function App() {
const [activeTab, setActiveTab] = useState('canvas'); // 'canvas', 'charts', or 'dataflow'
+ // Listen for the custom event to switch to DataFlow tab
+ useEffect(() => {
+ const handleViewDataFlow = (event) => {
+ // Switch to the dataflow tab
+ setActiveTab('dataflow');
+
+ // Log the database info (in a real app, you would use this to initialize the DataFlow view)
+ console.log('Viewing DataFlow for database:', event.detail);
+ };
+
+ // Add event listener
+ window.addEventListener('viewDataFlow', handleViewDataFlow);
+
+ // Clean up
+ return () => {
+ window.removeEventListener('viewDataFlow', handleViewDataFlow);
+ };
+ }, []);
+
return (
{
const [scale, setScale] = useState(1);
const [position, setPosition] = useState({ x: 0, y: 0 });
+ // State for selected database
+ const [selectedDatabase, setSelectedDatabase] = useState(null);
+
+ // Read selected database from localStorage on component mount
+ useEffect(() => {
+ try {
+ const dbData = localStorage.getItem('selectedDatabase');
+ if (dbData) {
+ const parsedData = JSON.parse(dbData);
+ setSelectedDatabase(parsedData);
+ console.log('DataFlow view initialized with database:', parsedData);
+ }
+ } catch (error) {
+ console.error('Error reading database from localStorage:', error);
+ }
+ }, []);
+
// State for connection mode
const [isConnectionMode, setIsConnectionMode] = useState(false);
const [connectionSource, setConnectionSource] = useState(null);
@@ -1553,6 +1570,47 @@ const DataflowCanvas = () => {
return (
+
+ {/* Database Header */}
+ {selectedDatabase && (
+
+
+
+
+
{selectedDatabase.name} Database
+
Data Flow View
+
+
+
+
+
+
+ )}
+
{
connectionLineType="bezier"
defaultMarkerColor="#00a99d"
>
+ {/* Empty Database Message */}
+ {nodes.length === 0 && selectedDatabase && (
+
+
+
+
+ {selectedDatabase.name} Database is Empty
+
+
+ This database doesn't have any tables or data flows yet. Start by adding tables and processes to visualize your data flow.
+
+
+
+
+
+
+ )}
+
{/* Process Details Popup */}
{showProcessPopup && selectedProcess && (
{
- {/* Schemas Section */}
-
-
-
-
-
-
- {formData.schemas.length > 0 ? (
-
- {formData.schemas.map((schema, index) => (
-
-
-
-
{schema.name}
-
- {schema.tables.length} tables
-
-
-
-
-
-
-
-
-
- {/* Tables within this schema */}
- {schema.tables.length > 0 && (
-
- {schema.tables.map((table, tableIndex) => (
-
-
- {table.name}
-
- {table.type}
-
-
-
-
- ))}
-
- )}
-
- ))}
-
- ) : (
-
- No schemas added yet. Click "Add Schema" to create one.
-
- )}
-
+ {/* Schemas Section removed as per requirements */}
-
+
{isDbtez ? 'Database' : `${data.schemas} schemas • ${data.tables} tables`}
+
+ {/* View Details Button */}
+
+
{
+ // Stop propagation to prevent the node click handler from being triggered
+ event.stopPropagation();
+ // Call the viewDetails function passed in data
+ if (data.onViewDetails) {
+ data.onViewDetails(data.id, data.label);
+ }
+ }}
+ style={{
+ padding: '4px 8px',
+ backgroundColor: isDbtez ? '#00a99d' : '#1890ff',
+ color: 'white',
+ border: 'none',
+ borderRadius: '3px',
+ cursor: 'pointer',
+ fontSize: '11px',
+ width: '100%',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ gap: '5px',
+ transition: 'all 0.2s'
+ }}
+ >
+
+ View Data Flow
+
+
);
};
@@ -1632,27 +1318,70 @@ const InfiniteCanvas = () => {
const [selectedDatabaseForSchema, setSelectedDatabaseForSchema] = useState(null);
const [selectedSchemaForTable, setSelectedSchemaForTable] = useState(null);
- // State for storing created entities
- const [databases, setDatabases] = useState([]);
- const [schemas, setSchemas] = useState([]);
- const [tables, setTables] = useState([]);
-
// Initialize with mock data
const mockData = generateMockData();
- // Initialize with default Dbtez database if no databases exist
- useEffect(() => {
- if (databases.length === 0) {
- setDatabases([{
- id: 'db4',
- name: 'Dbtez',
- description: 'Default database for data exploration',
- type: 'PostgreSQL',
- schemas: mockData.schemas.length,
- tables: mockData.tables.length
- }]);
+ // State for storing created entities
+ const [databases, setDatabases] = useState(() => {
+ // Try to load databases from localStorage
+ try {
+ const savedDatabases = localStorage.getItem('databases');
+ if (savedDatabases) {
+ return JSON.parse(savedDatabases);
+ }
+ } catch (error) {
+ console.error('Error loading databases from localStorage:', error);
}
- }, []);
+
+ // If no saved databases, return default Dbtez database
+ return [{
+ id: 'db4',
+ name: 'Dbtez',
+ description: 'Default database for data exploration',
+ type: 'PostgreSQL',
+ schemas: mockData.schemas.length,
+ tables: mockData.tables.length
+ }];
+ });
+
+ const [schemas, setSchemas] = useState(() => {
+ // Try to load schemas from localStorage
+ try {
+ const savedSchemas = localStorage.getItem('schemas');
+ if (savedSchemas) {
+ return JSON.parse(savedSchemas);
+ }
+ } catch (error) {
+ console.error('Error loading schemas from localStorage:', error);
+ }
+ return [];
+ });
+
+ const [tables, setTables] = useState(() => {
+ // Try to load tables from localStorage
+ try {
+ const savedTables = localStorage.getItem('tables');
+ if (savedTables) {
+ return JSON.parse(savedTables);
+ }
+ } catch (error) {
+ console.error('Error loading tables from localStorage:', error);
+ }
+ return [];
+ });
+
+ // Save databases, schemas, and tables to localStorage whenever they change
+ useEffect(() => {
+ localStorage.setItem('databases', JSON.stringify(databases));
+ }, [databases]);
+
+ useEffect(() => {
+ localStorage.setItem('schemas', JSON.stringify(schemas));
+ }, [schemas]);
+
+ useEffect(() => {
+ localStorage.setItem('tables', JSON.stringify(tables));
+ }, [tables]);
// Handler for creating a new database with nested schemas and tables
const handleCreateDatabase = (formData) => {
@@ -1680,7 +1409,8 @@ const InfiniteCanvas = () => {
schemas: newDatabase.schemas,
tables: newDatabase.tables,
expanded: false,
- onToggle: toggleDatabaseExpansion
+ onToggle: toggleDatabaseExpansion,
+ onViewDetails: handleViewDataFlow // Add the function to handle redirection
},
position: {
x: Math.random() * 300,
@@ -2014,16 +1744,38 @@ const InfiniteCanvas = () => {
custom: CustomEdge,
}), []);
- // Initialize with database nodes only
- const initialNodes = mockData.databases.map((db, index) => ({
+ // Function to handle redirection to DataFlow view
+ const handleViewDataFlow = (dbId, dbName) => {
+ // In a real application with proper routing, you would use a router to navigate
+ // Since we're using a tab-based navigation in App.jsx, we need to communicate with the parent
+
+ // Store the selected database info in localStorage for the DataFlow component to use
+ localStorage.setItem('selectedDatabase', JSON.stringify({
+ id: dbId,
+ name: dbName
+ }));
+
+ // Trigger an event that App.jsx can listen to
+ const event = new CustomEvent('viewDataFlow', {
+ detail: { databaseId: dbId, databaseName: dbName }
+ });
+ window.dispatchEvent(event);
+
+ // Alert the user about the redirection (in a real app, this would be a smooth transition)
+ alert(`Redirecting to Data Flow view for database: ${dbName}`);
+ };
+
+ // Initialize with database nodes from state instead of mockData
+ const initialNodes = databases.map((db, index) => ({
id: db.id,
type: 'database',
data: {
label: db.name,
- schemas: db.schemas,
- tables: db.tables,
+ schemas: db.schemas || 0,
+ tables: db.tables || 0,
expanded: false,
- onToggle: (id) => toggleDatabaseExpansion(id)
+ onToggle: (id) => toggleDatabaseExpansion(id),
+ onViewDetails: handleViewDataFlow // Add the function to handle redirection
},
position: { x: 250 * index, y: 50 },
}));