From da6a1cf5f2c8c86f8095a3e3b19010a30f75228f Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Fri, 8 Aug 2025 16:45:18 -0400 Subject: [PATCH 1/2] one request for all default values --- src/App.jsx | 174 +++++++++++++++++++++++++------------------------ src/backend.py | 31 +++++++++ 2 files changed, 121 insertions(+), 84 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 7bdebf66..b3204833 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -81,10 +81,10 @@ const DnDFlow = () => { // Global variables state const [globalVariables, setGlobalVariables] = useState([]); const [events, setEvents] = useState([]); - + // Python code editor state const [pythonCode, setPythonCode] = useState("# Define your Python variables and functions here\n# Example:\n# my_variable = 42\n# def my_function(x):\n# return x * 2\n"); - + const [defaultValues, setDefaultValues] = useState({}); const [isEditingLabel, setIsEditingLabel] = useState(false); const [tempLabel, setTempLabel] = useState(''); @@ -147,26 +147,31 @@ const DnDFlow = () => { // Function to preload all default values at startup const preloadDefaultValues = async () => { const availableTypes = Object.keys(nodeTypes); - const promises = availableTypes.map(async (nodeType) => { - try { - const response = await fetch(getApiEndpoint(`/default-values/${nodeType}`)); - if (response.ok) { - const defaults = await response.json(); - return { nodeType, defaults }; - } - } catch (error) { - console.warn(`Failed to preload defaults for ${nodeType}:`, error); - } - return { nodeType, defaults: {} }; - }); - const results = await Promise.all(promises); - const defaultValuesCache = {}; - results.forEach(({ nodeType, defaults }) => { - defaultValuesCache[nodeType] = defaults; - }); + try { + const response = await fetch(getApiEndpoint(`/default-values-all`)); - setDefaultValues(defaultValuesCache); + if (response.ok) { + const allDefaults = await response.json(); + setDefaultValues(allDefaults); + } else { + console.error('Failed to preload default values'); + // Fallback: initialize empty defaults for all types + const defaultValuesCache = {}; + availableTypes.forEach(nodeType => { + defaultValuesCache[nodeType] = {}; + }); + setDefaultValues(defaultValuesCache); + } + } catch (error) { + console.error('Error preloading default values:', error); + // Fallback: initialize empty defaults for all types + const defaultValuesCache = {}; + availableTypes.forEach(nodeType => { + defaultValuesCache[nodeType] = {}; + }); + setDefaultValues(defaultValuesCache); + } }; // Preload all default values when component mounts @@ -308,12 +313,12 @@ const DnDFlow = () => { } // Load the graph data - const { - nodes: loadedNodes, - edges: loadedEdges, - nodeCounter: loadedNodeCounter, - solverParams: loadedSolverParams, - globalVariables: loadedGlobalVariables, + const { + nodes: loadedNodes, + edges: loadedEdges, + nodeCounter: loadedNodeCounter, + solverParams: loadedSolverParams, + globalVariables: loadedGlobalVariables, events: loadedEvents, pythonCode: loadedPythonCode } = graphData; @@ -369,12 +374,12 @@ const DnDFlow = () => { return; } - const { - nodes: loadedNodes, - edges: loadedEdges, - nodeCounter: loadedNodeCounter, - solverParams: loadedSolverParams, - globalVariables: loadedGlobalVariables, + const { + nodes: loadedNodes, + edges: loadedEdges, + nodeCounter: loadedNodeCounter, + solverParams: loadedSolverParams, + globalVariables: loadedGlobalVariables, events: loadedEvents, pythonCode: loadedPythonCode } = graphData; @@ -752,22 +757,22 @@ const DnDFlow = () => { const selectedType = availableTypes[choiceIndex]; const newNodeId = nodeCounter.toString(); - + // Fetch default values and documentation for this node type const defaults = await fetchDefaultValues(selectedType); const docs = await fetchNodeDocumentation(selectedType); - + // Store default values and documentation for this node type setDefaultValues(prev => ({ ...prev, [selectedType]: defaults })); - + setNodeDocumentation(prev => ({ ...prev, [selectedType]: docs })); - + // Create node data with label and initialize all expected fields as empty strings let nodeData = { label: `${selectedType} ${newNodeId}` }; @@ -933,7 +938,7 @@ const DnDFlow = () => { document.removeEventListener('keydown', handleKeyDown); }; }, [selectedEdge, selectedNode, copiedNode, duplicateNode, setCopyFeedback]); - + return (
{/* Tab Navigation */} @@ -1022,7 +1027,8 @@ const DnDFlow = () => {
+ overflow: 'hidden' + }}> {/* Sidebar */}
{ }}>
- + {/* Main Graph Area */}
@@ -1272,50 +1278,50 @@ const DnDFlow = () => { }} >
-

Selected Edge

-
- ID: {selectedEdge.id} -
-
- Source: {selectedEdge.source} -
-
- Target: {selectedEdge.target} -
-
- Type: {selectedEdge.type} -
+

Selected Edge

+
+ ID: {selectedEdge.id} +
+
+ Source: {selectedEdge.source} +
+
+ Target: {selectedEdge.target} +
+
+ Type: {selectedEdge.type} +
-
- - +
+ +
)} @@ -1674,7 +1680,7 @@ const DnDFlow = () => { {/* Global Variables Tab */} {activeTab === 'globals' && ( - { ); } -export function App () { +export function App() { return ( diff --git a/src/backend.py b/src/backend.py index e378d768..4d7def4e 100644 --- a/src/backend.py +++ b/src/backend.py @@ -103,6 +103,37 @@ def health_check(): ), 200 +@app.route("/default-values-all", methods=["GET"]) +def get_all_default_values(): + try: + all_default_values = {} + for node_type, block_class in map_str_to_object.items(): + parameters_for_class = inspect.signature(block_class.__init__).parameters + default_values = {} + for param in parameters_for_class: + if param != "self": # Skip 'self' parameter + default_value = parameters_for_class[param].default + if default_value is inspect._empty: + default_values[param] = None # Handle empty defaults + else: + default_values[param] = default_value + # check if default value is serializable to JSON + if not isinstance( + default_value, (int, float, str, bool, list, dict) + ): + # Attempt to convert to JSON serializable type + try: + default_values[param] = json.dumps(default_value) + except TypeError: + # If conversion fails, set to a string 'default' + default_values[param] = "default" + all_default_values[node_type] = default_values + + return jsonify(all_default_values) + except Exception as e: + return jsonify({"error": f"Could not get all default values: {str(e)}"}), 400 + + # returns default values for parameters of a node @app.route("/default-values/", methods=["GET"]) def get_default_values(node_type): From f1ccabb5786efcef134224d2e7e63238454baa27 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Fri, 8 Aug 2025 16:56:05 -0400 Subject: [PATCH 2/2] request to get all docs in one go --- src/App.jsx | 77 ++++++++++++++++++++++++++++++++++++++++---------- src/backend.py | 24 ++++++++++++++++ 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index b3204833..a17d5aa6 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -144,6 +144,43 @@ const DnDFlow = () => { } }; + // Function to preload all documentation at startup + const preloadAllDocumentation = async () => { + const availableTypes = Object.keys(nodeTypes); + + try { + // Convert types array to a string (or could be sent as JSON array) + const response = await fetch(getApiEndpoint(`/get-all-docs`)); + + if (response.ok) { + const allDocs = await response.json(); + setNodeDocumentation(allDocs); + } else { + console.error('Failed to preload documentation'); + // Fallback: initialize empty documentation for all types + const documentationCache = {}; + availableTypes.forEach(nodeType => { + documentationCache[nodeType] = { + html: '

No documentation available for this node type.

', + text: 'No documentation available for this node type.' + }; + }); + setNodeDocumentation(documentationCache); + } + } catch (error) { + console.error('Error preloading documentation:', error); + // Fallback: initialize empty documentation for all types + const documentationCache = {}; + availableTypes.forEach(nodeType => { + documentationCache[nodeType] = { + html: '

Error loading documentation.

', + text: 'Error loading documentation.' + }; + }); + setNodeDocumentation(documentationCache); + } + }; + // Function to preload all default values at startup const preloadDefaultValues = async () => { const availableTypes = Object.keys(nodeTypes); @@ -174,9 +211,10 @@ const DnDFlow = () => { } }; - // Preload all default values when component mounts + // Preload all default values and documentation when component mounts useEffect(() => { preloadDefaultValues(); + preloadAllDocumentation(); }, []); const onDrop = useCallback( @@ -758,20 +796,29 @@ const DnDFlow = () => { const selectedType = availableTypes[choiceIndex]; const newNodeId = nodeCounter.toString(); - // Fetch default values and documentation for this node type - const defaults = await fetchDefaultValues(selectedType); - const docs = await fetchNodeDocumentation(selectedType); - - // Store default values and documentation for this node type - setDefaultValues(prev => ({ - ...prev, - [selectedType]: defaults - })); - - setNodeDocumentation(prev => ({ - ...prev, - [selectedType]: docs - })); + // Get default values and documentation for this node type (should be cached from preload) + let defaults = defaultValues[selectedType] || {}; + let docs = nodeDocumentation[selectedType] || { + html: '

No documentation available for this node type.

', + text: 'No documentation available for this node type.' + }; + + // Fallback: fetch if not cached (shouldn't happen normally) + if (!defaultValues[selectedType]) { + defaults = await fetchDefaultValues(selectedType); + setDefaultValues(prev => ({ + ...prev, + [selectedType]: defaults + })); + } + + if (!nodeDocumentation[selectedType]) { + docs = await fetchNodeDocumentation(selectedType); + setNodeDocumentation(prev => ({ + ...prev, + [selectedType]: docs + })); + } // Create node data with label and initialize all expected fields as empty strings let nodeData = { label: `${selectedType} ${newNodeId}` }; diff --git a/src/backend.py b/src/backend.py index 4d7def4e..33af927c 100644 --- a/src/backend.py +++ b/src/backend.py @@ -168,6 +168,30 @@ def get_default_values(node_type): ), 400 +@app.route("/get-all-docs", methods=["GET"]) +def get_all_docs(): + try: + all_docs = {} + for node_type, block_class in map_str_to_object.items(): + docstring = inspect.getdoc(block_class) + + # If no docstring, provide a basic description + if not docstring: + docstring = f"No documentation available for {node_type}." + + # Convert docstring to HTML using docutils/Sphinx-style processing + html_content = docstring_to_html(docstring) + + all_docs[node_type] = { + "docstring": docstring, # Keep original for backwards compatibility + "html": html_content, # New HTML version + } + + return jsonify(all_docs) + except Exception as e: + return jsonify({"error": f"Could not get docs for all nodes: {str(e)}"}), 400 + + @app.route("/get-docs/", methods=["GET"]) def get_docs(node_type): try: