diff --git a/docs/docs/components/custom.mdx b/docs/docs/components/custom.mdx
index d8c6ff2f5..9fb0fe689 100644
--- a/docs/docs/components/custom.mdx
+++ b/docs/docs/components/custom.mdx
@@ -83,15 +83,13 @@ The CustomComponent class serves as the foundation for creating custom component
| _`file_types: List[str]`_ | This is a requirement if the _`field_type`_ is _file_. Defines which file types will be accepted. For example, _json_, _yaml_ or _yml_. |
| _`range_spec: langflow.field_typing.RangeSpec`_ | This is a requirement if the _`field_type`_ is _`float`_. Defines the range of values accepted and the step size. If none is defined, the default is _`[-1, 1, 0.1]`_. |
| _`title_case: bool`_ | Formats the name of the field when _`display_name`_ is not defined. Set it to False to keep the name as you set it in the _`build`_ method. |
+ | _`refresh: bool`_ | If set to True a button will appear to the right of the field, and when clicked, it will call the _`update_build_config`_ method which takes in the _`build_config`_, the name of the field (_`field_name`_) and the latest value of the field (_`field_value`_). This is useful when you want to update the _`build_config`_ based on the value of the field. |
-
-
- Keys _`options`_ and _`value`_ can receive a method or function that returns a list of strings or a string, respectively. This is useful when you want to dynamically generate the options or the default value of a field. A refresh button will appear next to the field in the component, allowing the user to update the options or the default value.
-
-
-
+
+By using the _`update_build_config`_ method, you can update the _`build_config`_ in whatever way you want based on the value of the field or not.
+
- The CustomComponent class also provides helpful methods for specific tasks (e.g., to load and use other flows from the Langflow platform):
diff --git a/src/backend/langflow/api/v1/endpoints.py b/src/backend/langflow/api/v1/endpoints.py
index c28d06bcd..b77685d65 100644
--- a/src/backend/langflow/api/v1/endpoints.py
+++ b/src/backend/langflow/api/v1/endpoints.py
@@ -306,7 +306,10 @@ async def custom_component_update(
component = CustomComponent(code=raw_code.code)
component_node = build_custom_component_template(
- component, user_id=user.id, update_field=raw_code.field
+ component,
+ user_id=user.id,
+ update_field=raw_code.field,
+ update_field_value=raw_code.field_value,
)
# Update the field
return component_node
diff --git a/src/backend/langflow/api/v1/schemas.py b/src/backend/langflow/api/v1/schemas.py
index c47082540..17274bcfc 100644
--- a/src/backend/langflow/api/v1/schemas.py
+++ b/src/backend/langflow/api/v1/schemas.py
@@ -166,6 +166,7 @@ class StreamData(BaseModel):
class CustomComponentCode(BaseModel):
code: str
field: Optional[str] = None
+ field_value: Optional[str] = None
frontend_node: Optional[dict] = None
diff --git a/src/backend/langflow/api/v1/validate.py b/src/backend/langflow/api/v1/validate.py
index b062c1329..6b64faf20 100644
--- a/src/backend/langflow/api/v1/validate.py
+++ b/src/backend/langflow/api/v1/validate.py
@@ -1,4 +1,6 @@
from fastapi import APIRouter, HTTPException
+from loguru import logger
+
from langflow.api.v1.base import (
Code,
CodeValidationResponse,
@@ -6,9 +8,8 @@ from langflow.api.v1.base import (
ValidatePromptRequest,
validate_prompt,
)
-from langflow.template.field.base import TemplateField
-from langflow.utils.validate import PROMPT_INPUT_TYPES, validate_code
-from loguru import logger
+from langflow.template.field.prompt import DefaultPromptField
+from langflow.utils.validate import validate_code
# build router
router = APIRouter(prefix="/validate", tags=["Validate"])
@@ -40,7 +41,9 @@ def post_validate_prompt(prompt_request: ValidatePromptRequest):
add_new_variables_to_template(input_variables, prompt_request)
- remove_old_variables_from_template(old_custom_fields, input_variables, prompt_request)
+ remove_old_variables_from_template(
+ old_custom_fields, input_variables, prompt_request
+ )
update_input_variables_field(input_variables, prompt_request)
@@ -55,12 +58,19 @@ def post_validate_prompt(prompt_request: ValidatePromptRequest):
def get_old_custom_fields(prompt_request):
try:
- if len(prompt_request.frontend_node.custom_fields) == 1 and prompt_request.name == "":
+ if (
+ len(prompt_request.frontend_node.custom_fields) == 1
+ and prompt_request.name == ""
+ ):
# If there is only one custom field and the name is empty string
# then we are dealing with the first prompt request after the node was created
- prompt_request.name = list(prompt_request.frontend_node.custom_fields.keys())[0]
+ prompt_request.name = list(
+ prompt_request.frontend_node.custom_fields.keys()
+ )[0]
- old_custom_fields = prompt_request.frontend_node.custom_fields[prompt_request.name]
+ old_custom_fields = prompt_request.frontend_node.custom_fields[
+ prompt_request.name
+ ]
if old_custom_fields is None:
old_custom_fields = []
@@ -74,38 +84,43 @@ def get_old_custom_fields(prompt_request):
def add_new_variables_to_template(input_variables, prompt_request):
for variable in input_variables:
try:
- template_field = TemplateField(
- name=variable,
- display_name=variable,
- field_type="str",
- show=True,
- advanced=False,
- multiline=True,
- input_types=PROMPT_INPUT_TYPES,
- value="", # Set the value to empty string
- )
+ template_field = DefaultPromptField(name=variable, display_name=variable)
if variable in prompt_request.frontend_node.template:
# Set the new field with the old value
- template_field.value = prompt_request.frontend_node.template[variable]["value"]
+ template_field.value = prompt_request.frontend_node.template[variable][
+ "value"
+ ]
prompt_request.frontend_node.template[variable] = template_field.to_dict()
# Check if variable is not already in the list before appending
- if variable not in prompt_request.frontend_node.custom_fields[prompt_request.name]:
- prompt_request.frontend_node.custom_fields[prompt_request.name].append(variable)
+ if (
+ variable
+ not in prompt_request.frontend_node.custom_fields[prompt_request.name]
+ ):
+ prompt_request.frontend_node.custom_fields[prompt_request.name].append(
+ variable
+ )
except Exception as exc:
logger.exception(exc)
raise HTTPException(status_code=500, detail=str(exc)) from exc
-def remove_old_variables_from_template(old_custom_fields, input_variables, prompt_request):
+def remove_old_variables_from_template(
+ old_custom_fields, input_variables, prompt_request
+):
for variable in old_custom_fields:
if variable not in input_variables:
try:
# Remove the variable from custom_fields associated with the given name
- if variable in prompt_request.frontend_node.custom_fields[prompt_request.name]:
- prompt_request.frontend_node.custom_fields[prompt_request.name].remove(variable)
+ if (
+ variable
+ in prompt_request.frontend_node.custom_fields[prompt_request.name]
+ ):
+ prompt_request.frontend_node.custom_fields[
+ prompt_request.name
+ ].remove(variable)
# Remove the variable from the template
prompt_request.frontend_node.template.pop(variable, None)
@@ -117,4 +132,6 @@ def remove_old_variables_from_template(old_custom_fields, input_variables, promp
def update_input_variables_field(input_variables, prompt_request):
if "input_variables" in prompt_request.frontend_node.template:
- prompt_request.frontend_node.template["input_variables"]["value"] = input_variables
+ prompt_request.frontend_node.template["input_variables"][
+ "value"
+ ] = input_variables
diff --git a/src/backend/langflow/interface/custom/code_parser/code_parser.py b/src/backend/langflow/interface/custom/code_parser/code_parser.py
index 258d2fa6b..846edc716 100644
--- a/src/backend/langflow/interface/custom/code_parser/code_parser.py
+++ b/src/backend/langflow/interface/custom/code_parser/code_parser.py
@@ -95,7 +95,9 @@ class CodeParser:
elif isinstance(node, ast.ImportFrom):
for alias in node.names:
if alias.asname:
- self.data["imports"].append((node.module, f"{alias.name} as {alias.asname}"))
+ self.data["imports"].append(
+ (node.module, f"{alias.name} as {alias.asname}")
+ )
else:
self.data["imports"].append((node.module, alias.name))
@@ -144,7 +146,9 @@ class CodeParser:
return_type = None
if node.returns:
return_type_str = ast.unparse(node.returns)
- eval_env = self.construct_eval_env(return_type_str, tuple(self.data["imports"]))
+ eval_env = self.construct_eval_env(
+ return_type_str, tuple(self.data["imports"])
+ )
try:
return_type = eval(return_type_str, eval_env)
@@ -174,7 +178,7 @@ class CodeParser:
args += self.parse_keyword_args(node)
# Commented out because we don't want kwargs
# showing up as fields in the frontend
- # args += self.parse_kwargs(node)
+ args += self.parse_kwargs(node)
return args
@@ -186,14 +190,22 @@ class CodeParser:
num_defaults = len(node.args.defaults)
num_missing_defaults = num_args - num_defaults
missing_defaults = [None] * num_missing_defaults
- default_values = [ast.unparse(default).strip("'") if default else None for default in node.args.defaults]
+ default_values = [
+ ast.unparse(default).strip("'") if default else None
+ for default in node.args.defaults
+ ]
# Now check all default values to see if there
# are any "None" values in the middle
- default_values = [None if value == "None" else value for value in default_values]
+ default_values = [
+ None if value == "None" else value for value in default_values
+ ]
defaults = missing_defaults + default_values
- args = [self.parse_arg(arg, default) for arg, default in zip(node.args.args, defaults)]
+ args = [
+ self.parse_arg(arg, default)
+ for arg, default in zip(node.args.args, defaults)
+ ]
return args
def parse_varargs(self, node: ast.FunctionDef) -> List[Dict[str, Any]]:
@@ -211,11 +223,17 @@ class CodeParser:
"""
Parses the keyword-only arguments of a function or method node.
"""
- kw_defaults = [None] * (len(node.args.kwonlyargs) - len(node.args.kw_defaults)) + [
- ast.unparse(default) if default else None for default in node.args.kw_defaults
+ kw_defaults = [None] * (
+ len(node.args.kwonlyargs) - len(node.args.kw_defaults)
+ ) + [
+ ast.unparse(default) if default else None
+ for default in node.args.kw_defaults
]
- args = [self.parse_arg(arg, default) for arg, default in zip(node.args.kwonlyargs, kw_defaults)]
+ args = [
+ self.parse_arg(arg, default)
+ for arg, default in zip(node.args.kwonlyargs, kw_defaults)
+ ]
return args
def parse_kwargs(self, node: ast.FunctionDef) -> List[Dict[str, Any]]:
@@ -319,7 +337,9 @@ class CodeParser:
Extracts global variables from the code.
"""
global_var = {
- "targets": [t.id if hasattr(t, "id") else ast.dump(t) for t in node.targets],
+ "targets": [
+ t.id if hasattr(t, "id") else ast.dump(t) for t in node.targets
+ ],
"value": ast.unparse(node.value),
}
self.data["global_vars"].append(global_var)
diff --git a/src/backend/langflow/interface/custom/custom_component/custom_component.py b/src/backend/langflow/interface/custom/custom_component/custom_component.py
index d2913be3d..dde147d77 100644
--- a/src/backend/langflow/interface/custom/custom_component/custom_component.py
+++ b/src/backend/langflow/interface/custom/custom_component/custom_component.py
@@ -1,15 +1,7 @@
import operator
from pathlib import Path
-from typing import (
- TYPE_CHECKING,
- Any,
- Callable,
- ClassVar,
- List,
- Optional,
- Sequence,
- Union,
-)
+from typing import (TYPE_CHECKING, Any, Callable, ClassVar, List, Optional,
+ Sequence, Union)
from uuid import UUID
import yaml
@@ -20,17 +12,13 @@ from sqlmodel import select
from langflow.interface.custom.code_parser.utils import (
extract_inner_type_from_generic_alias,
- extract_union_types_from_generic_alias,
-)
+ extract_union_types_from_generic_alias)
from langflow.interface.custom.custom_component.component import Component
from langflow.schema import Record
from langflow.services.database.models.flow import Flow
from langflow.services.database.utils import session_getter
-from langflow.services.deps import (
- get_credential_service,
- get_db_service,
- get_storage_service,
-)
+from langflow.services.deps import (get_credential_service, get_db_service,
+ get_storage_service)
from langflow.services.storage.service import StorageService
from langflow.utils import validate
@@ -138,6 +126,10 @@ class CustomComponent(Component):
def build_config(self):
return self.field_config
+ def update_build_config(self, build_config: dict, field_name: str, field_value: Any):
+ build_config[field_name] = field_value
+ return build_config
+
@property
def tree(self):
return self.get_code_tree(self.code or "")
diff --git a/src/backend/langflow/interface/custom/utils.py b/src/backend/langflow/interface/custom/utils.py
index 85f636811..513669f75 100644
--- a/src/backend/langflow/interface/custom/utils.py
+++ b/src/backend/langflow/interface/custom/utils.py
@@ -8,6 +8,7 @@ from uuid import UUID
from fastapi import HTTPException
from loguru import logger
+from pydantic import BaseModel
from langflow.field_typing.range_spec import RangeSpec
from langflow.interface.custom.attributes import ATTR_FUNC_MAPPING
@@ -27,6 +28,10 @@ from langflow.utils import validate
from langflow.utils.util import get_base_classes
+class UpdateBuildConfigError(Exception):
+ pass
+
+
def add_output_types(
frontend_node: CustomComponentFrontendNode, return_types: List[str]
):
@@ -190,15 +195,23 @@ def add_extra_fields(frontend_node, field_config, function_args):
"""Add extra fields to the frontend node"""
if not function_args:
return
+ _field_config = field_config.copy()
+ function_args_names = [arg["name"] for arg in function_args]
+ # If kwargs is in the function_args and not all field_config keys are in function_args
+ # then we need to add the extra fields
for extra_field in function_args:
- if "name" not in extra_field or extra_field["name"] == "self":
+ if "name" not in extra_field or extra_field["name"] in [
+ "self",
+ "kwargs",
+ "args",
+ ]:
continue
field_name, field_type, field_value, field_required = get_field_properties(
extra_field
)
- config = field_config.get(field_name, {})
+ config = _field_config.pop(field_name, {})
frontend_node = add_new_custom_field(
frontend_node,
field_name,
@@ -207,6 +220,23 @@ def add_extra_fields(frontend_node, field_config, function_args):
field_required,
config,
)
+ if "kwargs" in function_args_names and not all(
+ key in function_args_names for key in field_config.keys()
+ ):
+ for field_name, field_config in _field_config.copy().items():
+ config = _field_config.get(field_name, {})
+ config = config.model_dump() if isinstance(config, BaseModel) else config
+ field_name, field_type, field_value, field_required = get_field_properties(
+ extra_field=config
+ )
+ frontend_node = add_new_custom_field(
+ frontend_node,
+ field_name,
+ field_type,
+ field_value,
+ field_required,
+ config,
+ )
def get_field_dict(field: Union[TemplateField, dict]):
@@ -220,6 +250,7 @@ def run_build_config(
custom_component: CustomComponent,
user_id: Optional[Union[str, UUID]] = None,
update_field=None,
+ update_field_value=None,
):
"""Build the field configuration for a custom component"""
@@ -246,33 +277,48 @@ def run_build_config(
custom_instance = custom_class(user_id=user_id)
build_config: Dict = custom_instance.build_config()
- for field_name, field in build_config.items():
+ for field_name, field in build_config.copy().items():
# Allow user to build TemplateField as well
# as a dict with the same keys as TemplateField
field_dict = get_field_dict(field)
# This has to be done to set refresh if options or value are callable
- update_field_dict(field_dict)
if update_field is not None and field_name != update_field:
+ build_config = update_field_dict(
+ custom_component_instance=custom_instance,
+ field_dict=field_dict,
+ build_config=build_config,
+ call=False,
+ )
continue
try:
- update_field_dict(field_dict, call=True)
+ build_config = update_field_dict(
+ custom_component_instance=custom_instance,
+ field_dict=field_dict,
+ build_config=build_config,
+ update_field=update_field,
+ update_field_value=update_field_value,
+ call=True,
+ )
build_config[field_name] = field_dict
except Exception as exc:
logger.error(f"Error while getting build_config: {str(exc)}")
+ if isinstance(exc, UpdateBuildConfigError):
+ message = str(exc)
+ else:
+ message = f"Error while getting build_config: {str(exc)}"
+ raise HTTPException(
+ status_code=400,
+ detail={
+ "error": message,
+ "traceback": traceback.format_exc(),
+ },
+ ) from exc
return build_config, custom_instance
except Exception as exc:
logger.error(f"Error while building field config: {str(exc)}")
- raise HTTPException(
- status_code=400,
- detail={
- "error": (
- "Invalid type convertion. Please check your code and try again."
- ),
- "traceback": traceback.format_exc(),
- },
- ) from exc
+ raise exc
def sanitize_template_config(template_config):
@@ -317,13 +363,17 @@ def build_custom_component_template(
custom_component: CustomComponent,
user_id: Optional[Union[str, UUID]] = None,
update_field: Optional[str] = None,
+ update_field_value: Optional[str] = None,
) -> Optional[Dict[str, Any]]:
"""Build a custom component template for the langchain"""
try:
frontend_node = build_frontend_node(custom_component.template_config)
field_config, custom_instance = run_build_config(
- custom_component, user_id=user_id, update_field=update_field
+ custom_component,
+ user_id=user_id,
+ update_field=update_field,
+ update_field_value=update_field_value,
)
entrypoint_args = custom_component.get_function_entrypoint_args
@@ -402,22 +452,32 @@ def build_custom_components(settings_service):
return custom_components_from_file
-def update_field_dict(field_dict, call=False):
+def update_field_dict(
+ custom_component_instance: "CustomComponent",
+ field_dict: Dict,
+ build_config: Dict,
+ update_field: Optional[str] = None,
+ update_field_value: Optional[Any] = None,
+ call: bool = False,
+):
"""Update the field dictionary by calling options() or value() if they are callable"""
- if "options" in field_dict and callable(field_dict["options"]):
+ if "refresh" in field_dict:
if call:
- field_dict["options"] = field_dict["options"]()
- # Also update the "refresh" key
- field_dict["refresh"] = True
-
- if "value" in field_dict and callable(field_dict["value"]):
- if call:
- field_dict["value"] = field_dict["value"]()
+ try:
+ custom_component_instance.update_build_config(
+ build_config, update_field, update_field_value
+ )
+ except Exception as exc:
+ logger.error(f"Error while running update_build_config: {str(exc)}")
+ raise UpdateBuildConfigError(
+ f"Error while running update_build_config: {str(exc)}"
+ ) from exc
field_dict["refresh"] = True
# Let's check if "range_spec" is a RangeSpec object
if "rangeSpec" in field_dict and isinstance(field_dict["rangeSpec"], RangeSpec):
field_dict["rangeSpec"] = field_dict["rangeSpec"].model_dump()
+ return build_config
def sanitize_field_config(field_config: Dict):
diff --git a/src/backend/langflow/template/field/prompt.py b/src/backend/langflow/template/field/prompt.py
new file mode 100644
index 000000000..89a4bf745
--- /dev/null
+++ b/src/backend/langflow/template/field/prompt.py
@@ -0,0 +1,14 @@
+from typing import Optional
+
+from langflow.template.field.base import TemplateField
+
+
+class DefaultPromptField(TemplateField):
+ name: str
+ display_name: Optional[str] = None
+ field_type: str = "str"
+
+ advanced: bool = False
+ multiline: bool = True
+ input_types: list[str] = ["Document", "BaseOutputParser", "Text", "Record"]
+ value: str = "" # Set the value to empty string
diff --git a/src/backend/langflow/utils/validate.py b/src/backend/langflow/utils/validate.py
index 21821538c..9611d3a56 100644
--- a/src/backend/langflow/utils/validate.py
+++ b/src/backend/langflow/utils/validate.py
@@ -6,8 +6,6 @@ from typing import Dict, List, Optional, Union
from langflow.field_typing.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES
-PROMPT_INPUT_TYPES = ["Document", "BaseOutputParser", "Text", "Record"]
-
def add_type_ignores():
if not hasattr(ast, "TypeIgnore"):
@@ -45,7 +43,9 @@ def validate_code(code):
# Evaluate the function definition
for node in tree.body:
if isinstance(node, ast.FunctionDef):
- code_obj = compile(ast.Module(body=[node], type_ignores=[]), "", "exec")
+ code_obj = compile(
+ ast.Module(body=[node], type_ignores=[]), "", "exec"
+ )
try:
exec(code_obj)
except Exception as e:
@@ -89,15 +89,23 @@ def execute_function(code, function_name, *args, **kwargs):
exec_globals,
locals(),
)
- exec_globals[alias.asname or alias.name] = importlib.import_module(alias.name)
+ exec_globals[alias.asname or alias.name] = importlib.import_module(
+ alias.name
+ )
except ModuleNotFoundError as e:
- raise ModuleNotFoundError(f"Module {alias.name} not found. Please install it and try again.") from e
+ raise ModuleNotFoundError(
+ f"Module {alias.name} not found. Please install it and try again."
+ ) from e
function_code = next(
- node for node in module.body if isinstance(node, ast.FunctionDef) and node.name == function_name
+ node
+ for node in module.body
+ if isinstance(node, ast.FunctionDef) and node.name == function_name
)
function_code.parent = None
- code_obj = compile(ast.Module(body=[function_code], type_ignores=[]), "", "exec")
+ code_obj = compile(
+ ast.Module(body=[function_code], type_ignores=[]), "", "exec"
+ )
try:
exec(code_obj, exec_globals, locals())
except Exception as exc:
@@ -124,15 +132,23 @@ def create_function(code, function_name):
if isinstance(node, ast.Import):
for alias in node.names:
try:
- exec_globals[alias.asname or alias.name] = importlib.import_module(alias.name)
+ exec_globals[alias.asname or alias.name] = importlib.import_module(
+ alias.name
+ )
except ModuleNotFoundError as e:
- raise ModuleNotFoundError(f"Module {alias.name} not found. Please install it and try again.") from e
+ raise ModuleNotFoundError(
+ f"Module {alias.name} not found. Please install it and try again."
+ ) from e
function_code = next(
- node for node in module.body if isinstance(node, ast.FunctionDef) and node.name == function_name
+ node
+ for node in module.body
+ if isinstance(node, ast.FunctionDef) and node.name == function_name
)
function_code.parent = None
- code_obj = compile(ast.Module(body=[function_code], type_ignores=[]), "", "exec")
+ code_obj = compile(
+ ast.Module(body=[function_code], type_ignores=[]), "", "exec"
+ )
with contextlib.suppress(Exception):
exec(code_obj, exec_globals, locals())
exec_globals[function_name] = locals()[function_name]
@@ -194,9 +210,13 @@ def prepare_global_scope(code, module):
if isinstance(node, ast.Import):
for alias in node.names:
try:
- exec_globals[alias.asname or alias.name] = importlib.import_module(alias.name)
+ exec_globals[alias.asname or alias.name] = importlib.import_module(
+ alias.name
+ )
except ModuleNotFoundError as e:
- raise ModuleNotFoundError(f"Module {alias.name} not found. Please install it and try again.") from e
+ raise ModuleNotFoundError(
+ f"Module {alias.name} not found. Please install it and try again."
+ ) from e
elif isinstance(node, ast.ImportFrom) and node.module is not None:
try:
imported_module = importlib.import_module(node.module)
@@ -217,7 +237,11 @@ def extract_class_code(module, class_name):
:param class_name: Name of the class to extract
:return: AST node of the specified class
"""
- class_code = next(node for node in module.body if isinstance(node, ast.ClassDef) and node.name == class_name)
+ class_code = next(
+ node
+ for node in module.body
+ if isinstance(node, ast.ClassDef) and node.name == class_name
+ )
class_code.parent = None
return class_code
@@ -230,7 +254,9 @@ def compile_class_code(class_code):
:param class_code: AST node of the class
:return: Compiled code object of the class
"""
- code_obj = compile(ast.Module(body=[class_code], type_ignores=[]), "", "exec")
+ code_obj = compile(
+ ast.Module(body=[class_code], type_ignores=[]), "", "exec"
+ )
return code_obj
@@ -274,7 +300,9 @@ def get_default_imports(code_string):
langflow_imports = list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())
necessary_imports = find_names_in_code(code_string, langflow_imports)
langflow_module = importlib.import_module("langflow.field_typing")
- default_imports.update({name: getattr(langflow_module, name) for name in necessary_imports})
+ default_imports.update(
+ {name: getattr(langflow_module, name) for name in necessary_imports}
+ )
return default_imports
diff --git a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx
index 83d916a9d..7a6c306f1 100644
--- a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx
+++ b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx
@@ -98,24 +98,33 @@ export default function ParameterComponent({
return;
}
- try {
- const res = await postCustomComponentUpdate(code, name);
- if (res.status === 200 && data.node?.template) {
- setNode(data.id, (oldNode) => {
- let newNode = cloneDeep(oldNode);
+ await postCustomComponentUpdate(
+ code,
+ name,
+ data.node?.template[name]?.value
+ )
+ .then((res) => {
+ if (res.status === 200 && data.node?.template) {
+ setNode(data.id, (oldNode) => {
+ let newNode = cloneDeep(oldNode);
- newNode.data = {
- ...newNode.data,
- };
+ newNode.data = {
+ ...newNode.data,
+ };
- newNode.data.node.template[name] = res.data.template[name];
+ newNode.data.node.template = res.data.template;
- return newNode;
+ return newNode;
+ });
+ }
+ })
+ .catch((error) => {
+ console.error("Error occurred while updating the node:", error);
+ setErrorData({
+ title: "Error while updating the Component",
+ list: [error.response.data.detail.error ?? "Unknown error"],
});
- }
- } catch (err) {
- setErrorData(err as { title: string; list?: Array });
- }
+ });
renderTooltips();
if (delayAnimation) {
diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts
index ff6305cfd..6ee4141a0 100644
--- a/src/frontend/src/controllers/API/index.ts
+++ b/src/frontend/src/controllers/API/index.ts
@@ -369,11 +369,13 @@ export async function postCustomComponent(
export async function postCustomComponentUpdate(
code: string,
- field: string
+ field: string,
+ field_value: string
): Promise> {
return await api.post(`${BASE_URL_API}custom_component/update`, {
code,
field,
+ field_value,
});
}