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 */}
- - - -
- {/* Parent Selector (for schema and table) */} - {activeEntityType === 'schema' && availableDatabases.length > 0 && ( -
- - -
- )} + {/* No parent selectors needed since we only have database */} - {activeEntityType === 'table' && availableSchemas.length > 0 && ( -
- - -
- )} - - {/* Form based on selected entity type */} - {activeEntityType === 'database' && ( - - )} - - {activeEntityType === 'schema' && selectedDatabaseForSchema && ( - - )} - - {activeEntityType === 'table' && selectedSchemaForTable && ( - - )} - - {/* Guidance message when no parent is selected */} - {activeEntityType === 'schema' && !selectedDatabaseForSchema && availableDatabases.length > 0 && ( -
- Please select a database to create a schema. -
- )} - - {activeEntityType === 'table' && !selectedSchemaForTable && availableSchemas.length > 0 && ( -
- Please select a schema to create a table. -
- )} + {/* Only Database Form */} + {/* Guidance message when no parents are available */} {activeEntityType === 'schema' && availableDatabases.length === 0 && ( @@ -1366,9 +1018,43 @@ const DatabaseNode = ({ data }) => { {data.label}
-
+
{isDbtez ? 'Database' : `${data.schemas} schemas • ${data.tables} tables`}
+ + {/* View Details Button */} +
+ +
); }; @@ -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 }, }));