refactor(api): rename placeholder to default_value in various parts

Previously the fields / classes are named with `placeholder`. However,
the actual purpose is to use as default values. This commit addresses
this problem by correcting names for relevant fields / classes.

- FormInputPlaceholder
- FormInput.placeholder
- HumanInputRequiredResponse.resolved_placeholder_values
- HumanInputFormDefinition.resolved_placeholder_values
- FormCreateParams.resolved_placeholder_values
- HumanInputRequired.resolved_placeholder_values
- The `resolved_placeholder_values` argument of _create_human_input_delivery_test_form
- The `resolved_placeholder_values` inside _jsonify_form_definition
This commit is contained in:
QuantumGhost
2026-01-23 15:04:46 +08:00
parent 9e56d65612
commit 33a830cbc9
27 changed files with 103 additions and 139 deletions

View File

@ -66,8 +66,8 @@ def test_get_form_includes_site(monkeypatch: pytest.MonkeyPatch, app: Flask):
return {
"form_content": "Raw content",
"rendered_content": "Rendered {{#$output.name#}}",
"inputs": [{"type": "text", "output_variable_name": "name", "placeholder": None}],
"placeholder_values": {"name": "Alice", "age": 30, "meta": {"k": "v"}},
"inputs": [{"type": "text", "output_variable_name": "name", "default": None}],
"default_values": {"name": "Alice", "age": 30, "meta": {"k": "v"}},
"user_actions": [{"id": "approve", "title": "Approve", "button_style": "default"}],
}
@ -132,13 +132,13 @@ def test_get_form_includes_site(monkeypatch: pytest.MonkeyPatch, app: Flask):
"site",
"form_content",
"inputs",
"resolved_placeholder_values",
"resolved_default_values",
"user_actions",
"expiration_time",
}
assert body["form_content"] == "Rendered {{#$output.name#}}"
assert body["inputs"] == [{"type": "text", "output_variable_name": "name", "placeholder": None}]
assert body["resolved_placeholder_values"] == {"name": "Alice", "age": "30", "meta": '{"k": "v"}'}
assert body["inputs"] == [{"type": "text", "output_variable_name": "name", "default": None}]
assert body["resolved_default_values"] == {"name": "Alice", "age": "30", "meta": '{"k": "v"}'}
assert body["user_actions"] == [{"id": "approve", "title": "Approve", "button_style": "default"}]
assert body["expiration_time"] == int(expiration_time.timestamp())
assert body["site"] == {
@ -184,7 +184,7 @@ def test_get_form_allows_backstage_token(monkeypatch: pytest.MonkeyPatch, app: F
"form_content": "Raw content",
"rendered_content": "Rendered",
"inputs": [],
"placeholder_values": {},
"default_values": {},
"user_actions": [],
}
@ -245,13 +245,13 @@ def test_get_form_allows_backstage_token(monkeypatch: pytest.MonkeyPatch, app: F
"site",
"form_content",
"inputs",
"resolved_placeholder_values",
"resolved_default_values",
"user_actions",
"expiration_time",
}
assert body["form_content"] == "Rendered"
assert body["inputs"] == []
assert body["resolved_placeholder_values"] == {}
assert body["resolved_default_values"] == {}
assert body["user_actions"] == []
assert body["expiration_time"] == int(expiration_time.timestamp())
assert body["site"] == {
@ -297,7 +297,7 @@ def test_get_form_raises_forbidden_when_site_missing(monkeypatch: pytest.MonkeyP
"form_content": "Raw content",
"rendered_content": "Rendered",
"inputs": [],
"placeholder_values": {},
"default_values": {},
"user_actions": [],
}

View File

@ -125,7 +125,7 @@ def test_handle_workflow_paused_event_persists_human_input_extra_content() -> No
node_id="node-1",
node_title="Approval",
form_token="token-1",
resolved_placeholder_values={},
resolved_default_values={},
)
event = QueueWorkflowPausedEvent(reasons=[reason], outputs={}, paused_nodes=["node-1"])

View File

@ -124,7 +124,7 @@ def test_queue_workflow_paused_event_to_stream_responses():
form_id="form-1",
form_content="Rendered",
inputs=[
FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="field", placeholder=None),
FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="field", default=None),
],
actions=[UserAction(id="approve", title="Approve")],
display_in_ui=True,

View File

@ -17,7 +17,7 @@ from core.workflow.nodes.human_input.entities import (
EmailRecipients,
ExternalRecipient,
FormInput,
FormInputPlaceholder,
FormInputDefault,
HumanInputNodeData,
MemberRecipient,
UserAction,
@ -76,37 +76,37 @@ class TestDeliveryMethod:
class TestFormInput:
"""Test FormInput entity."""
def test_text_input_with_constant_placeholder(self):
"""Test text input with constant placeholder."""
placeholder = FormInputPlaceholder(type=PlaceholderType.CONSTANT, value="Enter your response here...")
def test_text_input_with_constant_default(self):
"""Test text input with constant default value."""
default = FormInputDefault(type=PlaceholderType.CONSTANT, value="Enter your response here...")
form_input = FormInput(
type=FormInputType.TEXT_INPUT, output_variable_name="user_input", placeholder=placeholder
type=FormInputType.TEXT_INPUT, output_variable_name="user_input", default=default
)
assert form_input.type == FormInputType.TEXT_INPUT
assert form_input.output_variable_name == "user_input"
assert form_input.placeholder.type == PlaceholderType.CONSTANT
assert form_input.placeholder.value == "Enter your response here..."
assert form_input.default.type == PlaceholderType.CONSTANT
assert form_input.default.value == "Enter your response here..."
def test_text_input_with_variable_placeholder(self):
"""Test text input with variable placeholder."""
placeholder = FormInputPlaceholder(type=PlaceholderType.VARIABLE, selector=["node_123", "output_var"])
def test_text_input_with_variable_default(self):
"""Test text input with variable default value."""
default = FormInputDefault(type=PlaceholderType.VARIABLE, selector=["node_123", "output_var"])
form_input = FormInput(
type=FormInputType.TEXT_INPUT, output_variable_name="user_input", placeholder=placeholder
type=FormInputType.TEXT_INPUT, output_variable_name="user_input", default=default
)
assert form_input.placeholder.type == PlaceholderType.VARIABLE
assert form_input.placeholder.selector == ["node_123", "output_var"]
assert form_input.default.type == PlaceholderType.VARIABLE
assert form_input.default.selector == ["node_123", "output_var"]
def test_form_input_without_placeholder(self):
"""Test form input without placeholder."""
def test_form_input_without_default(self):
"""Test form input without default value."""
form_input = FormInput(type=FormInputType.PARAGRAPH, output_variable_name="description")
assert form_input.type == FormInputType.PARAGRAPH
assert form_input.output_variable_name == "description"
assert form_input.placeholder is None
assert form_input.default is None
class TestUserAction:
@ -163,7 +163,7 @@ class TestHumanInputNodeData:
FormInput(
type=FormInputType.TEXT_INPUT,
output_variable_name="content",
placeholder=FormInputPlaceholder(type=PlaceholderType.CONSTANT, value="Enter content..."),
default=FormInputDefault(type=PlaceholderType.CONSTANT, value="Enter content..."),
)
]
@ -209,7 +209,7 @@ class TestHumanInputNodeData:
assert node_data.timeout == 1
assert node_data.timeout_unit == TimeoutUnit.DAY
def test_node_data_default_values(self):
def test_node_data_defaults(self):
"""Test node data with default values."""
node_data = HumanInputNodeData(title="Test Node")
@ -302,9 +302,9 @@ class TestRecipients:
class TestHumanInputNodeVariableResolution:
"""Tests for resolving variable-based placeholders in HumanInputNode."""
"""Tests for resolving variable-based defaults in HumanInputNode."""
def test_resolves_variable_placeholders(self):
def test_resolves_variable_defaults(self):
variable_pool = VariablePool(
system_variables=SystemVariable(
user_id="user",
@ -335,12 +335,12 @@ class TestHumanInputNodeVariableResolution:
FormInput(
type=FormInputType.TEXT_INPUT,
output_variable_name="user_name",
placeholder=FormInputPlaceholder(type=PlaceholderType.VARIABLE, selector=["start", "name"]),
default=FormInputDefault(type=PlaceholderType.VARIABLE, selector=["start", "name"]),
),
FormInput(
type=FormInputType.TEXT_INPUT,
output_variable_name="user_email",
placeholder=FormInputPlaceholder(type=PlaceholderType.CONSTANT, value="foo@example.com"),
default=FormInputDefault(type=PlaceholderType.CONSTANT, value="foo@example.com"),
),
],
user_actions=[UserAction(id="submit", title="Submit")],
@ -370,10 +370,10 @@ class TestHumanInputNodeVariableResolution:
assert isinstance(pause_event, PauseRequestedEvent)
expected_values = {"user_name": "Jane Doe"}
assert pause_event.reason.resolved_placeholder_values == expected_values
assert pause_event.reason.resolved_default_values == expected_values
params = mock_repo.create_form.call_args.args[0]
assert params.resolved_placeholder_values == expected_values
assert params.resolved_default_values == expected_values
def test_debugger_falls_back_to_recipient_token_when_webapp_disabled(self):
variable_pool = VariablePool(

View File

@ -53,7 +53,7 @@ def _build_node(form_content: str = "Please enter your name:\n\n{{#$output.name#
{
"type": "text_input",
"output_variable_name": "name",
"placeholder": {"type": "constant", "value": ""},
"default": {"type": "constant", "value": ""},
}
],
"user_actions": [

View File

@ -50,7 +50,7 @@ class TestFormService:
"tenant_id": "tenant-abc",
"app_id": "app-def",
"form_content": "# Test Form\n\nInput: {{#$output.input#}}",
"inputs": [FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="input", placeholder=None)],
"inputs": [FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="input", default=None)],
"user_actions": [UserAction(id="submit", title="Submit")],
"timeout": 1,
"timeout_unit": TimeoutUnit.HOUR,
@ -305,7 +305,7 @@ class TestFormValidation:
"app_id": "app-def",
"form_content": "Test form",
"inputs": [
FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="required_input", placeholder=None)
FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="required_input", default=None)
],
"user_actions": [UserAction(id="submit", title="Submit")],
"timeout": 1,

View File

@ -31,7 +31,7 @@ class TestHumanInputForm:
"tenant_id": "tenant-abc",
"app_id": "app-def",
"form_content": "# Test Form\n\nInput: {{#$output.input#}}",
"inputs": [FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="input", placeholder=None)],
"inputs": [FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="input", default=None)],
"user_actions": [UserAction(id="submit", title="Submit")],
"timeout": 2,
"timeout_unit": TimeoutUnit.HOUR,

View File

@ -379,7 +379,7 @@ class TestBuildHumanInputRequiredReason:
rendered_content="rendered",
timeout=1,
timeout_unit=TimeoutUnit.HOUR,
placeholder_values={"name": "Alice"},
default_values={"name": "Alice"},
node_title="Ask Name",
display_in_ui=True,
)

View File

@ -127,7 +127,7 @@ def test_get_by_message_ids_returns_unsubmitted_form_definition() -> None:
rendered_content="rendered",
timeout=1,
timeout_unit=TimeoutUnit.HOUR,
placeholder_values={"name": "John"},
default_values={"name": "John"},
node_title="Approval",
display_in_ui=True,
)
@ -177,4 +177,4 @@ def test_get_by_message_ids_returns_unsubmitted_form_definition() -> None:
assert form_definition.form_content == "Rendered block"
assert form_definition.display_in_ui is True
assert form_definition.form_token == "token-1"
assert form_definition.resolved_placeholder_values == {"name": "John"}
assert form_definition.resolved_default_values == {"name": "John"}

View File

@ -24,8 +24,6 @@ from services.workflow_event_snapshot_service import (
BufferState,
MessageContext,
_build_snapshot_events,
_collect_snapshot_keys,
_filter_buffered_events,
_resolve_task_id,
)
@ -221,36 +219,3 @@ def test_resolve_task_id_priority(context_task_id, buffered_task_id, expected) -
buffer_state.task_id_ready.set()
task_id = _resolve_task_id(resumption_context, buffer_state, "run-1", wait_timeout=0.0)
assert task_id == expected
def test_filter_buffered_events_deduplicates_snapshot_nodes() -> None:
workflow_run = _build_workflow_run(WorkflowExecutionStatus.RUNNING)
snapshot = _build_snapshot(WorkflowNodeExecutionStatus.SUCCEEDED)
events = _build_snapshot_events(
workflow_run=workflow_run,
node_snapshots=[snapshot],
task_id="task-1",
message_context=None,
pause_entity=None,
resumption_context=None,
)
snapshot_keys = _collect_snapshot_keys(events)
buffered_events = [
{
"event": "node_started",
"data": {"id": "exec-1"},
},
{
"event": "node_finished",
"data": {"id": "exec-2"},
},
]
filtered = list(_filter_buffered_events(buffered_events, snapshot_keys))
assert filtered == [
{
"event": "node_finished",
"data": {"id": "exec-2"},
}
]

View File

@ -95,7 +95,7 @@ def test_human_input_delivery_dispatches_to_test_service(monkeypatch: pytest.Mon
service._build_human_input_variable_pool = MagicMock(return_value=MagicMock()) # type: ignore[attr-defined]
node_stub = MagicMock()
node_stub._render_form_content_before_submission.return_value = "rendered"
node_stub._resolve_inputs.return_value = {}
node_stub._resolve_default_values.return_value = {}
service._build_human_input_node = MagicMock(return_value=node_stub) # type: ignore[attr-defined]
service._create_human_input_delivery_test_form = MagicMock( # type: ignore[attr-defined]
return_value=("form-1", {})
@ -134,7 +134,7 @@ def test_human_input_delivery_debug_mode_overrides_recipients(monkeypatch: pytes
service._build_human_input_variable_pool = MagicMock(return_value=MagicMock()) # type: ignore[attr-defined]
node_stub = MagicMock()
node_stub._render_form_content_before_submission.return_value = "rendered"
node_stub._resolve_inputs.return_value = {}
node_stub._resolve_default_values.return_value = {}
service._build_human_input_node = MagicMock(return_value=node_stub) # type: ignore[attr-defined]
service._create_human_input_delivery_test_form = MagicMock( # type: ignore[attr-defined]
return_value=("form-1", {})