Add step type icons and inline name editing
- Add icons module with programmatically drawn icons: - Speech bubble for prompt steps - Code brackets </> for code steps - Arrow icons for input/output nodes - Display icons in list view next to step names - Display icons in flow view node headers - Add inline name editing in flow view via property_changed signal - Sync name changes from flow view to tool model and list view Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
@@ -13,6 +13,7 @@ from ...tool import (
|
||||
Tool, ToolArgument, PromptStep, CodeStep,
|
||||
load_tool, save_tool, validate_tool_name, DEFAULT_CATEGORIES
|
||||
)
|
||||
from ..widgets.icons import get_prompt_icon, get_code_icon
|
||||
|
||||
|
||||
class ToolBuilderPage(QWidget):
|
||||
@@ -242,6 +243,7 @@ class ToolBuilderPage(QWidget):
|
||||
self._flow_widget.node_double_clicked.connect(self._on_flow_node_double_clicked)
|
||||
self._flow_widget.steps_deleted.connect(self._on_flow_steps_deleted)
|
||||
self._flow_widget.steps_reordered.connect(self._on_flow_steps_reordered)
|
||||
self._flow_widget.step_name_changed.connect(self._on_flow_step_name_changed)
|
||||
|
||||
# Replace placeholder
|
||||
old_widget = self.steps_stack.widget(1)
|
||||
@@ -283,6 +285,17 @@ class ToolBuilderPage(QWidget):
|
||||
# Refresh the list view (flow view will be refreshed by set_tool)
|
||||
self._refresh_steps()
|
||||
|
||||
def _on_flow_step_name_changed(self, step_index: int, new_name: str):
|
||||
"""Handle step name change from flow view inline editing."""
|
||||
if not self._tool or step_index < 0 or step_index >= len(self._tool.steps):
|
||||
return
|
||||
|
||||
step = self._tool.steps[step_index]
|
||||
step.name = new_name
|
||||
|
||||
# Refresh list view to show updated name
|
||||
self._refresh_steps_list_only()
|
||||
|
||||
def _on_flow_steps_reordered(self, new_order: list):
|
||||
"""Handle step reordering from flow view.
|
||||
|
||||
@@ -371,15 +384,20 @@ class ToolBuilderPage(QWidget):
|
||||
prompt_count += 1
|
||||
# Use custom name if set, otherwise default per-type naming
|
||||
step_name = step.name if step.name else f"Prompt {prompt_count}"
|
||||
text = f"{i}. {step_name} [{step.provider}] → ${step.output_var}"
|
||||
text = f"{step_name} [{step.provider}] → ${step.output_var}"
|
||||
icon = get_prompt_icon(20)
|
||||
elif isinstance(step, CodeStep):
|
||||
code_count += 1
|
||||
step_name = step.name if step.name else f"Code {code_count}"
|
||||
text = f"{i}. {step_name} [python] → ${step.output_var}"
|
||||
text = f"{step_name} [python] → ${step.output_var}"
|
||||
icon = get_code_icon(20)
|
||||
else:
|
||||
text = f"{i}. Unknown step"
|
||||
text = f"Unknown step"
|
||||
icon = None
|
||||
|
||||
item = QListWidgetItem(text)
|
||||
if icon:
|
||||
item.setIcon(icon)
|
||||
item.setData(Qt.UserRole, step)
|
||||
|
||||
# Check for broken dependencies
|
||||
@@ -401,6 +419,59 @@ class ToolBuilderPage(QWidget):
|
||||
if self._flow_widget:
|
||||
self._flow_widget.set_tool(self._tool)
|
||||
|
||||
def _refresh_steps_list_only(self):
|
||||
"""Refresh only the steps list (not flow view).
|
||||
|
||||
Used when a change originated from the flow view to avoid
|
||||
rebuilding the graph unnecessarily.
|
||||
"""
|
||||
self.steps_list.clear()
|
||||
if self._tool and self._tool.steps:
|
||||
# Count steps by type for default naming
|
||||
prompt_count = 0
|
||||
code_count = 0
|
||||
|
||||
# Track available variables for dependency checking
|
||||
available_vars = {"input"}
|
||||
if self._tool.arguments:
|
||||
for arg in self._tool.arguments:
|
||||
if arg.variable:
|
||||
available_vars.add(arg.variable)
|
||||
|
||||
for i, step in enumerate(self._tool.steps, 1):
|
||||
if isinstance(step, PromptStep):
|
||||
prompt_count += 1
|
||||
step_name = step.name if step.name else f"Prompt {prompt_count}"
|
||||
text = f"{step_name} [{step.provider}] → ${step.output_var}"
|
||||
icon = get_prompt_icon(20)
|
||||
elif isinstance(step, CodeStep):
|
||||
code_count += 1
|
||||
step_name = step.name if step.name else f"Code {code_count}"
|
||||
text = f"{step_name} [python] → ${step.output_var}"
|
||||
icon = get_code_icon(20)
|
||||
else:
|
||||
text = f"Unknown step"
|
||||
icon = None
|
||||
|
||||
item = QListWidgetItem(text)
|
||||
if icon:
|
||||
item.setIcon(icon)
|
||||
item.setData(Qt.UserRole, step)
|
||||
|
||||
# Check for broken dependencies
|
||||
refs = self._get_step_variable_refs(step)
|
||||
broken_refs = [r for r in refs if r not in available_vars]
|
||||
if broken_refs:
|
||||
item.setForeground(Qt.red)
|
||||
item.setToolTip(f"Missing variables: {', '.join(broken_refs)}")
|
||||
|
||||
self.steps_list.addItem(item)
|
||||
|
||||
# Add this step's output to available vars for next iteration
|
||||
if hasattr(step, 'output_var') and step.output_var:
|
||||
for var in step.output_var.split(','):
|
||||
available_vars.add(var.strip())
|
||||
|
||||
def _add_argument(self):
|
||||
"""Add a new argument."""
|
||||
from ..dialogs.argument_dialog import ArgumentDialog
|
||||
|
||||
Reference in New Issue
Block a user