@@ -15,9 +15,10 @@ import './App.css';
1515import Plot from 'react-plotly.js' ;
1616import { getApiEndpoint } from './config.js' ;
1717import Sidebar from './Sidebar' ;
18+ import NodeSidebar from './NodeSidebar' ;
1819import { DnDProvider , useDnD } from './DnDContext.jsx' ;
1920import ContextMenu from './ContextMenu.jsx' ;
20-
21+ import { isValidPythonIdentifier } from './utils.js' ;
2122import { makeEdge } from './CustomEdge' ;
2223import { 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 - z A - Z _ ] [ a - z A - Z 0 - 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