Skip to content

Commit 76fa12e

Browse files
Merge pull request #107 from festim-dev/node-sidebar-improvements
Node sidebar improvements
2 parents 733a753 + f817669 commit 76fa12e

File tree

5 files changed

+371
-209
lines changed

5 files changed

+371
-209
lines changed

src/App.jsx

Lines changed: 18 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ import './App.css';
1515
import Plot from 'react-plotly.js';
1616
import { getApiEndpoint } from './config.js';
1717
import Sidebar from './Sidebar';
18+
import NodeSidebar from './NodeSidebar';
1819
import { DnDProvider, useDnD } from './DnDContext.jsx';
1920
import ContextMenu from './ContextMenu.jsx';
20-
21+
import { isValidPythonIdentifier } from './utils.js';
2122
import { makeEdge } from './CustomEdge';
2223
import { nodeTypes } from './nodeConfig.js';
2324

@@ -78,6 +79,8 @@ const DnDFlow = () => {
7879
// Global variables state
7980
const [globalVariables, setGlobalVariables] = useState([]);
8081
const [defaultValues, setDefaultValues] = useState({});
82+
const [isEditingLabel, setIsEditingLabel] = useState(false);
83+
const [tempLabel, setTempLabel] = useState('');
8184
const [nodeDocumentation, setNodeDocumentation] = useState({});
8285
const [isDocumentationExpanded, setIsDocumentationExpanded] = useState(false);
8386

@@ -558,30 +561,6 @@ const DnDFlow = () => {
558561
}
559562
};
560563

561-
// Functions for managing global variables
562-
const isValidPythonIdentifier = (name) => {
563-
// Check if name is empty
564-
if (!name) return false;
565-
566-
// Python identifier rules:
567-
// - Must start with letter or underscore
568-
// - Can contain letters, digits, underscores
569-
// - Cannot be a Python keyword
570-
const pythonKeywords = [
571-
'False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue',
572-
'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global',
573-
'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass',
574-
'raise', 'return', 'try', 'while', 'with', 'yield'
575-
];
576-
577-
// Check if it's a keyword
578-
if (pythonKeywords.includes(name)) return false;
579-
580-
// Check pattern: must start with letter or underscore, followed by letters, digits, or underscores
581-
const pattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
582-
return pattern.test(name);
583-
};
584-
585564
const addGlobalVariable = () => {
586565
const newVariable = {
587566
id: Date.now().toString(),
@@ -1211,165 +1190,19 @@ const DnDFlow = () => {
12111190
</ReactFlow>
12121191
</div>
12131192
</div>
1214-
{selectedNode && (
1215-
<div
1216-
className="sidebar-scrollable"
1217-
style={{
1218-
position: 'absolute',
1219-
right: 0,
1220-
top: 50,
1221-
height: 'calc(100vh - 50px)',
1222-
width: '300px',
1223-
background: '#1e1e2f',
1224-
color: '#ffffff',
1225-
borderLeft: '1px solid #ccc',
1226-
boxShadow: '-4px 0 8px rgba(0,0,0,0.1)',
1227-
zIndex: 10,
1228-
overflowY: 'auto',
1229-
overflowX: 'hidden'
1230-
}}
1231-
>
1232-
<div style={{ padding: '20px' }}>
1233-
<h3>{selectedNode.data.label}</h3>
1234-
{(() => {
1235-
// Get default values for this node type
1236-
const nodeDefaults = defaultValues[selectedNode.type] || {};
1237-
1238-
// Create a list of all possible parameters (both current data and defaults)
1239-
const allParams = new Set([
1240-
...Object.keys(selectedNode.data),
1241-
...Object.keys(nodeDefaults)
1242-
]);
1243-
1244-
return Array.from(allParams)
1245-
.map(key => {
1246-
const currentValue = selectedNode.data[key] || '';
1247-
const defaultValue = nodeDefaults[key];
1248-
const placeholder = defaultValue !== undefined && defaultValue !== null ?
1249-
String(defaultValue) : '';
1250-
1251-
return (
1252-
<div key={key} style={{ marginBottom: '10px' }}>
1253-
<label style={{
1254-
color: '#ffffff',
1255-
display: 'block',
1256-
marginBottom: '4px',
1257-
fontSize: '14px'
1258-
}}>
1259-
{key}:
1260-
</label>
1261-
<input
1262-
type="text"
1263-
value={currentValue}
1264-
placeholder={placeholder}
1265-
onChange={(e) => {
1266-
const newValue = e.target.value;
1267-
const updatedNode = {
1268-
...selectedNode,
1269-
data: { ...selectedNode.data, [key]: newValue },
1270-
};
1271-
1272-
setNodes((nds) =>
1273-
nds.map((node) =>
1274-
node.id === selectedNode.id ? updatedNode : node
1275-
)
1276-
);
1277-
setSelectedNode(updatedNode);
1278-
}}
1279-
style={{
1280-
width: '100%',
1281-
marginTop: 4,
1282-
padding: '8px',
1283-
borderRadius: '4px',
1284-
border: '1px solid #555',
1285-
backgroundColor: '#2a2a3e',
1286-
color: '#ffffff',
1287-
fontSize: '14px'
1288-
}}
1289-
/>
1290-
</div>
1291-
);
1292-
});
1293-
})()}
1294-
1295-
<br />
1296-
<button
1297-
style={{
1298-
marginTop: 10,
1299-
padding: '8px 16px',
1300-
backgroundColor: '#666',
1301-
color: 'white',
1302-
border: 'none',
1303-
borderRadius: '4px',
1304-
cursor: 'pointer'
1305-
}}
1306-
onClick={() => setSelectedNode(null)}
1307-
>
1308-
Close
1309-
</button>
1310-
1311-
{/* Documentation Section */}
1312-
<div style={{
1313-
marginTop: '20px',
1314-
borderTop: '1px solid #555',
1315-
paddingTop: '15px'
1316-
}}>
1317-
<div
1318-
style={{
1319-
display: 'flex',
1320-
alignItems: 'center',
1321-
justifyContent: 'space-between',
1322-
cursor: 'pointer',
1323-
padding: '8px 0',
1324-
borderRadius: '4px'
1325-
}}
1326-
onClick={() => setIsDocumentationExpanded(!isDocumentationExpanded)}
1327-
>
1328-
<h4 style={{
1329-
color: '#ffffff',
1330-
margin: 0,
1331-
fontSize: '16px',
1332-
fontWeight: 'bold'
1333-
}}>
1334-
Class Documentation
1335-
</h4>
1336-
<span style={{
1337-
color: '#ffffff',
1338-
fontSize: '18px',
1339-
fontWeight: 'bold',
1340-
transform: isDocumentationExpanded ? 'rotate(90deg)' : 'rotate(0deg)',
1341-
transition: 'transform 0.2s ease',
1342-
userSelect: 'none'
1343-
}}>
1344-
1345-
</span>
1346-
</div>
1347-
1348-
{isDocumentationExpanded && (
1349-
<div
1350-
className="documentation-content"
1351-
style={{
1352-
backgroundColor: '#2a2a3e',
1353-
border: '1px solid #555',
1354-
borderRadius: '4px',
1355-
padding: '12px',
1356-
minHeight: '120px',
1357-
maxHeight: '400px',
1358-
overflowY: 'auto',
1359-
fontSize: '13px',
1360-
lineHeight: '1.4',
1361-
color: '#e8e8e8',
1362-
marginTop: '8px'
1363-
}}
1364-
dangerouslySetInnerHTML={{
1365-
__html: nodeDocumentation[selectedNode.type]?.html || 'Loading documentation...'
1366-
}}
1367-
/>
1368-
)}
1369-
</div>
1370-
</div>
1371-
</div>
1372-
)}
1193+
<NodeSidebar
1194+
selectedNode={selectedNode}
1195+
defaultValues={defaultValues}
1196+
setNodes={setNodes}
1197+
setSelectedNode={setSelectedNode}
1198+
isEditingLabel={isEditingLabel}
1199+
setIsEditingLabel={setIsEditingLabel}
1200+
tempLabel={tempLabel}
1201+
setTempLabel={setTempLabel}
1202+
nodeDocumentation={nodeDocumentation}
1203+
isDocumentationExpanded={isDocumentationExpanded}
1204+
setIsDocumentationExpanded={setIsDocumentationExpanded}
1205+
/>
13731206
{selectedEdge && (
13741207
<div
13751208
className="sidebar-scrollable"
@@ -2003,6 +1836,7 @@ const DnDFlow = () => {
20031836
</div>
20041837
)}
20051838

1839+
{/* Results Tab */}
20061840
{activeTab === 'results' && (
20071841
<div style={{
20081842
width: '100%',

0 commit comments

Comments
 (0)