fix: make starter projects auto refactor not remove selected output (#8400)

* Fixed bug where starter projects were refactored incorrectly

* fix: improve handling of selected outputs in custom component template builder

- Added checks to ensure selected output is valid before attempting to set its state.
- Enhanced code readability with comments explaining the logic for selecting outputs.

* Set selected output as the previous selected output

* Update base.py

---------

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
This commit is contained in:
Lucas Oliveira 2025-06-11 11:10:22 -03:00 committed by GitHub
commit 8fd8be52aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 12 additions and 11 deletions

View file

@ -539,7 +539,6 @@ class Component(CustomComponent):
raise ValueError(msg)
return_types = self._get_method_return_type(output.method)
output.add_types(return_types)
output.set_selected()
def _set_output_required_inputs(self) -> None:
for output in self.outputs:
@ -851,7 +850,6 @@ class Component(CustomComponent):
continue
return_types = self._get_method_return_type(output.method)
output.add_types(return_types)
output.set_selected()
frontend_node.validate_component()
frontend_node.set_base_classes_from_outputs()

View file

@ -380,7 +380,7 @@ def build_custom_component_template_from_inputs(
return_types = cc_instance.get_method_return_type(output.method)
return_types = [format_type(return_type) for return_type in return_types]
output.add_types(return_types)
output.set_selected()
# Validate that there is not name overlap between inputs and outputs
frontend_node.validate_component()
# ! This should be removed when we have a better way to handle this

View file

@ -64,7 +64,16 @@ def update_projects_components_with_latest_component_versions(project_data, all_
is_tool_or_agent = node_data.get("tool_mode", False) or node_data.get("key") == "Agent"
has_tool_outputs = any(output.get("types") == ["Tool"] for output in node_data.get("outputs", []))
if "outputs" in latest_node and not has_tool_outputs and not is_tool_or_agent:
# Set selected output as the previous selected output
for output in latest_node["outputs"]:
node_data_output = next(
(output_ for output_ in node_data["outputs"] if output_["name"] == output["name"]),
None,
)
if node_data_output:
output["selected"] = node_data_output.get("selected")
node_data["outputs"] = latest_node["outputs"]
if node_data["template"]["_type"] != latest_template["_type"]:
node_data["template"]["_type"] = latest_template["_type"]
if node_type != "Prompt":

View file

@ -224,9 +224,8 @@ class Output(BaseModel):
if self.types is None:
self.types = []
self.types.extend([t for t in type_ if t not in self.types])
def set_selected(self) -> None:
if not self.selected and self.types:
# If no type is selected and we have types, select the first one
if self.selected is None and self.types:
self.selected = self.types[0]
@model_serializer(mode="wrap")

View file

@ -127,11 +127,6 @@ class TestOutput:
output_obj.add_types(["str", "int"])
assert output_obj.types == ["str", "int"]
def test_output_set_selected(self):
output_obj = Output(name="test_output", types=["str", "int"])
output_obj.set_selected()
assert output_obj.selected == "str"
def test_output_to_dict(self):
output_obj = Output(name="test_output")
assert output_obj.to_dict() == {