Compare commits
No commits in common. "f242d8661dbe8c92c07a0beea1ccc56458129b88" and "85b2f56fa08d77d8087c3ba102f1266ecae0cde3" have entirely different histories.
f242d8661d
...
85b2f56fa0
47
src/App.jsx
47
src/App.jsx
|
|
@ -10,26 +10,22 @@ function App() {
|
|||
const getInitialTab = () => {
|
||||
const pathname = window.location.pathname;
|
||||
if (pathname === '/charts') return 'charts';
|
||||
if (pathname === '/data_mappings') return 'data_mappigs';
|
||||
if (pathname === '/dataflow') return 'dataflow';
|
||||
if (pathname === '/settings') return 'settings';
|
||||
// Default to canvas/qubit_service
|
||||
window.history.pushState(null, '', '/qubit_service');
|
||||
// Default to canvas/explorer
|
||||
window.history.pushState(null, '', '/explorer');
|
||||
return 'canvas';
|
||||
};
|
||||
|
||||
const [activeTab, setActiveTab] = useState(getInitialTab());
|
||||
// Add state to track the current database for DataflowCanvas
|
||||
const [currentDbSlug, setCurrentDbSlug] = useState(null);
|
||||
// Add state to track if the current database has schemas
|
||||
const [hasSchemas, setHasSchemas] = useState(true);
|
||||
|
||||
// Handle browser back/forward navigation
|
||||
useEffect(() => {
|
||||
const handleLocationChange = () => {
|
||||
const pathname = window.location.pathname;
|
||||
if (pathname === '/qubit_service') setActiveTab('canvas');
|
||||
if (pathname === '/explorer') setActiveTab('canvas');
|
||||
else if (pathname === '/charts') setActiveTab('charts');
|
||||
else if (pathname === '/data_mappings') setActiveTab('data_mappigs');
|
||||
else if (pathname === '/dataflow') setActiveTab('dataflow');
|
||||
// Settings tab would be handled here too
|
||||
};
|
||||
|
||||
|
|
@ -47,17 +43,10 @@ function App() {
|
|||
setActiveTab('dataflow');
|
||||
|
||||
// Update URL path
|
||||
window.history.pushState(null, '', '/data_mappings');
|
||||
window.history.pushState(null, '', '/dataflow');
|
||||
|
||||
// Set the current database slug to force DataflowCanvas to re-render
|
||||
setCurrentDbSlug(event.detail.databaseSlug);
|
||||
|
||||
// Set whether this database has schemas
|
||||
setHasSchemas(!event.detail.isEmpty);
|
||||
|
||||
// Log the database info
|
||||
// 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);
|
||||
console.log('Database has schemas:', !event.detail.isEmpty);
|
||||
};
|
||||
|
||||
// Handler for switching to any tab
|
||||
|
|
@ -66,9 +55,9 @@ function App() {
|
|||
setActiveTab(event.detail);
|
||||
|
||||
// Update URL path based on the tab
|
||||
let path = '/qubit_service';
|
||||
let path = '/explorer';
|
||||
if (event.detail === 'charts') path = '/charts';
|
||||
if (event.detail === 'data_mappigs') path = '/data_mappings';
|
||||
if (event.detail === 'dataflow') path = '/dataflow';
|
||||
if (event.detail === 'settings') path = '/settings';
|
||||
|
||||
window.history.pushState(null, '', path);
|
||||
|
|
@ -128,7 +117,7 @@ function App() {
|
|||
{/* Navigation */}
|
||||
<div>
|
||||
<a
|
||||
href="/qubit_service"
|
||||
href="/explorer"
|
||||
style={{
|
||||
marginRight: '25px',
|
||||
cursor: 'pointer',
|
||||
|
|
@ -144,10 +133,10 @@ function App() {
|
|||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setActiveTab('canvas');
|
||||
window.history.pushState(null, '', '/qubit_service');
|
||||
window.history.pushState(null, '', '/explorer');
|
||||
}}
|
||||
>
|
||||
Overview
|
||||
Data Explorer
|
||||
</a>
|
||||
<a
|
||||
href="/charts"
|
||||
|
|
@ -172,7 +161,7 @@ function App() {
|
|||
Advanced Charts
|
||||
</a>
|
||||
<a
|
||||
href="/data_mappings"
|
||||
href="/dataflow"
|
||||
style={{
|
||||
marginRight: '25px',
|
||||
cursor: 'pointer',
|
||||
|
|
@ -188,10 +177,10 @@ function App() {
|
|||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setActiveTab('dataflow');
|
||||
window.history.pushState(null, '', '/data_mappings');
|
||||
window.history.pushState(null, '', '/dataflow');
|
||||
}}
|
||||
>
|
||||
Data Mapping
|
||||
Data Flow
|
||||
</a>
|
||||
<a
|
||||
href="/settings"
|
||||
|
|
@ -373,11 +362,7 @@ function App() {
|
|||
|
||||
{activeTab === 'dataflow' && (
|
||||
<>
|
||||
<DataflowCanvas
|
||||
key={`dataflow-${currentDbSlug || 'default'}-${hasSchemas ? 'has-schemas' : 'no-schemas'}-${Date.now()}`}
|
||||
dbSlug={currentDbSlug}
|
||||
hasSchemas={hasSchemas}
|
||||
/>
|
||||
<DataflowCanvas />
|
||||
<div style={{
|
||||
position: 'absolute',
|
||||
bottom: '20px',
|
||||
|
|
|
|||
|
|
@ -1,220 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
import { FaTimes, FaColumns, FaKey } from 'react-icons/fa';
|
||||
|
||||
const ColumnCreationPopup = ({ onClose, onCreateColumn, tableInfo }) => {
|
||||
const [columnName, setColumnName] = useState('');
|
||||
const [dataType, setDataType] = useState('TEXT');
|
||||
const [description, setDescription] = useState('');
|
||||
const [alias, setAlias] = useState('');
|
||||
const [isKey, setIsKey] = useState(false);
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (columnName.trim() === '') return;
|
||||
|
||||
onCreateColumn({
|
||||
name: columnName,
|
||||
data_type: dataType,
|
||||
description: description,
|
||||
alias: alias,
|
||||
is_key: isKey ? 1 : 0,
|
||||
tbl: tableInfo.tbl,
|
||||
sch: tableInfo.sch,
|
||||
con: tableInfo.con
|
||||
});
|
||||
|
||||
onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="popup-overlay" style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: 1000
|
||||
}}>
|
||||
<div className="popup-content" style={{
|
||||
backgroundColor: 'white',
|
||||
padding: '20px',
|
||||
borderRadius: '8px',
|
||||
width: '500px',
|
||||
maxWidth: '90%',
|
||||
maxHeight: '90vh',
|
||||
overflowY: 'auto',
|
||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)'
|
||||
}}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
|
||||
<h2 style={{ margin: 0, display: 'flex', alignItems: 'center', gap: '10px', color: "black" }}>
|
||||
<FaColumns />
|
||||
Add New Column
|
||||
</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
fontSize: '20px',
|
||||
cursor: 'pointer',
|
||||
color: '#999'
|
||||
}}
|
||||
>
|
||||
<FaTimes />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px', padding: '10px', backgroundColor: '#f5f5f5', borderRadius: '4px' }}>
|
||||
<p style={{ margin: 0, color: '#333' }}>
|
||||
<strong>Table:</strong> {tableInfo.tbl}
|
||||
<br />
|
||||
<strong>Schema:</strong> {tableInfo.sch}
|
||||
<br />
|
||||
<strong>Database:</strong> {tableInfo.con}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "black" }}>
|
||||
Column Name:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={columnName}
|
||||
onChange={(e) => setColumnName(e.target.value)}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9'
|
||||
}}
|
||||
placeholder="Enter column name"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "black" }}>
|
||||
Data Type:
|
||||
</label>
|
||||
<select
|
||||
value={dataType}
|
||||
onChange={(e) => setDataType(e.target.value)}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9'
|
||||
}}
|
||||
>
|
||||
<option value="TEXT">TEXT</option>
|
||||
<option value="INTEGER">INTEGER</option>
|
||||
<option value="FLOAT">FLOAT</option>
|
||||
<option value="BOOLEAN">BOOLEAN</option>
|
||||
<option value="DATE">DATE</option>
|
||||
<option value="TIMESTAMP">TIMESTAMP</option>
|
||||
<option value="JSON">JSON</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "black" }}>
|
||||
Description:
|
||||
</label>
|
||||
<textarea
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
minHeight: '80px'
|
||||
}}
|
||||
placeholder="Enter column description"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "black" }}>
|
||||
Display Alias:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={alias}
|
||||
onChange={(e) => setAlias(e.target.value)}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9'
|
||||
}}
|
||||
placeholder="Enter display alias (optional)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '8px',
|
||||
cursor: 'pointer',
|
||||
color: "black"
|
||||
}}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isKey}
|
||||
onChange={(e) => setIsKey(e.target.checked)}
|
||||
style={{ margin: 0 }}
|
||||
/>
|
||||
<FaKey style={{ color: isKey ? '#faad14' : '#d9d9d9' }} />
|
||||
Is Key Column
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: '10px', marginTop: '20px' }}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
background: 'white',
|
||||
color: '#333',
|
||||
border: '1px solid #d9d9d9',
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
background: '#1890ff',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px'
|
||||
}}
|
||||
>
|
||||
<FaColumns size={14} />
|
||||
Add Column
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColumnCreationPopup;
|
||||
|
|
@ -1,551 +0,0 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { FaTimes, FaColumns, FaKey, FaPlus, FaEdit, FaTrash, FaSave, FaUndo } from 'react-icons/fa';
|
||||
|
||||
const ColumnManagementPopup = ({ onClose, onCreateColumn, onUpdateColumn, onDeleteColumn, tableInfo, existingColumns = [] }) => {
|
||||
// State for the list of columns
|
||||
const [columns, setColumns] = useState([]);
|
||||
|
||||
// State for the new column form
|
||||
const [newColumn, setNewColumn] = useState({
|
||||
name: '',
|
||||
data_type: 'TEXT',
|
||||
description: '',
|
||||
alias: '',
|
||||
is_key: false
|
||||
});
|
||||
|
||||
// State for tracking which column is being edited
|
||||
const [editingColumnIndex, setEditingColumnIndex] = useState(null);
|
||||
|
||||
// State for the column being edited
|
||||
const [editingColumn, setEditingColumn] = useState(null);
|
||||
|
||||
// Load existing columns when the component mounts
|
||||
useEffect(() => {
|
||||
console.log('Existing columns received:', existingColumns);
|
||||
|
||||
if (existingColumns && existingColumns.length > 0) {
|
||||
// Make sure each column has both slug and col properties
|
||||
const processedColumns = existingColumns.map(column => {
|
||||
// Ensure we have a valid column identifier
|
||||
const colId = column.col || column.slug || column.id || column.column_id;
|
||||
|
||||
if (!colId) {
|
||||
console.warn('Column without identifier:', column);
|
||||
}
|
||||
|
||||
return {
|
||||
...column,
|
||||
col: colId, // Ensure col exists
|
||||
slug: colId // Ensure slug exists
|
||||
};
|
||||
});
|
||||
|
||||
console.log('Processed columns:', processedColumns);
|
||||
setColumns(processedColumns);
|
||||
} else {
|
||||
console.log('No existing columns or empty array received');
|
||||
setColumns([]);
|
||||
}
|
||||
}, [existingColumns]);
|
||||
|
||||
// Handle input change for the new column form
|
||||
const handleNewColumnChange = (e) => {
|
||||
const { name, value, type, checked } = e.target;
|
||||
setNewColumn({
|
||||
...newColumn,
|
||||
[name]: type === 'checkbox' ? checked : value
|
||||
});
|
||||
};
|
||||
|
||||
// Handle input change for the editing column form
|
||||
const handleEditColumnChange = (e) => {
|
||||
const { name, value, type, checked } = e.target;
|
||||
setEditingColumn({
|
||||
...editingColumn,
|
||||
[name]: type === 'checkbox' ? checked : value
|
||||
});
|
||||
};
|
||||
|
||||
// Handle adding a new column
|
||||
const handleAddColumn = () => {
|
||||
if (newColumn.name.trim() === '') return;
|
||||
|
||||
// Call the create column function
|
||||
onCreateColumn({
|
||||
name: newColumn.name,
|
||||
data_type: newColumn.data_type,
|
||||
description: newColumn.description,
|
||||
alias: newColumn.alias,
|
||||
is_key: newColumn.is_key ? 1 : 0,
|
||||
tbl: tableInfo.tbl,
|
||||
sch: tableInfo.sch,
|
||||
con: tableInfo.con
|
||||
});
|
||||
|
||||
// Reset the form
|
||||
setNewColumn({
|
||||
name: '',
|
||||
data_type: 'TEXT',
|
||||
description: '',
|
||||
alias: '',
|
||||
is_key: false
|
||||
});
|
||||
};
|
||||
|
||||
// Handle editing a column
|
||||
const handleEditColumn = (index) => {
|
||||
setEditingColumnIndex(index);
|
||||
setEditingColumn({ ...columns[index] });
|
||||
};
|
||||
|
||||
// Handle saving an edited column
|
||||
const handleSaveEdit = () => {
|
||||
if (!editingColumn || editingColumn.name.trim() === '') return;
|
||||
|
||||
// Call the update column function
|
||||
onUpdateColumn({
|
||||
col: editingColumn.col || editingColumn.slug, // Use col if available, otherwise use slug
|
||||
name: editingColumn.name,
|
||||
data_type: editingColumn.data_type,
|
||||
description: editingColumn.description,
|
||||
alias: editingColumn.alias,
|
||||
is_key: editingColumn.is_key ? 1 : 0,
|
||||
tbl: tableInfo.tbl,
|
||||
sch: tableInfo.sch,
|
||||
con: tableInfo.con
|
||||
});
|
||||
|
||||
// Update the columns array
|
||||
const updatedColumns = [...columns];
|
||||
updatedColumns[editingColumnIndex] = editingColumn;
|
||||
setColumns(updatedColumns);
|
||||
|
||||
// Reset the editing state
|
||||
setEditingColumnIndex(null);
|
||||
setEditingColumn(null);
|
||||
};
|
||||
|
||||
// Handle canceling an edit
|
||||
const handleCancelEdit = () => {
|
||||
setEditingColumnIndex(null);
|
||||
setEditingColumn(null);
|
||||
};
|
||||
|
||||
// Handle deleting a column
|
||||
const handleDeleteColumn = (index) => {
|
||||
const column = columns[index];
|
||||
|
||||
console.log('Attempting to delete column:', column);
|
||||
console.log('Column properties:', {
|
||||
name: column.name,
|
||||
slug: column.slug,
|
||||
col: column.col,
|
||||
data_type: column.data_type
|
||||
});
|
||||
|
||||
// Confirm deletion
|
||||
if (window.confirm(`Are you sure you want to delete the column "${column.name}"?`)) {
|
||||
// Create the payload with both col and slug for maximum compatibility
|
||||
const payload = {
|
||||
col: column.col || column.slug, // Use col if available, otherwise use slug
|
||||
slug: column.slug || column.col, // Include slug as well
|
||||
tbl: tableInfo.tbl,
|
||||
sch: tableInfo.sch,
|
||||
con: tableInfo.con,
|
||||
name: column.name // Include name for logging
|
||||
};
|
||||
|
||||
console.log('Sending delete payload:', payload);
|
||||
|
||||
// Call the delete column function
|
||||
onDeleteColumn(payload);
|
||||
|
||||
// Remove the column from the array
|
||||
const updatedColumns = [...columns];
|
||||
updatedColumns.splice(index, 1);
|
||||
setColumns(updatedColumns);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="popup-overlay" style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: 1000
|
||||
}}>
|
||||
<div className="popup-content" style={{
|
||||
backgroundColor: 'white',
|
||||
padding: '20px',
|
||||
borderRadius: '8px',
|
||||
width: '700px',
|
||||
maxWidth: '90%',
|
||||
maxHeight: '90vh',
|
||||
overflowY: 'auto',
|
||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)'
|
||||
}}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
|
||||
<h2 style={{ margin: 0, display: 'flex', alignItems: 'center', gap: '10px', color: "black" }}>
|
||||
<FaColumns />
|
||||
Manage Columns
|
||||
</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
fontSize: '20px',
|
||||
cursor: 'pointer',
|
||||
color: '#999'
|
||||
}}
|
||||
>
|
||||
<FaTimes />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px', padding: '10px', backgroundColor: '#f5f5f5', borderRadius: '4px' }}>
|
||||
<p style={{ margin: 0, color: '#333' }}>
|
||||
<strong>Table:</strong> {tableInfo.tbl}
|
||||
<br />
|
||||
<strong>Schema:</strong> {tableInfo.sch}
|
||||
<br />
|
||||
<strong>Database:</strong> {tableInfo.con}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Existing Columns Section */}
|
||||
<div style={{ marginBottom: '20px' }}>
|
||||
<h3 style={{ color: 'black', borderBottom: '1px solid #eee', paddingBottom: '8px' }}>
|
||||
Existing Columns
|
||||
</h3>
|
||||
|
||||
{columns.length === 0 ? (
|
||||
<div style={{ padding: '15px', textAlign: 'center', color: 'black', backgroundColor: '#f9f9f9', borderRadius: '4px' }}>
|
||||
No columns found for this table.
|
||||
</div>
|
||||
) : (
|
||||
<div style={{
|
||||
border: '1px solid #eee',
|
||||
borderRadius: '4px',
|
||||
overflow: 'hidden'
|
||||
}}>
|
||||
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
||||
<thead>
|
||||
<tr style={{ backgroundColor: '#f5f5f5' }}>
|
||||
<th style={{ padding: '10px', textAlign: 'left', borderBottom: '1px solid #eee', color: 'black', fontWeight: 'bold' }}>Name</th>
|
||||
<th style={{ padding: '10px', textAlign: 'left', borderBottom: '1px solid #eee', color: 'black', fontWeight: 'bold' }}>Type</th>
|
||||
<th style={{ padding: '10px', textAlign: 'left', borderBottom: '1px solid #eee', color: 'black', fontWeight: 'bold' }}>Key</th>
|
||||
<th style={{ padding: '10px', textAlign: 'right', borderBottom: '1px solid #eee', color: 'black', fontWeight: 'bold' }}>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{columns.map((column, index) => (
|
||||
<tr key={`column-${index}-${column.name}`} style={{ borderBottom: '1px solid #eee' }}>
|
||||
{editingColumnIndex === index ? (
|
||||
// Editing mode
|
||||
<>
|
||||
<td style={{ padding: '10px' }}>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={editingColumn.name}
|
||||
onChange={handleEditColumnChange}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '6px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
color: 'black'
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
<td style={{ padding: '10px' }}>
|
||||
<select
|
||||
name="data_type"
|
||||
value={editingColumn.data_type}
|
||||
onChange={handleEditColumnChange}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '6px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
color: 'black'
|
||||
}}
|
||||
>
|
||||
<option value="TEXT" style={{ color: 'black' }}>TEXT</option>
|
||||
<option value="INTEGER" style={{ color: 'black' }}>INTEGER</option>
|
||||
<option value="FLOAT" style={{ color: 'black' }}>FLOAT</option>
|
||||
<option value="BOOLEAN" style={{ color: 'black' }}>BOOLEAN</option>
|
||||
<option value="DATE" style={{ color: 'black' }}>DATE</option>
|
||||
<option value="TIMESTAMP" style={{ color: 'black' }}>TIMESTAMP</option>
|
||||
<option value="JSON" style={{ color: 'black' }}>JSON</option>
|
||||
</select>
|
||||
</td>
|
||||
<td style={{ padding: '10px' }}>
|
||||
<label style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="is_key"
|
||||
checked={editingColumn.is_key}
|
||||
onChange={handleEditColumnChange}
|
||||
/>
|
||||
<FaKey style={{ color: editingColumn.is_key ? '#faad14' : '#d9d9d9' }} />
|
||||
</label>
|
||||
</td>
|
||||
<td style={{ padding: '10px', textAlign: 'right' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: '5px' }}>
|
||||
<button
|
||||
onClick={handleSaveEdit}
|
||||
style={{
|
||||
background: '#52c41a',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
padding: '5px 10px',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px'
|
||||
}}
|
||||
>
|
||||
<FaSave size={12} />
|
||||
Save
|
||||
</button>
|
||||
<button
|
||||
onClick={handleCancelEdit}
|
||||
style={{
|
||||
background: '#f5f5f5',
|
||||
color: '#333',
|
||||
border: '1px solid #d9d9d9',
|
||||
borderRadius: '4px',
|
||||
padding: '5px 10px',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px'
|
||||
}}
|
||||
>
|
||||
<FaUndo size={12} />
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</>
|
||||
) : (
|
||||
// View mode
|
||||
<>
|
||||
<td style={{ padding: '10px', color: 'black' }}>{column.name}</td>
|
||||
<td style={{ padding: '10px', color: 'black' }}>{column.data_type}</td>
|
||||
<td style={{ padding: '10px', color: 'black' }}>
|
||||
{column.is_key && <FaKey style={{ color: '#faad14' }} />}
|
||||
</td>
|
||||
<td style={{ padding: '10px', textAlign: 'right' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: '5px' }}>
|
||||
<button
|
||||
onClick={() => handleEditColumn(index)}
|
||||
style={{
|
||||
background: '#1890ff',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
padding: '5px 10px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
<FaEdit size={12} />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleDeleteColumn(index)}
|
||||
style={{
|
||||
background: '#ff4d4f',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
padding: '5px 10px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
<FaTrash size={12} />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</>
|
||||
)}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Add New Column Section */}
|
||||
<div style={{ marginTop: '20px' }}>
|
||||
<h3 style={{ color: 'black', borderBottom: '1px solid #eee', paddingBottom: '8px' }}>
|
||||
Add New Column
|
||||
</h3>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '15px', marginBottom: '15px' }}>
|
||||
<div>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "black" }}>
|
||||
Column Name:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={newColumn.name}
|
||||
onChange={handleNewColumnChange}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
color: 'black'
|
||||
}}
|
||||
placeholder="Enter column name"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "black" }}>
|
||||
Data Type:
|
||||
</label>
|
||||
<select
|
||||
name="data_type"
|
||||
value={newColumn.data_type}
|
||||
onChange={handleNewColumnChange}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
color: 'black'
|
||||
}}
|
||||
>
|
||||
<option value="TEXT" style={{ color: 'black' }}>TEXT</option>
|
||||
<option value="INTEGER" style={{ color: 'black' }}>INTEGER</option>
|
||||
<option value="FLOAT" style={{ color: 'black' }}>FLOAT</option>
|
||||
<option value="BOOLEAN" style={{ color: 'black' }}>BOOLEAN</option>
|
||||
<option value="DATE" style={{ color: 'black' }}>DATE</option>
|
||||
<option value="TIMESTAMP" style={{ color: 'black' }}>TIMESTAMP</option>
|
||||
<option value="JSON" style={{ color: 'black' }}>JSON</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "black" }}>
|
||||
Description:
|
||||
</label>
|
||||
<textarea
|
||||
name="description"
|
||||
value={newColumn.description}
|
||||
onChange={handleNewColumnChange}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
minHeight: '60px',
|
||||
color: 'black'
|
||||
}}
|
||||
placeholder="Enter column description"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr auto', gap: '15px', marginBottom: '15px', alignItems: 'end' }}>
|
||||
<div>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "black" }}>
|
||||
Display Alias:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="alias"
|
||||
value={newColumn.alias}
|
||||
onChange={handleNewColumnChange}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
color: 'black'
|
||||
}}
|
||||
placeholder="Enter display alias (optional)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '8px',
|
||||
cursor: 'pointer',
|
||||
color: "black",
|
||||
padding: '8px',
|
||||
border: '1px solid #d9d9d9',
|
||||
borderRadius: '4px',
|
||||
backgroundColor: newColumn.is_key ? '#fffbe6' : 'transparent'
|
||||
}}>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="is_key"
|
||||
checked={newColumn.is_key}
|
||||
onChange={handleNewColumnChange}
|
||||
style={{ margin: 0 }}
|
||||
/>
|
||||
<FaKey style={{ color: newColumn.is_key ? '#faad14' : '#d9d9d9' }} />
|
||||
Is Key Column
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '20px' }}>
|
||||
<button
|
||||
onClick={handleAddColumn}
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
background: '#1890ff',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px'
|
||||
}}
|
||||
>
|
||||
<FaPlus size={14} />
|
||||
Add Column
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: '10px', marginTop: '20px', borderTop: '1px solid #eee', paddingTop: '20px' }}>
|
||||
<button
|
||||
onClick={onClose}
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
background: 'white',
|
||||
color: '#333',
|
||||
border: '1px solid #d9d9d9',
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColumnManagementPopup;
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1051,13 +1051,13 @@ const DatabaseNode = ({ data = {} }) => {
|
|||
</span>
|
||||
</div>
|
||||
|
||||
{/* <div style={{ fontSize: '0.8em', color: '#aaa', marginBottom: '5px' }}>
|
||||
<div style={{ fontSize: '0.8em', color: '#aaa', marginBottom: '5px' }}>
|
||||
{`${data.schemas} schemas • ${data.tables} tables`}
|
||||
</div>
|
||||
|
||||
<div style={{ fontSize: '0.7em', color: '#888', marginBottom: '10px' }}>
|
||||
Connection: {dbSlug}
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
{/* View Details Button */}
|
||||
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
||||
|
|
@ -1091,7 +1091,7 @@ const DatabaseNode = ({ data = {} }) => {
|
|||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 4.5C7 4.5 2.73 7.61 1 12C2.73 16.39 7 19.5 12 19.5C17 19.5 21.27 16.39 23 12C21.27 7.61 17 4.5 12 4.5ZM12 17C9.24 17 7 14.76 7 12C7 9.24 9.24 7 12 7C14.76 7 17 9.24 17 12C17 14.76 14.76 17 12 17ZM12 9C10.34 9 9 10.34 9 12C9 13.66 10.34 15 12 15C13.66 15 15 13.66 15 12C15 10.34 13.66 9 12 9Z" fill="white"/>
|
||||
</svg>
|
||||
View Data Mapping
|
||||
View Data Flow
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1908,24 +1908,20 @@ const InfiniteCanvas = () => {
|
|||
|
||||
console.log(`Viewing data flow for database: ${dbName} (${dbSlug})`);
|
||||
|
||||
// Selectively clear cached data for the current database only
|
||||
// Clear any existing schemas in localStorage for this database
|
||||
try {
|
||||
// Only clear the cache for the current database
|
||||
// Clear any existing schemas for this database
|
||||
localStorage.removeItem(`schemas_${dbSlug}`);
|
||||
localStorage.removeItem(`tables_${dbSlug}`);
|
||||
|
||||
// If this is "service 2" (my_dwh2), set empty schemas
|
||||
if (dbSlug === 'my_dwh2') {
|
||||
console.log('Setting empty schemas for service 2 database');
|
||||
// For service 2, we want to ensure it always shows as empty
|
||||
localStorage.setItem(`schemas_${dbSlug}`, JSON.stringify([]));
|
||||
localStorage.setItem(`tables_${dbSlug}`, JSON.stringify([]));
|
||||
} else {
|
||||
// For other databases like MyDataWarehouseDB, we want to preserve their data
|
||||
// but ensure we're not using stale data
|
||||
console.log(`Preserving schemas for database: ${dbName}`);
|
||||
|
||||
// We don't need to clear anything for MyDataWarehouseDB
|
||||
// This ensures its schemas will be loaded from the API or mock data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error managing cached data in localStorage:', error);
|
||||
console.error('Error clearing schemas from localStorage:', error);
|
||||
}
|
||||
|
||||
// Store the selected database info in localStorage for the DataFlow component to use
|
||||
|
|
@ -1933,34 +1929,23 @@ const InfiniteCanvas = () => {
|
|||
id: dbId,
|
||||
name: dbName,
|
||||
slug: dbSlug, // Include the slug for API calls
|
||||
isEmpty: dbSlug === 'my_dwh2', // Flag to indicate if this database has no schemas
|
||||
timestamp: Date.now() // Add timestamp to ensure uniqueness
|
||||
isEmpty: dbSlug === 'my_dwh2' // Flag to indicate if this database has no schemas
|
||||
}));
|
||||
|
||||
// Set the current database slug in mockData.js
|
||||
if (typeof window.setCurrentDbSlug === 'function') {
|
||||
// First clear any existing data
|
||||
window.setCurrentDbSlug(null);
|
||||
|
||||
// Then set the new database slug
|
||||
setTimeout(() => {
|
||||
window.setCurrentDbSlug(dbSlug);
|
||||
}, 50);
|
||||
} else {
|
||||
console.warn('window.setCurrentDbSlug function is not available');
|
||||
}
|
||||
|
||||
// Check if this database should have empty schemas
|
||||
const isEmpty = dbSlug === 'my_dwh2';
|
||||
|
||||
// Trigger an event that App.jsx can listen to
|
||||
const event = new CustomEvent('viewDataFlow', {
|
||||
detail: {
|
||||
databaseId: dbId,
|
||||
databaseName: dbName,
|
||||
databaseSlug: dbSlug,
|
||||
isEmpty: isEmpty, // Flag to indicate if this database has no schemas
|
||||
timestamp: Date.now() // Add timestamp to ensure uniqueness
|
||||
isEmpty: dbSlug === 'my_dwh2' // Flag to indicate if this database has no schemas
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(event);
|
||||
|
|
@ -2530,7 +2515,7 @@ const InfiniteCanvas = () => {
|
|||
padding: 0,
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
title="Add DataSource"
|
||||
title="Add Entity"
|
||||
>
|
||||
<svg width="99" height="36" viewBox="0 0 99 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.5" y="0.5" width="98" height="35" rx="7.5" fill="#3EA29A"/>
|
||||
|
|
@ -2824,7 +2809,7 @@ const InfiniteCanvas = () => {
|
|||
{/* Entity Creation Modal */}
|
||||
<Modal
|
||||
isOpen={showAddEntityModal}
|
||||
title="Add DataSource"
|
||||
title="Add Entity"
|
||||
onClose={() => {
|
||||
setShowAddEntityModal(false);
|
||||
setActiveEntityType('database');
|
||||
|
|
|
|||
|
|
@ -2,50 +2,19 @@ import React, { useState } from 'react';
|
|||
import { FaPlus, FaTimes, FaTable, FaLayerGroup } from 'react-icons/fa';
|
||||
import { CustomDatabaseIcon, CustomDocumentIcon, CustomDimensionIcon } from './CustomIcons';
|
||||
|
||||
// Add a style tag for animations
|
||||
const styles = `
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(-10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
from { opacity: 1; transform: translateY(0); }
|
||||
to { opacity: 0; transform: translateY(-10px); }
|
||||
}
|
||||
`;
|
||||
|
||||
const TableCreationPopup = ({ onClose, onCreateTable, schemaInfo }) => {
|
||||
const TableCreationPopup = ({ onClose, onCreateTable }) => {
|
||||
const [tableName, setTableName] = useState('');
|
||||
const [externalName, setExternalName] = useState('');
|
||||
const [tableType, setTableType] = useState('stage');
|
||||
const [description, setDescription] = useState('');
|
||||
const [columns, setColumns] = useState([{ name: '', type: 'TEXT' }]);
|
||||
const [columns, setColumns] = useState([{ name: '', type: 'string' }]);
|
||||
const [newColumnName, setNewColumnName] = useState('');
|
||||
const [newColumnType, setNewColumnType] = useState('TEXT');
|
||||
const [addSuccess, setAddSuccess] = useState(false); // To show success message
|
||||
const [newColumnType, setNewColumnType] = useState('string');
|
||||
|
||||
const handleAddColumn = () => {
|
||||
console.log('handleAddColumn called');
|
||||
if (newColumnName.trim() === '') {
|
||||
console.log('Column name is empty, not adding');
|
||||
return;
|
||||
}
|
||||
if (newColumnName.trim() === '') return;
|
||||
|
||||
console.log('Adding new column:', { name: newColumnName, type: newColumnType });
|
||||
setColumns([...columns, { name: newColumnName, type: newColumnType }]);
|
||||
|
||||
// Show success message
|
||||
setAddSuccess(true);
|
||||
|
||||
// Clear the form
|
||||
setNewColumnName('');
|
||||
setNewColumnType('TEXT'); // Changed from 'string' to 'TEXT' to match our options
|
||||
|
||||
// Hide success message after 2 seconds
|
||||
setTimeout(() => {
|
||||
setAddSuccess(false);
|
||||
}, 2000);
|
||||
setNewColumnType('string');
|
||||
};
|
||||
|
||||
const handleRemoveColumn = (index) => {
|
||||
|
|
@ -64,15 +33,8 @@ const TableCreationPopup = ({ onClose, onCreateTable, schemaInfo }) => {
|
|||
|
||||
onCreateTable({
|
||||
name: tableName,
|
||||
external_name: externalName || tableName,
|
||||
table_type: tableType,
|
||||
description: description,
|
||||
sch: schemaInfo.sch,
|
||||
con: schemaInfo.con,
|
||||
columns: validColumns.map(col => ({
|
||||
name: col.name,
|
||||
data_type: col.type
|
||||
}))
|
||||
type: tableType,
|
||||
columns: validColumns.map(col => col.name)
|
||||
});
|
||||
|
||||
onClose();
|
||||
|
|
@ -92,10 +54,6 @@ const TableCreationPopup = ({ onClose, onCreateTable, schemaInfo }) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Add the style tag for animations */}
|
||||
<style dangerouslySetInnerHTML={{ __html: styles }} />
|
||||
|
||||
<div className="popup-overlay" style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
|
|
@ -138,14 +96,6 @@ const TableCreationPopup = ({ onClose, onCreateTable, schemaInfo }) => {
|
|||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div style={{ marginBottom: '15px', padding: '10px', backgroundColor: '#f5f5f5', borderRadius: '4px' }}>
|
||||
<p style={{ margin: 0, color: '#333' }}>
|
||||
<strong>Schema:</strong> {schemaInfo?.sch}
|
||||
<br />
|
||||
<strong>Database:</strong> {schemaInfo?.con}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "black"}}>
|
||||
Table Name:
|
||||
|
|
@ -165,42 +115,6 @@ const TableCreationPopup = ({ onClose, onCreateTable, schemaInfo }) => {
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "black"}}>
|
||||
External Name (Optional):
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={externalName}
|
||||
onChange={(e) => setExternalName(e.target.value)}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9'
|
||||
}}
|
||||
placeholder="Enter external name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "black"}}>
|
||||
Description:
|
||||
</label>
|
||||
<textarea
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
minHeight: '80px'
|
||||
}}
|
||||
placeholder="Enter table description"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "black" }}>
|
||||
Table Type:
|
||||
|
|
@ -332,13 +246,10 @@ const TableCreationPopup = ({ onClose, onCreateTable, schemaInfo }) => {
|
|||
border: '1px solid #d9d9d9'
|
||||
}}
|
||||
>
|
||||
<option value="TEXT">TEXT</option>
|
||||
<option value="INTEGER">INTEGER</option>
|
||||
<option value="FLOAT">FLOAT</option>
|
||||
<option value="BOOLEAN">BOOLEAN</option>
|
||||
<option value="DATE">DATE</option>
|
||||
<option value="TIMESTAMP">TIMESTAMP</option>
|
||||
<option value="JSON">JSON</option>
|
||||
<option value="string">String</option>
|
||||
<option value="number">Number</option>
|
||||
<option value="date">Date</option>
|
||||
<option value="boolean">Boolean</option>
|
||||
</select>
|
||||
</div>
|
||||
<button
|
||||
|
|
@ -370,38 +281,12 @@ const TableCreationPopup = ({ onClose, onCreateTable, schemaInfo }) => {
|
|||
)}
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: '15px', marginBottom: '5px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: "#333", fontSize: '14px' }}>
|
||||
Add New Column:
|
||||
</label>
|
||||
|
||||
{/* Success message */}
|
||||
{addSuccess && (
|
||||
<div style={{
|
||||
color: '#52c41a',
|
||||
fontSize: '14px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px',
|
||||
animation: 'fadeIn 0.3s ease-in-out'
|
||||
}}>
|
||||
<span style={{ fontSize: '16px' }}>✓</span> Column added!
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ display: 'flex', gap: '10px', alignItems: 'flex-end', marginBottom: '10px' }}>
|
||||
<div style={{ display: 'flex', gap: '10px', alignItems: 'flex-end' }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<input
|
||||
type="text"
|
||||
value={newColumnName}
|
||||
onChange={(e) => setNewColumnName(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
// Add column when Enter key is pressed
|
||||
if (e.key === 'Enter' && newColumnName.trim() !== '') {
|
||||
e.preventDefault();
|
||||
handleAddColumn();
|
||||
}
|
||||
}}
|
||||
placeholder="New column name"
|
||||
style={{
|
||||
width: '100%',
|
||||
|
|
@ -422,45 +307,25 @@ const TableCreationPopup = ({ onClose, onCreateTable, schemaInfo }) => {
|
|||
border: '1px solid #d9d9d9'
|
||||
}}
|
||||
>
|
||||
<option value="TEXT">TEXT</option>
|
||||
<option value="INTEGER">INTEGER</option>
|
||||
<option value="FLOAT">FLOAT</option>
|
||||
<option value="BOOLEAN">BOOLEAN</option>
|
||||
<option value="DATE">DATE</option>
|
||||
<option value="TIMESTAMP">TIMESTAMP</option>
|
||||
<option value="JSON">JSON</option>
|
||||
<option value="string">String</option>
|
||||
<option value="number">Number</option>
|
||||
<option value="date">Date</option>
|
||||
<option value="boolean">Boolean</option>
|
||||
</select>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault(); // Prevent form submission
|
||||
console.log('Add button clicked');
|
||||
handleAddColumn();
|
||||
}}
|
||||
onClick={handleAddColumn}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '5px',
|
||||
padding: '8px 12px',
|
||||
background: '#1890ff',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer',
|
||||
minWidth: '80px',
|
||||
fontWeight: 'bold',
|
||||
transition: 'all 0.2s ease',
|
||||
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)'
|
||||
}}
|
||||
onMouseOver={(e) => {
|
||||
e.currentTarget.style.background = '#096dd9';
|
||||
e.currentTarget.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
|
||||
}}
|
||||
onMouseOut={(e) => {
|
||||
e.currentTarget.style.background = '#1890ff';
|
||||
e.currentTarget.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)';
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
<FaPlus size={12} />
|
||||
|
|
@ -505,7 +370,6 @@ const TableCreationPopup = ({ onClose, onCreateTable, schemaInfo }) => {
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,286 +0,0 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { FaTimes, FaTable, FaSave } from 'react-icons/fa';
|
||||
import { CustomDatabaseIcon, CustomDocumentIcon, CustomDimensionIcon } from './CustomIcons';
|
||||
|
||||
const TableUpdatePopup = ({ onClose, onUpdateTable, tableInfo }) => {
|
||||
const [tableName, setTableName] = useState('');
|
||||
const [externalName, setExternalName] = useState('');
|
||||
const [tableType, setTableType] = useState('stage');
|
||||
const [description, setDescription] = useState('');
|
||||
|
||||
// Initialize form with table info
|
||||
useEffect(() => {
|
||||
if (tableInfo) {
|
||||
setTableName(tableInfo.name || '');
|
||||
setExternalName(tableInfo.external_name || '');
|
||||
setTableType(tableInfo.table_type || 'stage');
|
||||
setDescription(tableInfo.description || '');
|
||||
}
|
||||
}, [tableInfo]);
|
||||
|
||||
// Handle form submission
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
// Validate form
|
||||
if (!tableName.trim()) {
|
||||
alert('Table name is required');
|
||||
return;
|
||||
}
|
||||
|
||||
// Call the update table function
|
||||
onUpdateTable({
|
||||
tbl: tableInfo.tbl,
|
||||
sch: tableInfo.sch,
|
||||
con: tableInfo.con,
|
||||
name: tableName,
|
||||
external_name: externalName,
|
||||
table_type: tableType,
|
||||
description: description
|
||||
});
|
||||
};
|
||||
|
||||
// Get the appropriate icon based on table type
|
||||
const getTableIcon = () => {
|
||||
switch (tableType) {
|
||||
case 'stage':
|
||||
return <CustomDatabaseIcon width="16" height="16" />;
|
||||
case 'dimension':
|
||||
return <CustomDimensionIcon width="16" height="16" />;
|
||||
case 'fact':
|
||||
return <CustomDocumentIcon width="16" height="16" />;
|
||||
default:
|
||||
return <FaTable />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="popup-overlay" style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: 1000
|
||||
}}>
|
||||
<div className="popup-content" style={{
|
||||
backgroundColor: 'white',
|
||||
padding: '20px',
|
||||
borderRadius: '8px',
|
||||
width: '500px',
|
||||
maxWidth: '90%',
|
||||
maxHeight: '90vh',
|
||||
overflowY: 'auto',
|
||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)'
|
||||
}}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
|
||||
<h2 style={{ margin: 0, display: 'flex', alignItems: 'center', gap: '10px', color: 'black' }}>
|
||||
{getTableIcon()}
|
||||
Update Table
|
||||
</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
fontSize: '20px',
|
||||
cursor: 'pointer',
|
||||
color: '#999'
|
||||
}}
|
||||
>
|
||||
<FaTimes />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px', padding: '10px', backgroundColor: '#f5f5f5', borderRadius: '4px' }}>
|
||||
<p style={{ margin: 0, color: '#333' }}>
|
||||
<strong>Table:</strong> {tableInfo.tbl}
|
||||
<br />
|
||||
<strong>Schema:</strong> {tableInfo.sch}
|
||||
<br />
|
||||
<strong>Database:</strong> {tableInfo.con}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: 'black' }}>
|
||||
Table Name:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={tableName}
|
||||
onChange={(e) => setTableName(e.target.value)}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
color: 'black'
|
||||
}}
|
||||
placeholder="Enter table name"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: 'black' }}>
|
||||
External Name:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={externalName}
|
||||
onChange={(e) => setExternalName(e.target.value)}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
color: 'black'
|
||||
}}
|
||||
placeholder="Enter external name (optional)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: 'black' }}>
|
||||
Table Type:
|
||||
</label>
|
||||
<div style={{ display: 'flex', gap: '15px' }}>
|
||||
<label style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px',
|
||||
cursor: 'pointer',
|
||||
padding: '8px 12px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
backgroundColor: tableType === 'stage' ? 'rgba(250, 140, 22, 0.1)' : 'transparent',
|
||||
borderColor: tableType === 'stage' ? '#fa8c16' : '#d9d9d9',
|
||||
color: 'black'
|
||||
}}>
|
||||
<input
|
||||
type="radio"
|
||||
name="tableType"
|
||||
value="stage"
|
||||
checked={tableType === 'stage'}
|
||||
onChange={() => setTableType('stage')}
|
||||
style={{ marginRight: '5px' }}
|
||||
/>
|
||||
<CustomDatabaseIcon width="16" height="16" style={{ marginRight: '5px' }} />
|
||||
Stage
|
||||
</label>
|
||||
|
||||
<label style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px',
|
||||
cursor: 'pointer',
|
||||
padding: '8px 12px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
backgroundColor: tableType === 'fact' ? 'rgba(24, 144, 255, 0.1)' : 'transparent',
|
||||
borderColor: tableType === 'fact' ? '#1890ff' : '#d9d9d9',
|
||||
color: 'black'
|
||||
}}>
|
||||
<input
|
||||
type="radio"
|
||||
name="tableType"
|
||||
value="fact"
|
||||
checked={tableType === 'fact'}
|
||||
onChange={() => setTableType('fact')}
|
||||
style={{ marginRight: '5px' }}
|
||||
/>
|
||||
<CustomDocumentIcon width="16" height="16" style={{ marginRight: '5px' }} />
|
||||
Fact
|
||||
</label>
|
||||
|
||||
<label style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px',
|
||||
cursor: 'pointer',
|
||||
padding: '8px 12px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
backgroundColor: tableType === 'dimension' ? 'rgba(82, 196, 26, 0.1)' : 'transparent',
|
||||
borderColor: tableType === 'dimension' ? '#52c41a' : '#d9d9d9',
|
||||
color: 'black'
|
||||
}}>
|
||||
<input
|
||||
type="radio"
|
||||
name="tableType"
|
||||
value="dimension"
|
||||
checked={tableType === 'dimension'}
|
||||
onChange={() => setTableType('dimension')}
|
||||
style={{ marginRight: '5px' }}
|
||||
/>
|
||||
<CustomDimensionIcon width="16" height="16" style={{ marginRight: '5px' }} />
|
||||
Dimension
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '15px' }}>
|
||||
<label style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold', color: 'black' }}>
|
||||
Description:
|
||||
</label>
|
||||
<textarea
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '8px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #d9d9d9',
|
||||
minHeight: '80px',
|
||||
color: 'black'
|
||||
}}
|
||||
placeholder="Enter table description (optional)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: '10px', marginTop: '20px' }}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
background: 'white',
|
||||
color: '#333',
|
||||
border: '1px solid #d9d9d9',
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
background: '#1890ff',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px'
|
||||
}}
|
||||
>
|
||||
<FaSave size={14} />
|
||||
Update Table
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableUpdatePopup;
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue