Skip to content

Commit e769c27

Browse files
authored
fix baserow#4147 - iterator node can be placed after itself (baserow#4151)
* fix baserow#4147 - iterator node can be placed after itself * Make the formula error log less verbose
1 parent 7e8b9ed commit e769c27

File tree

7 files changed

+98
-7
lines changed

7 files changed

+98
-7
lines changed

backend/src/baserow/contrib/automation/nodes/models.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,18 @@ def get_previous_service_outputs(self):
121121

122122
return {node.service_id: str(out) for [node, _, out] in previous_positions}
123123

124+
def get_parent_nodes(self):
125+
"""
126+
Returns the ancestors of this node which are the container nodes that contain
127+
the current node instance.
128+
"""
129+
130+
return [
131+
position[0]
132+
for position in self.workflow.get_graph().get_previous_positions(self)
133+
if position[1] == "child"
134+
]
135+
124136
def get_next_nodes(
125137
self, output_uid: str | None = None
126138
) -> Iterable["AutomationNode"]:

backend/src/baserow/contrib/automation/nodes/node_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def before_move(
103103
Check the container node is not moved inside it self.
104104
"""
105105

106-
if node in reference_node.get_previous_nodes():
106+
if node in reference_node.get_parent_nodes():
107107
raise AutomationNodeNotMovable(
108108
"A container node cannot be moved inside itself"
109109
)

backend/src/baserow/contrib/automation/workflows/graph_handler.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,7 @@ def _get_all_next_nodes(self, node: AutomationNode):
232232

233233
node_info = self.get_info(node)
234234

235-
return [
236-
x for sublist in node_info.get("next", {}).values() for x in sublist
237-
] + node_info.get("children", [])
235+
return [x for sublist in node_info.get("next", {}).values() for x in sublist]
238236

239237
def get_next_nodes(
240238
self, node: AutomationNode, output: str | None = None

backend/tests/baserow/contrib/automation/nodes/test_node_service.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,85 @@ def test_move_node_outside_of_container(data_fixture: Fixtures):
635635
assert move_result.previous_output == ""
636636

637637

638+
@pytest.mark.django_db
639+
def test_move_container_after_itself(data_fixture: Fixtures):
640+
user = data_fixture.create_user()
641+
workflow = data_fixture.create_automation_workflow(user)
642+
action1 = data_fixture.create_automation_node(workflow=workflow, label="action1")
643+
644+
iterator = data_fixture.create_core_iterator_action_node(workflow=workflow)
645+
action2 = data_fixture.create_automation_node(workflow=workflow, label="action2")
646+
action3 = data_fixture.create_automation_node(workflow=workflow, label="action3")
647+
action4 = data_fixture.create_automation_node(workflow=workflow, label="action4")
648+
649+
# move `action3` to be the first child of iterator
650+
move_result = AutomationNodeService().move_node(
651+
user, iterator.id, reference_node_id=action4.id, position="south", output=""
652+
)
653+
654+
workflow.assert_reference(
655+
{
656+
"0": "rows_created",
657+
"rows_created": {"next": {"": ["action1"]}},
658+
"action1": {"next": {"": ["action2"]}},
659+
"action2": {"next": {"": ["action3"]}},
660+
"action3": {"next": {"": ["action4"]}},
661+
"action4": {"next": {"": ["iterator"]}},
662+
"iterator": {},
663+
}
664+
)
665+
666+
667+
@pytest.mark.django_db
668+
def test_move_container_inside_itself_should_fail(data_fixture: Fixtures):
669+
user = data_fixture.create_user()
670+
workflow = data_fixture.create_automation_workflow(user)
671+
action1 = data_fixture.create_automation_node(workflow=workflow, label="action1")
672+
673+
iterator = data_fixture.create_core_iterator_action_node(workflow=workflow)
674+
iterator2 = data_fixture.create_core_iterator_action_node(
675+
workflow=workflow, reference_node=iterator, position="child"
676+
)
677+
action2 = data_fixture.create_automation_node(
678+
workflow=workflow, label="action2", reference_node=iterator2, position="child"
679+
)
680+
action3 = data_fixture.create_automation_node(
681+
workflow=workflow, label="action3", reference_node=action2, position="south"
682+
)
683+
action4 = data_fixture.create_automation_node(
684+
workflow=workflow, label="action4", reference_node=iterator2, position="south"
685+
)
686+
687+
with pytest.raises(AutomationNodeNotMovable) as exc:
688+
AutomationNodeService().move_node(
689+
user, iterator.id, reference_node_id=action3.id, position="south", output=""
690+
)
691+
692+
assert exc.value.args[0] == "A container node cannot be moved inside itself"
693+
694+
with pytest.raises(AutomationNodeNotMovable) as exc:
695+
AutomationNodeService().move_node(
696+
user,
697+
iterator.id,
698+
reference_node_id=iterator2.id,
699+
position="south",
700+
output="",
701+
)
702+
703+
assert exc.value.args[0] == "A container node cannot be moved inside itself"
704+
705+
with pytest.raises(AutomationNodeNotMovable) as exc:
706+
AutomationNodeService().move_node(
707+
user,
708+
iterator.id,
709+
reference_node_id=iterator2.id,
710+
position="child",
711+
output="",
712+
)
713+
714+
assert exc.value.args[0] == "A container node cannot be moved inside itself"
715+
716+
638717
@pytest.mark.django_db
639718
def test_move_node_invalid_reference_node(data_fixture: Fixtures):
640719
user = data_fixture.create_user()

backend/tests/baserow/contrib/automation/workflows/test_graph_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ def test_graph_handler_insert_first_node(
511511
{
512512
"0": 1,
513513
"1": {"next": {"": [2]}},
514-
"2": {"next": {"": [4, 7]}},
514+
"2": {"next": {"": [4]}}, # yes we lose the child for now
515515
"4": {"next": {"": [5], "randomUid": [9]}},
516516
"7": {"next": {"": [8]}},
517517
"8": {"children": []},

web-frontend/modules/builder/elementTypes.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,9 @@ export class ElementType extends Registerable {
804804
page,
805805
element,
806806
allowSameElement = true,
807-
recordIndexPath,
807+
// The default value is used when we try to resolve the name in element menu for
808+
// instance.
809+
recordIndexPath = [0],
808810
} = applicationContext
809811

810812
const collectionAncestry = this.getCollectionAncestry({

web-frontend/modules/core/formula/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const resolveFormula = (
2828
const tree = parseBaserowFormula(formulaCtx.formula)
2929
return new JavascriptExecutor(functions, RuntimeFormulaContext).visit(tree)
3030
} catch (err) {
31-
console.debug('Err in formula resolution', err)
31+
console.debug(`FORMULA DEBUG: ${err}`)
3232
return ''
3333
}
3434
}

0 commit comments

Comments
 (0)