Skip to content

Commit

Permalink
render state table.
Browse files Browse the repository at this point in the history
  • Loading branch information
apotonick committed Feb 17, 2024
1 parent ca6a2d0 commit 03f0e59
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 178 deletions.
1 change: 1 addition & 0 deletions lib/trailblazer/workflow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ module Workflow
require "trailblazer/workflow/test/plan"

require "trailblazer/workflow/discovery"
require "trailblazer/workflow/discovery/present"
6 changes: 3 additions & 3 deletions lib/trailblazer/workflow/collaboration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def to_a
# DISCUSS: is lane_positions same as Configuration?
class Positions
def initialize(positions)
@positions = positions
@positions = positions.sort { |a, b| a.activity.object_id <=> b.activity.object_id } # TODO: allow other orders?

@activity_to_task = positions.collect { |position| [position.activity, position.task] }.to_h
freeze
Expand Down Expand Up @@ -69,7 +69,7 @@ def collect(&block)
.collect(&block)
end

def ==(b)
def ==(b) # DISCUSS: needed?
eql?(b)
end

Expand All @@ -78,7 +78,7 @@ def eql?(b)
end

def hash
@positions.collect { |position| position.hash }.sort.join("").to_i
@positions.flat_map { |position| position.to_a }.hash
end
end

Expand Down
29 changes: 14 additions & 15 deletions lib/trailblazer/workflow/discovery.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def call(collaboration, start_position:, run_multiple_times: {}, initial_lane_po

original_lanes = collaboration.to_h[:lanes] # this dictates the order within created Positions.

collaboration, message_flow, start_position, initial_lane_positions, original_activity_2_stub_activity, original_task_2_stub_task = stub_tasks_for(collaboration, message_flow: message_flow, start_position: start_position, initial_lane_positions: initial_lane_positions)
collaboration, message_flow, start_position, initial_lane_positions, activity_2_stub, original_task_2_stub_task = stub_tasks_for(collaboration, message_flow: message_flow, start_position: start_position, initial_lane_positions: initial_lane_positions)

# pp collaboration.to_h[:lanes][:ui].to_h
# raise
Expand Down Expand Up @@ -67,7 +67,7 @@ def call(collaboration, start_position:, run_multiple_times: {}, initial_lane_po

discovered_state = discovered_state.merge(
stubbed_positions_before: [lane_positions, start_position],
positions_before: [unstub_positions(original_activity_2_stub_activity, original_task_2_stub_task, lane_positions, lanes: original_lanes), *unstub_positions(original_activity_2_stub_activity, original_task_2_stub_task, [start_position], lanes: Hash.new(0))]
positions_before: [unstub_positions(activity_2_stub, original_task_2_stub_task, lane_positions, lanes: original_lanes), *unstub_positions(activity_2_stub, original_task_2_stub_task, [start_position], lanes: Hash.new(0))]
)

discovered_state = discovered_state.merge(ctx_before: [ctx.inspect])
Expand Down Expand Up @@ -95,7 +95,7 @@ def call(collaboration, start_position:, run_multiple_times: {}, initial_lane_po
suspend_configuration = configuration
discovered_state = discovered_state.merge(
stubbed_suspend_configuration: suspend_configuration,
suspend_configuration: unstub_configuration(original_activity_2_stub_activity, configuration, lanes: original_lanes)
suspend_configuration: unstub_configuration(activity_2_stub, configuration, lanes: original_lanes)
)

# figure out possible next resumes/catchs:
Expand Down Expand Up @@ -178,47 +178,46 @@ def stub_tasks_for(collaboration, ignore_class: Trailblazer::Activity::End, mess

lane = Activity.new(Activity::Schema.new(new_circuit, activity.to_h[:outputs], new_nodes, activity.to_h[:config])) # FIXME: breaking taskWrap here (which is no problem, actually).

# [lane_id, lane, replaced_tasks]
[[lane_id, lane], replaced_tasks]
end

# DISCUSS: interestingly, we don't need this map as all stubbed tasks are user tasks, and positions always reference suspends or catch events, which arent' stubbed.
original_task_2_stub_task = collected.inject({}) { |memo, (_, replaced_tasks)| memo.merge(replaced_tasks) }

stubbed_lanes = collected.collect { |lane, _| lane }.to_h

original_activity_2_stub_activity = collaboration.to_h[:lanes].collect { |lane_id, activity| [activity, stubbed_lanes[lane_id]] }.to_h
activity_2_stub = collaboration.to_h[:lanes].collect { |lane_id, activity| [activity, stubbed_lanes[lane_id]] }.to_h

new_message_flow = message_flow.collect { |throw_evt, (activity, catch_evt)| [throw_evt, [original_activity_2_stub_activity[activity], catch_evt]] }.to_h
new_message_flow = message_flow.collect { |throw_evt, (activity, catch_evt)| [throw_evt, [activity_2_stub[activity], catch_evt]] }.to_h

new_start_position = Collaboration::Position.new(original_activity_2_stub_activity.fetch(start_position.activity), start_position.task)
new_start_position = Collaboration::Position.new(activity_2_stub.fetch(start_position.activity), start_position.task)

new_initial_lane_positions = initial_lane_positions.collect do |position|
# TODO: make lane_positions {Position} instances, too.
Collaboration::Position.new(original_activity_2_stub_activity[position[0]], position[1])
Collaboration::Position.new(activity_2_stub[position[0]], position[1])
end

new_initial_lane_positions = Collaboration::Positions.new(new_initial_lane_positions)

return Collaboration::Schema.new(lanes: stubbed_lanes, message_flow: new_message_flow), new_message_flow, new_start_position, new_initial_lane_positions, original_activity_2_stub_activity, original_task_2_stub_task
return Collaboration::Schema.new(lanes: stubbed_lanes, message_flow: new_message_flow), new_message_flow, new_start_position, new_initial_lane_positions, activity_2_stub, original_task_2_stub_task
end

# Get the original lane activity and tasks for a {Positions} set from the stubbed ones.
def unstub_positions(original_activity_2_stub_activity, original_task_2_stub_task, positions, lanes: {})
def unstub_positions(activity_2_stub, original_task_2_stub_task, positions, lanes: {})
real_positions = positions.to_a.collect do |position|
Collaboration::Position.new(
original_activity_2_stub_activity.invert.fetch(position.activity),
activity_2_stub.invert.fetch(position.activity),
position.task # since the task will always be a suspend, a resume or terminus, we can safely use the stubbed one, which is identical to the original.
)
end.sort { |a, b| lanes.values.index(a.activity) <=> lanes.values.index(b.activity) }

Collaboration::Positions.new(real_positions)
end

def unstub_configuration(original_activity_2_stub_activity, configuration, lanes:)
def unstub_configuration(activity_2_stub, configuration, lanes:)
real_lane_positions = unstub_positions(activity_2_stub, nil, configuration.lane_positions, lanes: lanes)

real_lane_positions = unstub_positions(original_activity_2_stub_activity, nil, configuration.lane_positions, lanes: lanes)

real_last_lane = original_activity_2_stub_activity[configuration.last_lane]
real_last_lane = activity_2_stub[configuration.last_lane]

Collaboration::Configuration.new(
**configuration.to_h,
Expand Down
116 changes: 116 additions & 0 deletions lib/trailblazer/workflow/discovery/present.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
module Trailblazer
module Workflow
module Discovery
# Rendering-specific code using {Discovery:states}.
module Present
module_function

# Find the next connected task, usually outgoing from a catch event.
def label_for_next_task(activity, catch_event)
task_after_catch = activity.to_h[:circuit].to_h[:map][catch_event][Trailblazer::Activity::Right]

Trailblazer::Activity::Introspect.Nodes(activity, task: task_after_catch).data[:label] || task_after_catch
end


def readable_name_for_catch_event(activity, catch_event, lanes_cfg: {})
envelope_icon = "(✉)➔" # TODO: implement {envelope_icon} flag.
envelope_icon = "▶"

lane_options = lane_options_for(activity, catch_event, lanes_cfg: lanes_cfg)
lane_name = lane_options[:label]
lane_label = lane_options[:icon] #if lane_icons.key?(lane_name) # TODO: handle default!

event_label = label_for_next_task(activity, catch_event)

"#{lane_label} #{envelope_icon}#{event_label}"
end

# Compute real catch events from the ID for a particular resume.
def resumes_from_suspend(activity, suspend)
suspend.to_h["resumes"].collect do |catch_event_id|
_catch_event = Trailblazer::Activity::Introspect.Nodes(activity, id: catch_event_id).task
end
end

def lane_options_for(activity, task, lanes_cfg:)
lanes_cfg.values.find { |options| options[:activity] == activity } or raise
end

# Each row represents a configuration of suspends aka "state".
# The state knows its possible resume events.
# does the state know which state fields belong to it?
#
# TODO: move that to separate module {StateTable.call}.
def render_cli_state_table(discovered_states, lanes_cfg:)
# raise discovery_state_table.inspect
start_position_to_catch = {}

# Key by lane_positions, which represent a state.
# State (lane_positions) => [events (start position)]
states = {}

# Collect the invoked start positions per Positions configuration.
# This implies the possible "catch events" per configuration.
discovered_states.each do |row|
positions_before, start_position = row[:positions_before]

# raise positions_before.inspect
# puts positions_before.to_a.collect { |p|
# # puts "@@@@@ #{p.inspect}"
# next if p.task.to_h["resumes"].nil?
# resumes_from_suspend(*p).collect { |catch_event| readable_name_for_catch_event(p.activity, catch_event, lanes_cfg: lanes_cfg) }

# }.inspect

events = states[positions_before]
events = [] if events.nil?

events << start_position

states[positions_before] = events
end

# render
cli_rows = states.flat_map do |configuration, catch_events|
suggested_state_name = suggested_state_name_for(catch_events)

suggested_state_name = "⛊ #{suggested_state_name}"
.inspect


# triggerable_events = events
# .collect { |event_position| readable_name_for_catch_event(event_position, lanes_cfg: lanes_cfg).inspect }
# .uniq
# .join(", ")


Hash[
"state name",
suggested_state_name,

# "triggerable events",
# triggerable_events
]
end

Hirb::Helpers::Table.render(cli_rows, fields: [
"state name",
"triggerable events",
# *lane_ids,
],
max_width: 186,
) # 186 for laptop 13"
end

# TODO: move to StateTable
def suggested_state_name_for(catch_events)
catch_events
.collect { |event_position| label_for_next_task(*event_position.to_a) }
.uniq
.join("/")
end
end
end
end
end
70 changes: 0 additions & 70 deletions lib/trailblazer/workflow/state/discovery.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,73 +75,9 @@ def self.generate_state_table(discovery_states, lanes:)
state_table
end

# Each row represents a configuration of suspends aka "state".
# The state knows its possible resume events.
# does the state know which state fields belong to it?
def self.render_cli_state_table(discovery_state_table)
start_position_to_catch = {}

# Key by lane_positions, which represent a state.
# State (lane_positions) => [events (start position)]
states = {}

discovery_state_table.each do |row|
configuration = row[:lane_positions]

events = states[configuration]
events = [] if events.nil?

events << row[:start_position]

states[configuration] = events
end


# render
cli_rows = states.flat_map do |configuration, events|
suggested_state_name = events
.collect { |event| event[:comment][1] }
.uniq
.join("/")

suggested_state_name = "> #{suggested_state_name}"
.inspect


triggerable_events = events
.collect { |event| readable_name_for_catch_event(event).inspect }
.uniq
.join(", ")


Hash[
"state name",
suggested_state_name,

"triggerable events",
triggerable_events
]
end

Hirb::Helpers::Table.render(cli_rows, fields: [
"state name",
"triggerable events",
# *lane_ids,
],
max_width: 186,
) # 186 for laptop 13"
end

def self.readable_name_for_catch_event(position, envelope_icon: false, lane_icons: {})
envelope_icon = "(✉)➔" # TODO: implement {envelope_icon} flag.
envelope_icon = "▶"

lane_name = position[:tuple][0]
lane_label = "#{lane_name}:"
lane_label = lane_icons[lane_name] if lane_icons.key?(lane_name)

"#{lane_label} #{envelope_icon}#{position[:comment][1]}"
end

def self.readable_name_for_resume_event(position, tuple: false, lane_icons: {})
resume_labels = position[:comment][1]
Expand Down Expand Up @@ -226,12 +162,6 @@ def self.render_cli_event_table(discovery_state_table, render_ids: false, hide_l
) # 186 for laptop 13"
end

# Find the next connected task, usually outgoing from a catch event.
def self.find_next_task_label(activity, catch_event)
task_after_catch = activity.to_h[:circuit].to_h[:map][catch_event][Trailblazer::Activity::Right]
Trailblazer::Activity::Introspect.Nodes(activity, task: task_after_catch).data[:label] || task_after_catch
end

def self.serialize_comment(event_name)
["before", event_name]
end
Expand Down
Loading

0 comments on commit 03f0e59

Please sign in to comment.