mirror of
https://github.com/langgenius/dify.git
synced 2026-05-09 21:28:25 +08:00
refactor(api): rename form definitions fields
This commit is contained in:
parent
7a12d46a45
commit
74f17d0ec8
@ -5,7 +5,7 @@ from typing import Any, TypeAlias
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
from graphon.nodes.human_input.entities import FormInput, UserAction
|
||||
from graphon.nodes.human_input.entities import FormInputConfig, UserActionConfig
|
||||
from models.execution_extra_content import ExecutionContentType
|
||||
|
||||
|
||||
@ -16,8 +16,8 @@ class HumanInputFormDefinition(BaseModel):
|
||||
node_id: str
|
||||
node_title: str
|
||||
form_content: str
|
||||
inputs: Sequence[FormInput] = Field(default_factory=list)
|
||||
actions: Sequence[UserAction] = Field(default_factory=list)
|
||||
inputs: Sequence[FormInputConfig] = Field(default_factory=list)
|
||||
actions: Sequence[UserActionConfig] = Field(default_factory=list)
|
||||
display_in_ui: bool = False
|
||||
form_token: str | None = None
|
||||
resolved_default_values: Mapping[str, Any] = Field(default_factory=dict)
|
||||
|
||||
@ -17,7 +17,7 @@ from core.workflow.human_input_adapter import (
|
||||
MemberRecipient,
|
||||
WebAppDeliveryMethod,
|
||||
)
|
||||
from graphon.nodes.human_input.entities import FormDefinition, HumanInputNodeData, UserAction
|
||||
from graphon.nodes.human_input.entities import FormDefinition, HumanInputNodeData, UserActionConfig
|
||||
from models.account import (
|
||||
Account,
|
||||
AccountStatus,
|
||||
@ -69,7 +69,7 @@ def _build_form_params(delivery_methods: list[DeliveryChannelConfig]) -> FormCre
|
||||
title="Human Approval",
|
||||
delivery_methods=delivery_methods,
|
||||
form_content="<p>Approve?</p>",
|
||||
user_actions=[UserAction(id="approve", title="Approve")],
|
||||
user_actions=[UserActionConfig(id="approve", title="Approve")],
|
||||
)
|
||||
return FormCreateParams(
|
||||
workflow_execution_id=str(uuid4()),
|
||||
@ -185,7 +185,7 @@ class TestHumanInputFormRepositoryImplWithContainers:
|
||||
title="Human Approval",
|
||||
form_content="<p>Approve?</p>",
|
||||
inputs=[],
|
||||
user_actions=[UserAction(id="approve", title="Approve")],
|
||||
user_actions=[UserActionConfig(id="approve", title="Approve")],
|
||||
),
|
||||
rendered_content="<p>Approve?</p>",
|
||||
delivery_methods=[],
|
||||
@ -220,7 +220,7 @@ class TestHumanInputFormRepositoryImplWithContainers:
|
||||
title="Human Approval",
|
||||
form_content="<p>Approve?</p>",
|
||||
inputs=[],
|
||||
user_actions=[UserAction(id="approve", title="Approve")],
|
||||
user_actions=[UserActionConfig(id="approve", title="Approve")],
|
||||
delivery_methods=[WebAppDeliveryMethod()],
|
||||
),
|
||||
rendered_content="<p>Approve?</p>",
|
||||
|
||||
@ -21,7 +21,7 @@ from graphon.graph_engine import GraphEngine
|
||||
from graphon.graph_engine.command_channels import InMemoryChannel
|
||||
from graphon.nodes.end.end_node import EndNode
|
||||
from graphon.nodes.end.entities import EndNodeData
|
||||
from graphon.nodes.human_input.entities import HumanInputNodeData, UserAction
|
||||
from graphon.nodes.human_input.entities import HumanInputNodeData, UserActionConfig
|
||||
from graphon.nodes.human_input.enums import HumanInputFormStatus
|
||||
from graphon.nodes.human_input.human_input_node import HumanInputNode
|
||||
from graphon.nodes.start.entities import StartNodeData
|
||||
@ -112,7 +112,7 @@ def _build_graph(
|
||||
form_content="Awaiting human input",
|
||||
inputs=[],
|
||||
user_actions=[
|
||||
UserAction(id="continue", title="Continue"),
|
||||
UserActionConfig(id="continue", title="Continue"),
|
||||
],
|
||||
)
|
||||
human_node = HumanInputNode(
|
||||
|
||||
@ -15,8 +15,8 @@ from extensions.ext_storage import storage
|
||||
from graphon.entities import WorkflowExecution
|
||||
from graphon.entities.pause_reason import HumanInputRequired, PauseReasonType
|
||||
from graphon.enums import WorkflowExecutionStatus
|
||||
from graphon.nodes.human_input.entities import FormDefinition, FormInput, UserAction
|
||||
from graphon.nodes.human_input.enums import FormInputType, HumanInputFormStatus
|
||||
from graphon.nodes.human_input.entities import FormDefinition, ParagraphInputConfig, UserActionConfig
|
||||
from graphon.nodes.human_input.enums import HumanInputFormStatus
|
||||
from libs.datetime_utils import naive_utc_now
|
||||
from models.enums import CreatorUserRole, WorkflowRunTriggeredFrom
|
||||
from models.human_input import (
|
||||
@ -638,8 +638,8 @@ class TestBuildHumanInputRequiredReason:
|
||||
expiration_time = naive_utc_now()
|
||||
form_definition = FormDefinition(
|
||||
form_content="content",
|
||||
inputs=[FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="name")],
|
||||
user_actions=[UserAction(id="approve", title="Approve")],
|
||||
inputs=[ParagraphInputConfig(output_variable_name="name")],
|
||||
user_actions=[UserActionConfig(id="approve", title="Approve")],
|
||||
rendered_content="rendered",
|
||||
expiration_time=expiration_time,
|
||||
default_values={"name": "Alice"},
|
||||
|
||||
@ -177,9 +177,9 @@ def _create_submitted_form(
|
||||
) -> HumanInputForm:
|
||||
expiration_time = naive_utc_now() + timedelta(days=1)
|
||||
form_definition = FormDefinition(
|
||||
form_content="content",
|
||||
inputs=[],
|
||||
user_actions=[UserAction(id=action_id, title=action_title)],
|
||||
form_content=form_content,
|
||||
inputs=inputs or [],
|
||||
user_actions=[UserActionConfig(id=action_id, title=action_title)],
|
||||
rendered_content="rendered",
|
||||
expiration_time=expiration_time,
|
||||
node_title=node_title,
|
||||
|
||||
@ -12,8 +12,7 @@ from controllers.console.app import workflow_run as workflow_run_module
|
||||
from controllers.web.error import NotFoundError
|
||||
from graphon.entities.pause_reason import HumanInputRequired
|
||||
from graphon.enums import WorkflowExecutionStatus
|
||||
from graphon.nodes.human_input.entities import FormInput, UserAction
|
||||
from graphon.nodes.human_input.enums import FormInputType
|
||||
from graphon.nodes.human_input.entities import ParagraphInputConfig, UserActionConfig
|
||||
from libs import login as login_lib
|
||||
from models.account import Account, AccountStatus, TenantAccountRole
|
||||
from models.workflow import WorkflowRun
|
||||
@ -63,8 +62,8 @@ def test_pause_details_returns_backstage_input_url(app: Flask, monkeypatch: pyte
|
||||
reason = HumanInputRequired(
|
||||
form_id="form-1",
|
||||
form_content="content",
|
||||
inputs=[FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="name")],
|
||||
actions=[UserAction(id="approve", title="Approve")],
|
||||
inputs=[ParagraphInputConfig(output_variable_name="name")],
|
||||
actions=[UserActionConfig(id="approve", title="Approve")],
|
||||
node_id="node-1",
|
||||
node_title="Ask Name",
|
||||
)
|
||||
|
||||
@ -14,8 +14,7 @@ from core.workflow.system_variables import build_system_variables
|
||||
from graphon.entities import WorkflowStartReason
|
||||
from graphon.entities.pause_reason import HumanInputRequired
|
||||
from graphon.graph_events import GraphRunPausedEvent
|
||||
from graphon.nodes.human_input.entities import FormInput, UserAction
|
||||
from graphon.nodes.human_input.enums import FormInputType
|
||||
from graphon.nodes.human_input.entities import ParagraphInputConfig, UserActionConfig
|
||||
from models.account import Account
|
||||
from models.human_input import RecipientType
|
||||
|
||||
@ -156,10 +155,8 @@ def test_queue_workflow_paused_event_to_stream_responses(monkeypatch: pytest.Mon
|
||||
reason = HumanInputRequired(
|
||||
form_id="form-1",
|
||||
form_content="Rendered",
|
||||
inputs=[
|
||||
FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="field", default=None),
|
||||
],
|
||||
actions=[UserAction(id="approve", title="Approve")],
|
||||
inputs=[ParagraphInputConfig(output_variable_name="field")],
|
||||
actions=[UserActionConfig(id="approve", title="Approve")],
|
||||
node_id="node-id",
|
||||
node_title="Human Step",
|
||||
)
|
||||
|
||||
@ -4,8 +4,7 @@ from core.entities.execution_extra_content import (
|
||||
HumanInputFormDefinition,
|
||||
HumanInputFormSubmissionData,
|
||||
)
|
||||
from graphon.nodes.human_input.entities import FormInput, UserAction
|
||||
from graphon.nodes.human_input.enums import FormInputType
|
||||
from graphon.nodes.human_input.entities import ParagraphInputConfig, UserActionConfig
|
||||
from models.execution_extra_content import ExecutionContentType
|
||||
|
||||
|
||||
@ -16,8 +15,8 @@ def test_human_input_content_defaults_and_domain_alias() -> None:
|
||||
node_id="node-1",
|
||||
node_title="Human Input",
|
||||
form_content="Please confirm",
|
||||
inputs=[FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="answer")],
|
||||
actions=[UserAction(id="confirm", title="Confirm")],
|
||||
inputs=[ParagraphInputConfig(output_variable_name="answer")],
|
||||
actions=[UserActionConfig(id="confirm", title="Confirm")],
|
||||
resolved_default_values={"answer": "yes"},
|
||||
expiration_time=1_700_000_000,
|
||||
)
|
||||
|
||||
@ -23,7 +23,7 @@ from core.workflow.human_input_adapter import (
|
||||
)
|
||||
from graphon.nodes.human_input.entities import (
|
||||
FormDefinition,
|
||||
UserAction,
|
||||
UserActionConfig,
|
||||
)
|
||||
from graphon.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus
|
||||
from libs.datetime_utils import naive_utc_now
|
||||
@ -272,7 +272,7 @@ def _make_form_definition() -> str:
|
||||
return FormDefinition(
|
||||
form_content="hello",
|
||||
inputs=[],
|
||||
user_actions=[UserAction(id="submit", title="Submit")],
|
||||
user_actions=[UserActionConfig(id="submit", title="Submit")],
|
||||
rendered_content="<p>hello</p>",
|
||||
expiration_time=naive_utc_now(),
|
||||
).model_dump_json()
|
||||
|
||||
@ -29,7 +29,7 @@ from core.workflow.human_input_adapter import (
|
||||
MemberRecipient,
|
||||
WebAppDeliveryMethod,
|
||||
)
|
||||
from graphon.nodes.human_input.entities import HumanInputNodeData, UserAction
|
||||
from graphon.nodes.human_input.entities import HumanInputNodeData, UserActionConfig
|
||||
from graphon.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus
|
||||
from libs.datetime_utils import naive_utc_now
|
||||
from models.human_input import HumanInputFormRecipient, RecipientType
|
||||
|
||||
@ -24,7 +24,14 @@ from graphon.graph_events import (
|
||||
from graphon.nodes.base.entities import OutputVariableEntity
|
||||
from graphon.nodes.end.end_node import EndNode
|
||||
from graphon.nodes.end.entities import EndNodeData
|
||||
from graphon.nodes.human_input.entities import HumanInputNodeData, UserAction
|
||||
from graphon.nodes.human_input.entities import (
|
||||
FileInputConfig,
|
||||
FileListInputConfig,
|
||||
HumanInputNodeData,
|
||||
SelectInputConfig,
|
||||
StringListSource,
|
||||
UserActionConfig,
|
||||
)
|
||||
from graphon.nodes.human_input.enums import HumanInputFormStatus
|
||||
from graphon.nodes.human_input.human_input_node import HumanInputNode
|
||||
from graphon.nodes.start.entities import StartNodeData
|
||||
|
||||
@ -36,20 +36,25 @@ from graphon.entities import GraphInitParams
|
||||
from graphon.node_events import PauseRequestedEvent
|
||||
from graphon.node_events.node import StreamCompletedEvent
|
||||
from graphon.nodes.human_input.entities import (
|
||||
FormInput,
|
||||
FormInputDefault,
|
||||
FileInputConfig,
|
||||
FileListInputConfig,
|
||||
HumanInputNodeData,
|
||||
UserAction,
|
||||
ParagraphInputConfig,
|
||||
SelectInputConfig,
|
||||
StringListSource,
|
||||
StringSource,
|
||||
UserActionConfig,
|
||||
)
|
||||
from graphon.nodes.human_input.enums import (
|
||||
ButtonStyle,
|
||||
FormInputType,
|
||||
HumanInputFormStatus,
|
||||
PlaceholderType,
|
||||
TimeoutUnit,
|
||||
ValueSourceType,
|
||||
)
|
||||
from graphon.nodes.human_input.human_input_node import HumanInputNode
|
||||
from graphon.runtime import GraphRuntimeState, VariablePool
|
||||
from graphon.variables.segments import ArrayFileSegment, FileSegment
|
||||
from libs.datetime_utils import naive_utc_now
|
||||
|
||||
|
||||
@ -195,27 +200,27 @@ class TestFormInput:
|
||||
|
||||
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...")
|
||||
default = StringSource(type=ValueSourceType.CONSTANT, value="Enter your response here...")
|
||||
|
||||
form_input = FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="user_input", default=default)
|
||||
form_input = ParagraphInputConfig(output_variable_name="user_input", default=default)
|
||||
|
||||
assert form_input.type == FormInputType.TEXT_INPUT
|
||||
assert form_input.type == FormInputType.PARAGRAPH
|
||||
assert form_input.output_variable_name == "user_input"
|
||||
assert form_input.default.type == PlaceholderType.CONSTANT
|
||||
assert form_input.default.type == ValueSourceType.CONSTANT
|
||||
assert form_input.default.value == "Enter your response here..."
|
||||
|
||||
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"])
|
||||
default = StringSource(type=ValueSourceType.VARIABLE, selector=["node_123", "output_var"])
|
||||
|
||||
form_input = FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="user_input", default=default)
|
||||
form_input = ParagraphInputConfig(output_variable_name="user_input", default=default)
|
||||
|
||||
assert form_input.default.type == PlaceholderType.VARIABLE
|
||||
assert form_input.default.type == ValueSourceType.VARIABLE
|
||||
assert form_input.default.selector == ["node_123", "output_var"]
|
||||
|
||||
def test_form_input_without_default(self):
|
||||
"""Test form input without default value."""
|
||||
form_input = FormInput(type=FormInputType.PARAGRAPH, output_variable_name="description")
|
||||
form_input = ParagraphInputConfig(output_variable_name="description")
|
||||
|
||||
assert form_input.type == FormInputType.PARAGRAPH
|
||||
assert form_input.output_variable_name == "description"
|
||||
@ -227,7 +232,7 @@ class TestUserAction:
|
||||
|
||||
def test_user_action_creation(self):
|
||||
"""Test user action creation."""
|
||||
action = UserAction(id="approve", title="Approve", button_style=ButtonStyle.PRIMARY)
|
||||
action = UserActionConfig(id="approve", title="Approve", button_style=ButtonStyle.PRIMARY)
|
||||
|
||||
assert action.id == "approve"
|
||||
assert action.title == "Approve"
|
||||
@ -235,13 +240,13 @@ class TestUserAction:
|
||||
|
||||
def test_user_action_default_button_style(self):
|
||||
"""Test user action with default button style."""
|
||||
action = UserAction(id="cancel", title="Cancel")
|
||||
action = UserActionConfig(id="cancel", title="Cancel")
|
||||
|
||||
assert action.button_style == ButtonStyle.DEFAULT
|
||||
|
||||
def test_user_action_length_boundaries(self):
|
||||
"""Test user action id and title length boundaries."""
|
||||
action = UserAction(id="a" * 20, title="b" * 20)
|
||||
action = UserActionConfig(id="a" * 20, title="b" * 20)
|
||||
|
||||
assert action.id == "a" * 20
|
||||
assert action.title == "b" * 20
|
||||
@ -259,7 +264,7 @@ class TestUserAction:
|
||||
data[field_name] = value
|
||||
|
||||
with pytest.raises(ValidationError) as exc_info:
|
||||
UserAction.model_validate(data)
|
||||
UserActionConfig.model_validate(data)
|
||||
|
||||
errors = exc_info.value.errors()
|
||||
assert any(error["loc"] == (field_name,) and error["type"] == "string_too_long" for error in errors)
|
||||
@ -273,14 +278,13 @@ class TestHumanInputNodeData:
|
||||
delivery_methods = [WebAppDeliveryMethod(enabled=True, config=_WebAppDeliveryConfig())]
|
||||
|
||||
inputs = [
|
||||
FormInput(
|
||||
type=FormInputType.TEXT_INPUT,
|
||||
ParagraphInputConfig(
|
||||
output_variable_name="content",
|
||||
default=FormInputDefault(type=PlaceholderType.CONSTANT, value="Enter content..."),
|
||||
default=StringSource(type=ValueSourceType.CONSTANT, value="Enter content..."),
|
||||
)
|
||||
]
|
||||
|
||||
user_actions = [UserAction(id="submit", title="Submit", button_style=ButtonStyle.PRIMARY)]
|
||||
user_actions = [UserActionConfig(id="submit", title="Submit", button_style=ButtonStyle.PRIMARY)]
|
||||
|
||||
node_data = HumanInputNodeData(
|
||||
title="Human Input Test",
|
||||
@ -338,8 +342,8 @@ class TestHumanInputNodeData:
|
||||
def test_duplicate_input_output_variable_name_raises_validation_error(self):
|
||||
"""Duplicate form input output_variable_name should raise validation error."""
|
||||
duplicate_inputs = [
|
||||
FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="content"),
|
||||
FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="content"),
|
||||
ParagraphInputConfig(output_variable_name="content"),
|
||||
ParagraphInputConfig(output_variable_name="content"),
|
||||
]
|
||||
|
||||
with pytest.raises(ValidationError, match="duplicated output_variable_name 'content'"):
|
||||
@ -348,8 +352,8 @@ class TestHumanInputNodeData:
|
||||
def test_duplicate_user_action_ids_raise_validation_error(self):
|
||||
"""Duplicate user action ids should raise validation error."""
|
||||
duplicate_actions = [
|
||||
UserAction(id="submit", title="Submit"),
|
||||
UserAction(id="submit", title="Submit Again"),
|
||||
UserActionConfig(id="submit", title="Submit"),
|
||||
UserActionConfig(id="submit", title="Submit Again"),
|
||||
]
|
||||
|
||||
with pytest.raises(ValidationError, match="duplicated user action id 'submit'"):
|
||||
@ -458,18 +462,16 @@ class TestHumanInputNodeVariableResolution:
|
||||
title="Human Input",
|
||||
form_content="Provide your name",
|
||||
inputs=[
|
||||
FormInput(
|
||||
type=FormInputType.TEXT_INPUT,
|
||||
ParagraphInputConfig(
|
||||
output_variable_name="user_name",
|
||||
default=FormInputDefault(type=PlaceholderType.VARIABLE, selector=["start", "name"]),
|
||||
default=StringSource(type=ValueSourceType.VARIABLE, selector=["start", "name"]),
|
||||
),
|
||||
FormInput(
|
||||
type=FormInputType.TEXT_INPUT,
|
||||
ParagraphInputConfig(
|
||||
output_variable_name="user_email",
|
||||
default=FormInputDefault(type=PlaceholderType.CONSTANT, value="foo@example.com"),
|
||||
default=StringSource(type=ValueSourceType.CONSTANT, value="foo@example.com"),
|
||||
),
|
||||
],
|
||||
user_actions=[UserAction(id="submit", title="Submit")],
|
||||
user_actions=[UserActionConfig(id="submit", title="Submit")],
|
||||
)
|
||||
config = {"id": "human", "data": node_data.model_dump()}
|
||||
|
||||
@ -534,7 +536,7 @@ class TestHumanInputNodeVariableResolution:
|
||||
title="Human Input",
|
||||
form_content="Provide your name",
|
||||
inputs=[],
|
||||
user_actions=[UserAction(id="submit", title="Submit")],
|
||||
user_actions=[UserActionConfig(id="submit", title="Submit")],
|
||||
)
|
||||
config = {"id": "human", "data": node_data.model_dump()}
|
||||
|
||||
@ -661,7 +663,7 @@ class TestHumanInputNodeVariableResolution:
|
||||
title="Human Input",
|
||||
form_content="Provide your name",
|
||||
inputs=[],
|
||||
user_actions=[UserAction(id="submit", title="Submit")],
|
||||
user_actions=[UserActionConfig(id="submit", title="Submit")],
|
||||
delivery_methods=[
|
||||
EmailDeliveryMethod(
|
||||
enabled=True,
|
||||
@ -721,15 +723,17 @@ class TestValidation:
|
||||
def test_invalid_form_input_type(self):
|
||||
"""Test validation with invalid form input type."""
|
||||
with pytest.raises(ValidationError):
|
||||
FormInput(
|
||||
type="invalid-type", # Invalid type
|
||||
output_variable_name="test",
|
||||
ParagraphInputConfig.model_validate(
|
||||
{
|
||||
"type": "invalid-type",
|
||||
"output_variable_name": "test",
|
||||
}
|
||||
)
|
||||
|
||||
def test_invalid_button_style(self):
|
||||
"""Test validation with invalid button style."""
|
||||
with pytest.raises(ValidationError):
|
||||
UserAction(
|
||||
UserActionConfig(
|
||||
id="test",
|
||||
title="Test",
|
||||
button_style="invalid-style", # Invalid style
|
||||
@ -777,13 +781,8 @@ class TestHumanInputNodeRenderedContent:
|
||||
node_data = HumanInputNodeData(
|
||||
title="Human Input",
|
||||
form_content="Name: {{#$output.name#}}",
|
||||
inputs=[
|
||||
FormInput(
|
||||
type=FormInputType.TEXT_INPUT,
|
||||
output_variable_name="name",
|
||||
)
|
||||
],
|
||||
user_actions=[UserAction(id="approve", title="Approve")],
|
||||
inputs=[ParagraphInputConfig(output_variable_name="name")],
|
||||
user_actions=[UserActionConfig(id="approve", title="Approve")],
|
||||
)
|
||||
config = {"id": "human", "data": node_data.model_dump()}
|
||||
|
||||
|
||||
@ -6,15 +6,26 @@ from core.workflow.node_runtime import DifyHumanInputNodeRuntime
|
||||
from core.workflow.system_variables import default_system_variables
|
||||
from graphon.entities import GraphInitParams
|
||||
from graphon.enums import BuiltinNodeTypes
|
||||
from graphon.file import FileTransferMethod, FileType
|
||||
from graphon.graph_events import (
|
||||
NodeRunHumanInputFormFilledEvent,
|
||||
NodeRunHumanInputFormTimeoutEvent,
|
||||
NodeRunStartedEvent,
|
||||
)
|
||||
from graphon.nodes.human_input.entities import HumanInputNodeData
|
||||
from graphon.nodes.human_input.entities import (
|
||||
FileInputConfig,
|
||||
FileListInputConfig,
|
||||
HumanInputNodeData,
|
||||
ParagraphInputConfig,
|
||||
SelectInputConfig,
|
||||
StringListSource,
|
||||
UserActionConfig,
|
||||
)
|
||||
from graphon.nodes.human_input.enums import HumanInputFormStatus
|
||||
from graphon.nodes.human_input.human_input_node import HumanInputNode
|
||||
from graphon.runtime import GraphRuntimeState, VariablePool
|
||||
from graphon.variables.segments import ArrayFileSegment, FileSegment, StringSegment
|
||||
from graphon.variables.types import SegmentType
|
||||
from libs.datetime_utils import naive_utc_now
|
||||
|
||||
|
||||
@ -76,19 +87,15 @@ def _build_node(form_content: str = "Please enter your name:\n\n{{#$output.name#
|
||||
"title": "Human Input",
|
||||
"form_content": form_content,
|
||||
"inputs": [
|
||||
{
|
||||
"type": "text_input",
|
||||
"output_variable_name": "name",
|
||||
"default": {"type": "constant", "value": ""},
|
||||
}
|
||||
],
|
||||
"user_actions": [
|
||||
{
|
||||
"id": "Accept",
|
||||
"title": "Approve",
|
||||
"button_style": "default",
|
||||
}
|
||||
ParagraphInputConfig(output_variable_name="name").model_dump(mode="json"),
|
||||
SelectInputConfig(
|
||||
output_variable_name="decision",
|
||||
option_source=StringListSource(type="constant", value=["approve", "reject"]),
|
||||
).model_dump(mode="json"),
|
||||
FileInputConfig(output_variable_name="attachment").model_dump(mode="json"),
|
||||
FileListInputConfig(output_variable_name="attachments", number_limits=2).model_dump(mode="json"),
|
||||
],
|
||||
"user_actions": [UserActionConfig(id="Accept", title="Approve").model_dump(mode="json")],
|
||||
},
|
||||
}
|
||||
|
||||
@ -97,7 +104,28 @@ def _build_node(form_content: str = "Please enter your name:\n\n{{#$output.name#
|
||||
rendered_content=form_content,
|
||||
submitted=True,
|
||||
selected_action_id="Accept",
|
||||
submitted_data={"name": "Alice"},
|
||||
submitted_data={
|
||||
"name": "Alice",
|
||||
"decision": "approve",
|
||||
"attachment": {
|
||||
"type": "document",
|
||||
"transfer_method": "remote_url",
|
||||
"remote_url": "https://example.com/resume.pdf",
|
||||
"filename": "resume.pdf",
|
||||
"extension": ".pdf",
|
||||
"mime_type": "application/pdf",
|
||||
},
|
||||
"attachments": [
|
||||
{
|
||||
"type": "image",
|
||||
"transfer_method": "remote_url",
|
||||
"remote_url": "https://example.com/a.png",
|
||||
"filename": "a.png",
|
||||
"extension": ".png",
|
||||
"mime_type": "image/png",
|
||||
}
|
||||
],
|
||||
},
|
||||
status=HumanInputFormStatus.SUBMITTED,
|
||||
expiration_time=naive_utc_now() + datetime.timedelta(days=1),
|
||||
)
|
||||
@ -138,20 +166,8 @@ def _build_timeout_node() -> HumanInputNode:
|
||||
"data": {
|
||||
"title": "Human Input",
|
||||
"form_content": "Please enter your name:\n\n{{#$output.name#}}",
|
||||
"inputs": [
|
||||
{
|
||||
"type": "text_input",
|
||||
"output_variable_name": "name",
|
||||
"default": {"type": "constant", "value": ""},
|
||||
}
|
||||
],
|
||||
"user_actions": [
|
||||
{
|
||||
"id": "Accept",
|
||||
"title": "Approve",
|
||||
"button_style": "default",
|
||||
}
|
||||
],
|
||||
"inputs": [ParagraphInputConfig(output_variable_name="name").model_dump(mode="json")],
|
||||
"user_actions": [UserActionConfig(id="Accept", title="Approve").model_dump(mode="json")],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ from dataclasses import dataclass, field
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any
|
||||
|
||||
from graphon.nodes.human_input.entities import FormInput
|
||||
from graphon.nodes.human_input.entities import FormInputConfig
|
||||
from graphon.nodes.human_input.enums import TimeoutUnit
|
||||
from libs.datetime_utils import naive_utc_now
|
||||
|
||||
@ -45,7 +45,7 @@ class HumanInputForm:
|
||||
tenant_id: str
|
||||
app_id: str | None
|
||||
form_content: str
|
||||
inputs: list[FormInput]
|
||||
inputs: list[FormInputConfig]
|
||||
user_actions: list[dict[str, Any]]
|
||||
timeout: int
|
||||
timeout_unit: TimeoutUnit
|
||||
@ -88,7 +88,7 @@ class HumanInputForm:
|
||||
def to_response_dict(self, *, include_site_info: bool) -> dict[str, Any]:
|
||||
inputs_response = [
|
||||
{
|
||||
"type": form_input.type.name.lower().replace("_", "-"),
|
||||
"type": form_input.type.value,
|
||||
"output_variable_name": form_input.output_variable_name,
|
||||
}
|
||||
for form_input in self.inputs
|
||||
|
||||
@ -7,11 +7,10 @@ from datetime import timedelta
|
||||
import pytest
|
||||
|
||||
from graphon.nodes.human_input.entities import (
|
||||
FormInput,
|
||||
UserAction,
|
||||
ParagraphInputConfig,
|
||||
UserActionConfig,
|
||||
)
|
||||
from graphon.nodes.human_input.enums import (
|
||||
FormInputType,
|
||||
TimeoutUnit,
|
||||
)
|
||||
from libs.datetime_utils import naive_utc_now
|
||||
@ -50,8 +49,8 @@ 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", default=None)],
|
||||
"user_actions": [UserAction(id="submit", title="Submit")],
|
||||
"inputs": [ParagraphInputConfig(output_variable_name="input")],
|
||||
"user_actions": [UserActionConfig(id="submit", title="Submit")],
|
||||
"timeout": 1,
|
||||
"timeout_unit": TimeoutUnit.HOUR,
|
||||
"form_token": "token-xyz",
|
||||
@ -304,8 +303,8 @@ class TestFormValidation:
|
||||
"tenant_id": "tenant-abc",
|
||||
"app_id": "app-def",
|
||||
"form_content": "Test form",
|
||||
"inputs": [FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="required_input", default=None)],
|
||||
"user_actions": [UserAction(id="submit", title="Submit")],
|
||||
"inputs": [ParagraphInputConfig(output_variable_name="required_input")],
|
||||
"user_actions": [UserActionConfig(id="submit", title="Submit")],
|
||||
"timeout": 1,
|
||||
"timeout_unit": TimeoutUnit.HOUR,
|
||||
}
|
||||
|
||||
@ -7,11 +7,10 @@ from datetime import datetime, timedelta
|
||||
import pytest
|
||||
|
||||
from graphon.nodes.human_input.entities import (
|
||||
FormInput,
|
||||
UserAction,
|
||||
ParagraphInputConfig,
|
||||
UserActionConfig,
|
||||
)
|
||||
from graphon.nodes.human_input.enums import (
|
||||
FormInputType,
|
||||
TimeoutUnit,
|
||||
)
|
||||
from libs.datetime_utils import naive_utc_now
|
||||
@ -32,8 +31,8 @@ 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", default=None)],
|
||||
"user_actions": [UserAction(id="submit", title="Submit")],
|
||||
"inputs": [ParagraphInputConfig(output_variable_name="input")],
|
||||
"user_actions": [UserActionConfig(id="submit", title="Submit")],
|
||||
"timeout": 2,
|
||||
"timeout_unit": TimeoutUnit.HOUR,
|
||||
"form_token": "token-xyz",
|
||||
@ -132,7 +131,7 @@ class TestHumanInputForm:
|
||||
assert "site" not in response
|
||||
assert response["form_content"] == "# Test Form\n\nInput: {{#$output.input#}}"
|
||||
assert len(response["inputs"]) == 1
|
||||
assert response["inputs"][0]["type"] == "text-input"
|
||||
assert response["inputs"][0]["type"] == "paragraph"
|
||||
assert response["inputs"][0]["output_variable_name"] == "input"
|
||||
|
||||
def test_form_to_response_dict_with_site_info(self, sample_form_data):
|
||||
|
||||
@ -9,12 +9,17 @@ from core.repositories.human_input_repository import (
|
||||
HumanInputFormRecord,
|
||||
HumanInputFormSubmissionRepository,
|
||||
)
|
||||
from graphon.file import File, FileTransferMethod, FileType
|
||||
from graphon.nodes.human_input.entities import (
|
||||
FileInputConfig,
|
||||
FileListInputConfig,
|
||||
FormDefinition,
|
||||
FormInput,
|
||||
UserAction,
|
||||
ParagraphInputConfig,
|
||||
SelectInputConfig,
|
||||
StringListSource,
|
||||
UserActionConfig,
|
||||
)
|
||||
from graphon.nodes.human_input.enums import FormInputType, HumanInputFormKind, HumanInputFormStatus
|
||||
from graphon.nodes.human_input.enums import HumanInputFormKind, HumanInputFormStatus, ValueSourceType
|
||||
from libs.datetime_utils import naive_utc_now
|
||||
from models.human_input import RecipientType
|
||||
from services.human_input_service import (
|
||||
@ -50,7 +55,7 @@ def sample_form_record():
|
||||
definition=FormDefinition(
|
||||
form_content="hello",
|
||||
inputs=[],
|
||||
user_actions=[UserAction(id="submit", title="Submit")],
|
||||
user_actions=[UserActionConfig(id="submit", title="Submit")],
|
||||
rendered_content="<p>hello</p>",
|
||||
expiration_time=naive_utc_now() + timedelta(hours=1),
|
||||
),
|
||||
@ -273,7 +278,7 @@ def test_submit_form_by_token_missing_inputs(sample_form_record, mock_session_fa
|
||||
|
||||
definition_with_input = FormDefinition(
|
||||
form_content="hello",
|
||||
inputs=[FormInput(type=FormInputType.TEXT_INPUT, output_variable_name="content")],
|
||||
inputs=[ParagraphInputConfig(output_variable_name="content")],
|
||||
user_actions=sample_form_record.definition.user_actions,
|
||||
rendered_content="<p>hello</p>",
|
||||
expiration_time=sample_form_record.expiration_time,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user