Skip to content

Commit

Permalink
fix(action_form): all fields should be returned during execute (#310)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbarreau authored Jan 28, 2025
1 parent 15377e8 commit 9c60c27
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ async def execute(self, request: ActionRequest) -> Union[FileResponse, Response]
# As forms are dynamic, we don't have any way to ensure that we're parsing the data correctly
# => better send invalid data to the getForm() customer handler than to the execute() one.
unsafe_data = ForestValueConverter.make_form_unsafe_data(raw_data)
fields = await request.collection.get_form(request.user, request.action_name, unsafe_data, filter_)

fields = await request.collection.get_form(
request.user, request.action_name, unsafe_data, filter_, {"include_hidden_fields": True}
)

fields = SchemaActionGenerator.extract_fields_and_layout(fields)[0]
# Now that we have the field list, we can parse the data again.
Expand Down
54 changes: 54 additions & 0 deletions src/agent_toolkit/tests/resources/actions/test_resources.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import copy
import importlib
import json
import sys
Expand Down Expand Up @@ -980,3 +981,56 @@ def execute(ctx, result_builder):
response = self.loop.run_until_complete(self.action_resource.execute(request))
self.assertEqual(response.headers["headerOne"], "valueOne")
self.assertEqual(response.headers["headerOne"], "valueOne")

def test_execute_should_get_all_form_fields_included_hidden(self):

self.decorated_collection_book.add_action(
"test_action_global_hidden_fields",
{
"scope": ActionsScope.GLOBAL,
"execute": lambda ctx, rb: rb.success(ctx.form_values.get("hidden_field")),
"form": [
{
"type": "String",
"label": "hidden_field",
"if_": lambda ctx: False,
}
],
},
)
body_params = copy.deepcopy(self.body_params)
body_params["data"]["attributes"]["values"] = {"hidden_field": "hidden_value"}
request = ActionRequest(
method=RequestMethod.POST,
action_name="test_action_global_hidden_fields",
collection=self.decorated_collection_book,
body=body_params,
query={
"timezone": "Europe/Paris",
"collection_name": "Book",
"action_name": 0,
"slug": "test_action_global_hidden_fields",
},
headers={},
user=self.mocked_caller,
client_ip="127.0.0.1",
)
with patch.object(
self.decorated_collection_book,
"get_form",
new_callable=AsyncMock,
wraps=self.decorated_collection_book.get_form,
) as spy_get_form:
response = self.loop.run_until_complete(self.action_resource.execute(request))
spy_get_form.assert_awaited_once_with(
request.user,
"test_action_global_hidden_fields",
{"hidden_field": "hidden_value"},
ANY,
{"include_hidden_fields": True},
)
self.assertEqual(response.status, 200)
self.assertEqual(
response.body,
'{"success": "hidden_value"}',
)
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@ async def get_form(
form_values = await self._build_form_values(context, form_fields, form_values)
context.form_values.update(form_values)
action_fields = await self._build_fields(
context, form_fields, form_values, meta.get("search_values", {}).get(meta.get("search_field"))
context,
form_fields,
form_values,
meta.get("search_values", {}).get(meta.get("search_field")),
meta.get("include_hidden_fields", False),
)

self._set_watch_changes_attr(action_fields, context)
Expand Down Expand Up @@ -215,10 +219,11 @@ async def _build_fields(
fields: List[DynamicFormElements],
form_values: RecordsDataAlias,
search_value: Optional[str] = None,
include_hidden_fields: bool = False,
) -> List[Union[ActionLayoutElement, ActionField]]:
action_fields: List[Union[ActionLayoutElement, ActionField]] = []
for field in fields:
if await field.if_(context):
if include_hidden_fields or await field.if_(context):
value = form_values if isinstance(field, DynamicLayoutElements) else form_values.get(field.id)
action_field = await field.to_action_field(context, value, search_value) # type:ignore
if action_field is not None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -819,3 +819,43 @@ def _search_fn(context, search_value):
}
],
)

def test_get_form_should_return_hidden_fields_when_asked(self):
if_fn = Mock(return_value=False)
test_action: ActionDict = {
"scope": ActionsScope.SINGLE,
"execute": lambda ctx, result_builder: result_builder.success("ok"),
"form": [
{
"label": "name",
"type": ActionFieldType.STRING,
"if_": if_fn,
},
],
}
self.product_collection.add_action("action_test", test_action)

result = self.loop.run_until_complete(
self.product_collection.get_form(
self.mocked_caller, "action_test", {"name": "name"}, None, {"include_hidden_fields": True}
)
)
self.assertEqual(
result,
[
{
"label": "name",
"id": "name",
"type": ActionFieldType.STRING,
"description": "",
"is_read_only": False,
"is_required": False,
"value": "name",
"default_value": None,
"collection_name": None,
"enum_values": None,
"watch_changes": False,
}
],
)
if_fn.assert_not_called()

0 comments on commit 9c60c27

Please sign in to comment.