From bf25c287a1dadbc1e32bf89cecd7d7a6ab5bd537 Mon Sep 17 00:00:00 2001 From: Nick Sutterer Date: Fri, 9 Feb 2024 13:19:38 +0100 Subject: [PATCH] start introducing Positions and Position. --- lib/trailblazer/workflow/collaboration.rb | 50 ++- lib/trailblazer/workflow/state/discovery.rb | 5 +- .../workflow/state/discovery/testing.rb | 8 +- lib/trailblazer/workflow/test/plan.rb | 2 + test/collaboration_test.rb | 37 +- test/discovery_testing_json.json | 376 +++++++++--------- 6 files changed, 266 insertions(+), 212 deletions(-) diff --git a/lib/trailblazer/workflow/collaboration.rb b/lib/trailblazer/workflow/collaboration.rb index 1167836..6baaea9 100644 --- a/lib/trailblazer/workflow/collaboration.rb +++ b/lib/trailblazer/workflow/collaboration.rb @@ -29,8 +29,50 @@ def to_h task: task } end + + def to_a + [ + activity, + task + ] + end + end + + # DISCUSS: is lane_positions same as Configuration? + class Positions + def initialize(positions) + @positions = positions + + @activity_to_task = positions.collect { |position| [position.activity, position.task] }.to_h + freeze + end + + def [](activity) # TODO: do that mapping in constructor. + @activity_to_task[activity] + end + + def replace(activity, task) + replaced_position = @positions.find { |position| position.activity == activity } + + new_positions = @positions - [replaced_position] + [Position.new(activity, task)] + + Positions.new(new_positions) + end + + def to_a + @positions + end + + # Iterate [activity, task] directly, without the {Position} instance. + def collect(&block) + @positions + .collect { |position| position.to_a } + .collect(&block) + end end + + # DISCUSS: rename to State or something better matching? # Keeps the collaboration lane positions after running, it's a "state" class Configuration < Struct.new(:lane_positions, :signal, :ctx, :flow_options, :last_lane, keyword_init: true) # DISCUSS: should we keep ctx/flow_options? @@ -119,13 +161,13 @@ def advance(collaboration, (ctx, flow), circuit_options, lane_positions:, start_ # {:activity} and {:task} are the targeted position. def validate_targeted_position(lane_positions, activity:, task:) # the *actual* receiver position, where we're currently. - actual_receiver_position = lane_positions[activity] # receiver should always be in a suspend task/event gateway. + actual_receiver_task = lane_positions[activity] # receiver should always be in a suspend task/event gateway. # puts "######### #{} | #{task} -# >>>>>>>>> #{actual_receiver_position}" +# >>>>>>>>> #{actual_receiver_task}" # puts - reachable_catch_events = actual_receiver_position.to_h["resumes"] + reachable_catch_events = actual_receiver_task.to_h["resumes"] .collect { |catch_id| Trailblazer::Activity::Introspect.Nodes(activity, id: catch_id).task } # if possible_catch_event_ids = @@ -138,7 +180,7 @@ def validate_targeted_position(lane_positions, activity:, task:) # @private # @param signal Workflow::Event::Suspend def advance_position(lane_positions, activity, suspend_event) - lane_positions.merge(activity => suspend_event) + lane_positions.replace(activity, suspend_event) end diff --git a/lib/trailblazer/workflow/state/discovery.rb b/lib/trailblazer/workflow/state/discovery.rb index f3ab830..0f5cdbb 100644 --- a/lib/trailblazer/workflow/state/discovery.rb +++ b/lib/trailblazer/workflow/state/discovery.rb @@ -54,7 +54,7 @@ def self.generate_state_table(discovery_states, lanes:) # catch_event = # Go through each lane. - lane_position_tuples = lane_positions.flat_map do |lane_position| + lane_position_tuples = lane_positions.to_a.collect do |lane_position| next if lane_position.nil? # FIXME: why do we have that? @@ -246,11 +246,10 @@ def self.generate_from(states) rows = states.collect do |state| lane_positions, start_position = state # DISCUSS: introduce a Discovery::State object? - # triggered_catch_event_id = Trailblazer::Activity::Introspect.Nodes(start_position.activity, task: start_position.task).id # Go through each lane. - row = lane_positions.flat_map do |activity, suspend| + row = lane_positions.collect do |activity, suspend| next if suspend.to_h["resumes"].nil? resumes = resumes_from_suspend(activity, suspend) diff --git a/lib/trailblazer/workflow/state/discovery/testing.rb b/lib/trailblazer/workflow/state/discovery/testing.rb index b49d720..90d2865 100644 --- a/lib/trailblazer/workflow/state/discovery/testing.rb +++ b/lib/trailblazer/workflow/state/discovery/testing.rb @@ -125,9 +125,13 @@ def self.format_start_positions_for(rows, column_name:, formatted_col_name:, lan columns_2_length = columns.collect { |lane_label, lengths| [lane_label, lengths.sort.last] }.to_h - # TODO: always same col order!!! rows = rows.collect do |row| - columns = row[column_name].collect do |lane_label, catch_label| + position_columns = Hash[row[column_name]] + + sorted_columns = lane_icons.keys.collect { |name, _| [name, position_columns[name]] } + + + columns = sorted_columns.collect do |lane_label, catch_label| col_length = columns_2_length[lane_label] lane_label = lane_icons[lane_label] diff --git a/lib/trailblazer/workflow/test/plan.rb b/lib/trailblazer/workflow/test/plan.rb index f4e70cd..862a0a9 100644 --- a/lib/trailblazer/workflow/test/plan.rb +++ b/lib/trailblazer/workflow/test/plan.rb @@ -23,6 +23,8 @@ def self.for(test_structure, input:) "Trailblazer::Workflow::State::Discovery.position_from_tuple(lanes, *#{row[:tuple].inspect})" end.join(", ")}] +lane_positions = Trailblazer::Workflow::Collaboration::Positions.new(lane_positions) + configuration, (ctx, flow) = Trailblazer::Workflow::Collaboration::Synchronous.advance( schema, [{seq: []}, {throw: []}], diff --git a/test/collaboration_test.rb b/test/collaboration_test.rb index c5c769c..6cfdc09 100644 --- a/test/collaboration_test.rb +++ b/test/collaboration_test.rb @@ -203,6 +203,8 @@ def decider(ctx, decision: true, **) extended_initial_lane_positions = initial_lane_positions.merge( approver_activity => approver_start_suspend ) + extended_initial_lane_positions = Trailblazer::Workflow::Collaboration::Positions.new(extended_initial_lane_positions.collect { |activity, task| Trailblazer::Workflow::Collaboration::Position.new(activity, task) }) + # State discovery: # The idea is that we collect suspend events and follow up on all their resumes (catch) events. @@ -382,6 +384,8 @@ def render_states(states, lanes:, additional_state_data:, task_map:) ], max_width: 186) # 186 for laptop 13" end + + render_states(states, lanes: ___lanes___ = {lane_activity => "lifecycle", lane_activity_ui => "UI", approver_activity => "approver"}, additional_state_data: additional_state_data, task_map: task_map) # raise "figure out how to build a generated state table" @@ -547,21 +551,21 @@ def render_states(states, lanes:, additional_state_data:, task_map:) %(+----------------------+--------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ | triggered catch | start_configuration_formatted | expected_lane_positions_formatted | +----------------------+--------------------------------------------------------------------------------+--------------------------------------------------------------------------------+ -| ☝ ▶Create form | ⛾ ▶Create ☝ ▶Create form ☑ ▶#" ], "comment": [ "before", [ - "Create" + "#" ] ] }, { "tuple": [ - "approver", - "#" + "UI", + "suspend-Gateway_14h0q7a" ], "comment": [ "before", [ - "#" + "Create" ] ] } @@ -115,25 +115,25 @@ }, { "tuple": [ - "UI", - "suspend-Gateway_14h0q7a" + "approver", + "#" ], "comment": [ "before", [ - "Create" + "#" ] ] }, { "tuple": [ - "approver", - "#" + "UI", + "suspend-Gateway_14h0q7a" ], "comment": [ "before", [ - "#" + "Create" ] ] } @@ -141,39 +141,39 @@ "expected_lane_positions": [ { "tuple": [ - "lifecycle", - "suspend-Gateway_0fnbg3r" + "approver", + "#" ], "comment": [ "before", [ - "Update", - "Notify approver" + "#" ] ] }, { "tuple": [ - "UI", - "suspend-Gateway_0kknfje" + "lifecycle", + "suspend-Gateway_0fnbg3r" ], "comment": [ "before", [ - "Update form", + "Update", "Notify approver" ] ] }, { "tuple": [ - "approver", - "#" + "UI", + "suspend-Gateway_0kknfje" ], "comment": [ "before", [ - "#" + "Update form", + "Notify approver" ] ] } @@ -207,25 +207,25 @@ }, { "tuple": [ - "UI", - "suspend-Gateway_14h0q7a" + "approver", + "#" ], "comment": [ "before", [ - "Create" + "#" ] ] }, { "tuple": [ - "approver", - "#" + "UI", + "suspend-Gateway_14h0q7a" ], "comment": [ "before", [ - "#" + "Create" ] ] } @@ -233,20 +233,20 @@ "expected_lane_positions": [ { "tuple": [ - "lifecycle", - "suspend-gw-to-catch-before-Activity_0wwfenp" + "approver", + "#" ], "comment": [ "before", [ - "Create" + "#" ] ] }, { "tuple": [ - "UI", - "suspend-Gateway_14h0q7a" + "lifecycle", + "suspend-gw-to-catch-before-Activity_0wwfenp" ], "comment": [ "before", @@ -257,13 +257,13 @@ }, { "tuple": [ - "approver", - "#" + "UI", + "suspend-Gateway_14h0q7a" ], "comment": [ "before", [ - "#" + "Create" ] ] } @@ -283,6 +283,18 @@ ] }, "start_configuration": [ + { + "tuple": [ + "approver", + "#" + ], + "comment": [ + "before", + [ + "#" + ] + ] + }, { "tuple": [ "lifecycle", @@ -308,7 +320,9 @@ "Notify approver" ] ] - }, + } + ], + "expected_lane_positions": [ { "tuple": [ "approver", @@ -320,9 +334,7 @@ "#" ] ] - } - ], - "expected_lane_positions": [ + }, { "tuple": [ "lifecycle", @@ -347,18 +359,6 @@ "Update" ] ] - }, - { - "tuple": [ - "approver", - "#" - ], - "comment": [ - "before", - [ - "#" - ] - ] } ], "expected_outcome": "success", @@ -376,6 +376,18 @@ ] }, "start_configuration": [ + { + "tuple": [ + "approver", + "#" + ], + "comment": [ + "before", + [ + "#" + ] + ] + }, { "tuple": [ "lifecycle", @@ -401,21 +413,19 @@ "Notify approver" ] ] - }, + } + ], + "expected_lane_positions": [ { "tuple": [ "approver", - "#" + "End.failure" ], "comment": [ - "before", - [ - "#" - ] + "terminus", + "failure" ] - } - ], - "expected_lane_positions": [ + }, { "tuple": [ "lifecycle", @@ -443,16 +453,6 @@ "Publish" ] ] - }, - { - "tuple": [ - "approver", - "End.failure" - ], - "comment": [ - "terminus", - "failure" - ] } ], "expected_outcome": "success", @@ -470,6 +470,18 @@ ] }, "start_configuration": [ + { + "tuple": [ + "approver", + "#" + ], + "comment": [ + "before", + [ + "#" + ] + ] + }, { "tuple": [ "lifecycle", @@ -494,7 +506,9 @@ "Update" ] ] - }, + } + ], + "expected_lane_positions": [ { "tuple": [ "approver", @@ -506,9 +520,7 @@ "#" ] ] - } - ], - "expected_lane_positions": [ + }, { "tuple": [ "lifecycle", @@ -534,18 +546,6 @@ "Notify approver" ] ] - }, - { - "tuple": [ - "approver", - "#" - ], - "comment": [ - "before", - [ - "#" - ] - ] } ], "expected_outcome": "success", @@ -563,6 +563,18 @@ ] }, "start_configuration": [ + { + "tuple": [ + "approver", + "#" + ], + "comment": [ + "before", + [ + "#" + ] + ] + }, { "tuple": [ "lifecycle", @@ -588,21 +600,19 @@ "Notify approver" ] ] - }, + } + ], + "expected_lane_positions": [ { "tuple": [ "approver", - "#" + "End.success" ], "comment": [ - "before", - [ - "#" - ] + "terminus", + "success" ] - } - ], - "expected_lane_positions": [ + }, { "tuple": [ "lifecycle", @@ -626,16 +636,6 @@ "Revise form" ] ] - }, - { - "tuple": [ - "approver", - "End.success" - ], - "comment": [ - "terminus", - "success" - ] } ], "expected_outcome": "failure", @@ -683,6 +683,16 @@ } ], "expected_lane_positions": [ + { + "tuple": [ + "approver", + "End.failure" + ], + "comment": [ + "terminus", + "failure" + ] + }, { "tuple": [ "lifecycle", @@ -709,16 +719,6 @@ "Cancel" ] ] - }, - { - "tuple": [ - "approver", - "End.failure" - ], - "comment": [ - "terminus", - "failure" - ] } ], "expected_outcome": "success", @@ -766,6 +766,16 @@ } ], "expected_lane_positions": [ + { + "tuple": [ + "approver", + "End.failure" + ], + "comment": [ + "terminus", + "failure" + ] + }, { "tuple": [ "lifecycle", @@ -789,16 +799,6 @@ "Archive" ] ] - }, - { - "tuple": [ - "approver", - "End.failure" - ], - "comment": [ - "terminus", - "failure" - ] } ], "expected_outcome": "success", @@ -816,6 +816,18 @@ ] }, "start_configuration": [ + { + "tuple": [ + "approver", + "#" + ], + "comment": [ + "before", + [ + "#" + ] + ] + }, { "tuple": [ "lifecycle", @@ -840,7 +852,9 @@ "Update" ] ] - }, + } + ], + "expected_lane_positions": [ { "tuple": [ "approver", @@ -852,9 +866,7 @@ "#" ] ] - } - ], - "expected_lane_positions": [ + }, { "tuple": [ "lifecycle", @@ -879,18 +891,6 @@ "Update" ] ] - }, - { - "tuple": [ - "approver", - "#" - ], - "comment": [ - "before", - [ - "#" - ] - ] } ], "expected_outcome": "failure", @@ -934,6 +934,16 @@ } ], "expected_lane_positions": [ + { + "tuple": [ + "approver", + "End.success" + ], + "comment": [ + "terminus", + "success" + ] + }, { "tuple": [ "lifecycle", @@ -957,16 +967,6 @@ "Revise" ] ] - }, - { - "tuple": [ - "approver", - "End.success" - ], - "comment": [ - "terminus", - "success" - ] } ], "expected_outcome": "success", @@ -1015,18 +1015,18 @@ "expected_lane_positions": [ { "tuple": [ - "lifecycle", - "Event_1p8873y" + "approver", + "End.failure" ], "comment": [ "terminus", - "success" + "failure" ] }, { "tuple": [ - "UI", - "Event_0h6yhq6" + "lifecycle", + "Event_1p8873y" ], "comment": [ "terminus", @@ -1035,12 +1035,12 @@ }, { "tuple": [ - "approver", - "End.failure" + "UI", + "Event_0h6yhq6" ], "comment": [ "terminus", - "failure" + "success" ] } ], @@ -1088,6 +1088,16 @@ } ], "expected_lane_positions": [ + { + "tuple": [ + "approver", + "End.failure" + ], + "comment": [ + "terminus", + "failure" + ] + }, { "tuple": [ "lifecycle", @@ -1115,16 +1125,6 @@ "Publish" ] ] - }, - { - "tuple": [ - "approver", - "End.failure" - ], - "comment": [ - "terminus", - "failure" - ] } ], "expected_outcome": "success", @@ -1170,18 +1170,18 @@ "expected_lane_positions": [ { "tuple": [ - "lifecycle", - "Event_1p8873y" + "approver", + "End.failure" ], "comment": [ "terminus", - "success" + "failure" ] }, { "tuple": [ - "UI", - "Event_0h6yhq6" + "lifecycle", + "Event_1p8873y" ], "comment": [ "terminus", @@ -1190,12 +1190,12 @@ }, { "tuple": [ - "approver", - "End.failure" + "UI", + "Event_0h6yhq6" ], "comment": [ "terminus", - "failure" + "success" ] } ], @@ -1240,6 +1240,16 @@ } ], "expected_lane_positions": [ + { + "tuple": [ + "approver", + "End.success" + ], + "comment": [ + "terminus", + "success" + ] + }, { "tuple": [ "lifecycle", @@ -1265,16 +1275,6 @@ "Notify approver" ] ] - }, - { - "tuple": [ - "approver", - "End.success" - ], - "comment": [ - "terminus", - "success" - ] } ], "expected_outcome": "success",