flow_core 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +7 -0
- data/app/models/flow_core/arc.rb +8 -0
- data/app/models/flow_core/arc_guard.rb +27 -2
- data/app/models/flow_core/branch.rb +48 -0
- data/app/models/flow_core/instance.rb +10 -1
- data/app/models/flow_core/pipeline.rb +58 -0
- data/app/models/flow_core/place.rb +2 -1
- data/app/models/flow_core/step.rb +337 -0
- data/app/models/flow_core/steps/end.rb +32 -0
- data/app/models/flow_core/steps/exclusive_choice.rb +72 -0
- data/app/models/flow_core/steps/parallel_split.rb +42 -0
- data/app/models/flow_core/steps/redirection.rb +39 -0
- data/app/models/flow_core/steps/task.rb +25 -0
- data/app/models/flow_core/task.rb +21 -8
- data/app/models/flow_core/transition.rb +44 -6
- data/app/models/flow_core/transition_callback.rb +19 -2
- data/app/models/flow_core/transition_trigger.rb +19 -2
- data/app/models/flow_core/workflow.rb +11 -4
- data/db/migrate/{20200130200532_create_flow_core_tables.rb → 20200130200532_create_workflow_tables.rb} +32 -29
- data/db/migrate/20200130200533_create_pipeline_tables.rb +64 -0
- data/lib/flow_core.rb +3 -4
- data/lib/flow_core/definition/net.rb +6 -4
- data/lib/flow_core/definition/transition.rb +37 -25
- data/lib/flow_core/engine.rb +5 -0
- data/lib/flow_core/locale/en.yml +9 -4
- data/lib/flow_core/task_executable.rb +4 -0
- data/lib/flow_core/version.rb +1 -1
- data/lib/flow_core/workflow_callbacks.rb +2 -0
- metadata +41 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 743fbfab50000cf6b47c17fe0d90d962faad47fb8eeb0cb44df1e777b56fff0d
|
4
|
+
data.tar.gz: 67d9e0a9f7e7f47d0d958116f4e10d5e885e80ce6b929aa49c49ae844cdc2c18
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7b941b64b50e8d083832c3faf1c22f729473fbf1ac7ed1a0ba67f0831bb9d1a7078f95c008f18ae77138358be376124c47c094fb97d6b41ecf18e99f78a0c68
|
7
|
+
data.tar.gz: 35f944cd17e0b9d07afc0903198ffa9cc43f7d74858fa778112ae4a7c69a0de6a59e21354ab9c4460e2eafb8800f790aa12270dce06ffc85e1bfcafd643e5fca
|
data/README.md
CHANGED
data/app/models/flow_core/arc.rb
CHANGED
@@ -19,6 +19,14 @@ module FlowCore
|
|
19
19
|
uniqueness: {
|
20
20
|
scope: %i[workflow transition direction]
|
21
21
|
}
|
22
|
+
validates :fallback_arc,
|
23
|
+
uniqueness: {
|
24
|
+
scope: %i[workflow transition direction]
|
25
|
+
}, if: :fallback_arc?
|
26
|
+
|
27
|
+
before_validation on: :create do
|
28
|
+
self.workflow ||= place&.workflow || transition&.workflow
|
29
|
+
end
|
22
30
|
|
23
31
|
before_destroy :prevent_destroy
|
24
32
|
after_create :reset_workflow_verification
|
@@ -4,13 +4,38 @@ module FlowCore
|
|
4
4
|
class ArcGuard < FlowCore::ApplicationRecord
|
5
5
|
self.table_name = "flow_core_arc_guards"
|
6
6
|
|
7
|
-
belongs_to :workflow, class_name: "FlowCore::Workflow"
|
8
|
-
belongs_to :arc, class_name: "FlowCore::Arc"
|
7
|
+
belongs_to :workflow, class_name: "FlowCore::Workflow", optional: true
|
8
|
+
belongs_to :arc, class_name: "FlowCore::Arc", optional: true
|
9
9
|
|
10
10
|
has_one :transition, through: :arc, class_name: "FlowCore::Transition"
|
11
11
|
|
12
|
+
belongs_to :pipeline, class_name: "FlowCore::Pipeline", optional: true
|
13
|
+
belongs_to :branch, class_name: "FlowCore::Branch", optional: true
|
14
|
+
|
15
|
+
validates :arc,
|
16
|
+
presence: true,
|
17
|
+
if: ->(r) { r.workflow }
|
18
|
+
validates :branch,
|
19
|
+
presence: true,
|
20
|
+
if: ->(r) { r.pipeline }
|
21
|
+
validates :workflow,
|
22
|
+
presence: true,
|
23
|
+
if: ->(r) { !r.pipeline }
|
24
|
+
validates :pipeline,
|
25
|
+
presence: true,
|
26
|
+
if: ->(r) { !r.workflow }
|
27
|
+
|
12
28
|
before_validation do
|
13
29
|
self.workflow ||= arc&.workflow
|
30
|
+
self.pipeline ||= branch&.pipeline
|
31
|
+
end
|
32
|
+
|
33
|
+
def configurable?
|
34
|
+
false
|
35
|
+
end
|
36
|
+
|
37
|
+
def type_key
|
38
|
+
self.class.to_s.split("::").last.underscore
|
14
39
|
end
|
15
40
|
|
16
41
|
include FlowCore::ArcGuardable
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlowCore
|
4
|
+
class Branch < FlowCore::ApplicationRecord
|
5
|
+
self.table_name = "flow_core_branches"
|
6
|
+
|
7
|
+
belongs_to :pipeline, class_name: "FlowCore::Pipeline"
|
8
|
+
belongs_to :step, class_name: "FlowCore::Step"
|
9
|
+
|
10
|
+
has_many :arc_guards, class_name: "FlowCore::ArcGuard", dependent: :destroy
|
11
|
+
|
12
|
+
has_many :steps, -> { order(position: :asc) },
|
13
|
+
class_name: "FlowCore::Step", inverse_of: :branch,
|
14
|
+
dependent: :destroy
|
15
|
+
|
16
|
+
validates :name,
|
17
|
+
presence: true
|
18
|
+
|
19
|
+
validates :fallback_branch,
|
20
|
+
uniqueness: {
|
21
|
+
scope: %i[step_id]
|
22
|
+
}, if: :fallback_branch?
|
23
|
+
|
24
|
+
before_validation do
|
25
|
+
self.pipeline ||= step.pipeline
|
26
|
+
end
|
27
|
+
|
28
|
+
def user_destroyable?
|
29
|
+
!fallback_branch || (fallback_branch? && !step.fallback_branch_required?)
|
30
|
+
end
|
31
|
+
|
32
|
+
def arc_guard_attachable?
|
33
|
+
!fallback_branch? && step.branch_arc_guard_attachable?
|
34
|
+
end
|
35
|
+
|
36
|
+
def copy_arc_guards_to(arc)
|
37
|
+
return unless arc_guard_attachable?
|
38
|
+
|
39
|
+
arc_guards.find_each do |arc_guard|
|
40
|
+
new_guard = arc_guard.dup
|
41
|
+
new_guard.arc = arc
|
42
|
+
new_guard.pipeline = nil
|
43
|
+
new_guard.branch = nil
|
44
|
+
new_guard.save!
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -27,6 +27,8 @@ module FlowCore
|
|
27
27
|
scope :errored, -> { where.not(errored_at: nil) }
|
28
28
|
scope :suspended, -> { where.not(suspended_at: nil) }
|
29
29
|
|
30
|
+
validate :on_create_validation, on: :create
|
31
|
+
|
30
32
|
after_initialize do
|
31
33
|
self.payload ||= {}
|
32
34
|
end
|
@@ -66,10 +68,11 @@ module FlowCore
|
|
66
68
|
return false unless can_activate?
|
67
69
|
|
68
70
|
with_transaction_returning_status do
|
69
|
-
tokens.create! place: workflow.start_place
|
70
71
|
update! stage: :activated, activated_at: Time.zone.now
|
71
72
|
workflow.on_instance_activate(self)
|
72
73
|
|
74
|
+
tokens.create! place: workflow.start_place
|
75
|
+
|
73
76
|
true
|
74
77
|
end
|
75
78
|
end
|
@@ -117,5 +120,11 @@ module FlowCore
|
|
117
120
|
def terminate!(reason:)
|
118
121
|
terminate(reason: reason) || raise(FlowCore::InvalidTransition, "Can't terminate Instance##{id}")
|
119
122
|
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def on_create_validation
|
127
|
+
workflow.on_instance_create_validation(self)
|
128
|
+
end
|
120
129
|
end
|
121
130
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlowCore
|
4
|
+
class Pipeline < FlowCore::ApplicationRecord
|
5
|
+
self.table_name = "flow_core_pipelines"
|
6
|
+
|
7
|
+
has_many :generated_workflows,
|
8
|
+
class_name: "FlowCore::Workflow", foreign_key: :generated_by_pipeline_id,
|
9
|
+
inverse_of: :generated_by, dependent: :nullify
|
10
|
+
|
11
|
+
has_many :steps, -> { where(branch_id: nil).order(position: :asc) },
|
12
|
+
class_name: "FlowCore::Step", inverse_of: :pipeline,
|
13
|
+
dependent: :destroy
|
14
|
+
|
15
|
+
has_many :branches, class_name: "FlowCore::Branch", dependent: :restrict_with_exception
|
16
|
+
has_many :whole_steps, class_name: "FlowCore::Step", inverse_of: :pipeline, dependent: :restrict_with_exception
|
17
|
+
|
18
|
+
validates :name,
|
19
|
+
presence: true
|
20
|
+
|
21
|
+
def deploy_workflow
|
22
|
+
return if steps.empty?
|
23
|
+
return if whole_steps.exists? verified: false
|
24
|
+
|
25
|
+
workflow = nil
|
26
|
+
transaction do
|
27
|
+
workflow = generated_workflows.new name: name, type: workflow_class.to_s
|
28
|
+
on_build_workflow(workflow)
|
29
|
+
workflow.save!
|
30
|
+
|
31
|
+
end_place = workflow.create_end_place!
|
32
|
+
|
33
|
+
place_or_transition = nil
|
34
|
+
steps.each do |step|
|
35
|
+
place_or_transition = step.deploy_to_workflow!(workflow, place_or_transition)
|
36
|
+
end
|
37
|
+
|
38
|
+
if place_or_transition.is_a? FlowCore::Place
|
39
|
+
place_or_transition.input_arcs.update place: end_place
|
40
|
+
place_or_transition.reload.destroy!
|
41
|
+
else
|
42
|
+
end_place.input_transitions << place_or_transition
|
43
|
+
end
|
44
|
+
end
|
45
|
+
workflow&.verify!
|
46
|
+
|
47
|
+
workflow
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def on_build_workflow(_workflow); end
|
53
|
+
|
54
|
+
def workflow_class
|
55
|
+
FlowCore::Workflow
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -10,10 +10,11 @@ module FlowCore
|
|
10
10
|
|
11
11
|
# NOTE: Place - out -> Transition - in -> Place
|
12
12
|
has_many :input_arcs, -> { where direction: :out },
|
13
|
-
class_name: "FlowCore::Arc", inverse_of: :place, dependent: :
|
13
|
+
class_name: "FlowCore::Arc", inverse_of: :place, dependent: :destroy
|
14
14
|
has_many :output_arcs, -> { where direction: :in },
|
15
15
|
class_name: "FlowCore::Arc", inverse_of: :place, dependent: :delete_all
|
16
16
|
|
17
|
+
has_many :input_transitions, through: :input_arcs, class_name: "FlowCore::Transition", source: :transition
|
17
18
|
has_many :output_transitions, through: :output_arcs, class_name: "FlowCore::Transition", source: :transition
|
18
19
|
|
19
20
|
before_destroy :prevent_destroy
|
@@ -0,0 +1,337 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlowCore
|
4
|
+
class Step < FlowCore::ApplicationRecord
|
5
|
+
self.table_name = "flow_core_steps"
|
6
|
+
|
7
|
+
has_many :generated_transitions,
|
8
|
+
class_name: "FlowCore::Transition", foreign_key: :generated_by_step_id,
|
9
|
+
inverse_of: :generated_by, dependent: :nullify
|
10
|
+
|
11
|
+
belongs_to :pipeline, class_name: "FlowCore::Pipeline"
|
12
|
+
belongs_to :branch, class_name: "FlowCore::Branch", optional: true
|
13
|
+
|
14
|
+
has_many :branches, class_name: "FlowCore::Branch", inverse_of: :step, dependent: :destroy
|
15
|
+
belongs_to :redirect_to_step, class_name: "FlowCore::Step", optional: true
|
16
|
+
has_one :transition_trigger, class_name: "FlowCore::TransitionTrigger", dependent: :destroy
|
17
|
+
has_many :transition_callbacks, class_name: "FlowCore::TransitionCallback", dependent: :destroy
|
18
|
+
|
19
|
+
extend Ancestry::HasAncestry
|
20
|
+
has_ancestry orphan_strategy: :restrict
|
21
|
+
|
22
|
+
extend ActiveRecord::Acts::List::ClassMethods
|
23
|
+
acts_as_list scope: %i[pipeline_id branch_id]
|
24
|
+
|
25
|
+
validates :name,
|
26
|
+
presence: true
|
27
|
+
|
28
|
+
validates :type,
|
29
|
+
presence: true
|
30
|
+
|
31
|
+
validates :redirect_to_step,
|
32
|
+
inclusion: {
|
33
|
+
in: :redirectable_steps
|
34
|
+
},
|
35
|
+
allow_nil: true
|
36
|
+
|
37
|
+
validate do
|
38
|
+
if branch && branch.pipeline_id != pipeline_id
|
39
|
+
errors.add :branch, :invalid
|
40
|
+
end
|
41
|
+
|
42
|
+
if redirect_to_step && redirect_to_step.pipeline_id != pipeline_id
|
43
|
+
errors.add :redirect_to_step, :invalid
|
44
|
+
end
|
45
|
+
|
46
|
+
if redirection_step?
|
47
|
+
if !branch
|
48
|
+
errors.add :type, :invalid
|
49
|
+
elsif branch.fallback_branch?
|
50
|
+
errors.add :type, :invalid
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
before_validation do
|
56
|
+
self.pipeline ||= branch&.pipeline
|
57
|
+
end
|
58
|
+
|
59
|
+
before_save :update_parent
|
60
|
+
before_save :update_verified
|
61
|
+
|
62
|
+
after_create :reorder_by_append_to_on_create
|
63
|
+
after_destroy :recheck_redirection_steps_on_destroy
|
64
|
+
|
65
|
+
attr_accessor :append_to
|
66
|
+
|
67
|
+
def deploy_to_workflow!(_workflow, _input_place_or_transition)
|
68
|
+
raise NotImplementedError
|
69
|
+
end
|
70
|
+
|
71
|
+
def redirection_step?
|
72
|
+
self.class.redirection_step?
|
73
|
+
end
|
74
|
+
|
75
|
+
def multi_branch_step?
|
76
|
+
self.class.multi_branch_step?
|
77
|
+
end
|
78
|
+
|
79
|
+
def barrier_step?
|
80
|
+
self.class.barrier_step?
|
81
|
+
end
|
82
|
+
|
83
|
+
def transition_trigger_attachable?
|
84
|
+
self.class.transition_trigger_attachable?
|
85
|
+
end
|
86
|
+
|
87
|
+
def transition_callback_attachable?
|
88
|
+
self.class.transition_callback_attachable?
|
89
|
+
end
|
90
|
+
|
91
|
+
def branch_arc_guard_attachable?
|
92
|
+
self.class.branch_arc_guard_attachable?
|
93
|
+
end
|
94
|
+
|
95
|
+
def fallback_branch_required?
|
96
|
+
self.class.fallback_branch_required?
|
97
|
+
end
|
98
|
+
|
99
|
+
def transition_trigger_required?
|
100
|
+
self.class.transition_trigger_required?
|
101
|
+
end
|
102
|
+
|
103
|
+
def redirection_configurable?
|
104
|
+
self.class.redirection_configurable?
|
105
|
+
end
|
106
|
+
|
107
|
+
def branch_configurable?
|
108
|
+
self.class.branch_configurable?
|
109
|
+
end
|
110
|
+
|
111
|
+
def redirectable_steps
|
112
|
+
return [] unless redirection_step?
|
113
|
+
|
114
|
+
redirectable_steps = []
|
115
|
+
|
116
|
+
# Barrier step is the stop point, beyond if can't ensure the workflow valid
|
117
|
+
# e.g. consider there's a redirection step in one of branch of a parallel branch step,
|
118
|
+
# the parallel branch step is the barrier step, if redirect beyond the barrier step,
|
119
|
+
# it will multiplex all branches again and again
|
120
|
+
# Barrier step 是保障流程的边界,如果重定向到边界外的节点,就无法保证流程合法,
|
121
|
+
# 一个例子是假设并发分支步骤的某个分支里有一个重定向节点,并发分支步骤就是一个 Barrier Step,
|
122
|
+
# 如果可以重定向到并发分支步骤外,重定向到步骤后会重新执行这个并发分支步骤,导致其他分支的步骤会被无限重复执行
|
123
|
+
ancestors.reverse_each do |step|
|
124
|
+
break if step.barrier_step?
|
125
|
+
|
126
|
+
redirectable_steps << step
|
127
|
+
end
|
128
|
+
|
129
|
+
# return an empty array if there's no safe ancestor,
|
130
|
+
# redirect to steps which in current branch in not safe, because it will infinite loop
|
131
|
+
# 如果一个安全的祖先步骤都没有,就返回空集,跳到当前分支的步骤会导致死循环或者死代码,没有意义
|
132
|
+
return [] if redirectable_steps.empty?
|
133
|
+
|
134
|
+
# if the redirection step is the first step of a branch,
|
135
|
+
# avoiding redirect to parent and ancestors which are first step (of a branch) and without a transition trigger,
|
136
|
+
# because it will lead infinite loop,
|
137
|
+
# 如果重定向步骤是分支的第一步,那么父步骤和其他也是处于(分支)第一步的祖先,也都要避免跳转,因为会导致死循环
|
138
|
+
if position == 1 && redirectable_steps.any?
|
139
|
+
if redirectable_steps.first.multi_branch_step? && !redirectable_steps.first.transition_trigger
|
140
|
+
redirectable_steps.shift
|
141
|
+
end
|
142
|
+
|
143
|
+
while redirectable_steps.any?
|
144
|
+
step = redirectable_steps.first
|
145
|
+
if step.multi_branch_step? && !redirectable_steps.first.transition_trigger
|
146
|
+
redirectable_steps.shift
|
147
|
+
|
148
|
+
if step.position > 1
|
149
|
+
break
|
150
|
+
end
|
151
|
+
else
|
152
|
+
break
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# It's safe to redirect to any top level (or main branch) steps,
|
158
|
+
# just avoiding the redirect step's ancestor, because it may lead infinite loop
|
159
|
+
# 跳到顶层(或者说主干)步骤都是安全的,只是要去掉跳转步骤的祖先,因为会导致死循环
|
160
|
+
if redirectable_steps.reject!(&:root?)
|
161
|
+
redirectable_steps.concat(pipeline.steps)
|
162
|
+
elsif redirectable_steps.empty?
|
163
|
+
redirectable_steps.concat(pipeline.steps - ancestors)
|
164
|
+
end
|
165
|
+
|
166
|
+
# It's also safe to redirect to any of children steps,
|
167
|
+
# just avoid current branch which the redirection step belongs to.
|
168
|
+
# 跳转到任何步骤的分支也都是安全的,就是要避免分支是当前跳转步骤的祖先步骤
|
169
|
+
redirectable_steps.map! do |s|
|
170
|
+
if s.parent_of? self
|
171
|
+
[s].concat s.children.where.not(branch_id: branch_id)
|
172
|
+
else
|
173
|
+
[s].concat s.children
|
174
|
+
end
|
175
|
+
end
|
176
|
+
redirectable_steps.flatten!
|
177
|
+
redirectable_steps.uniq!
|
178
|
+
redirectable_steps.reject!(&:redirection_step?)
|
179
|
+
|
180
|
+
redirectable_steps
|
181
|
+
end
|
182
|
+
|
183
|
+
class << self
|
184
|
+
def multi_branch_step?
|
185
|
+
false
|
186
|
+
end
|
187
|
+
|
188
|
+
def redirection_step?
|
189
|
+
false
|
190
|
+
end
|
191
|
+
|
192
|
+
def barrier_step?
|
193
|
+
false
|
194
|
+
end
|
195
|
+
|
196
|
+
def transition_trigger_attachable?
|
197
|
+
!multi_branch_step? && !redirection_step?
|
198
|
+
end
|
199
|
+
|
200
|
+
def transition_callback_attachable?
|
201
|
+
!multi_branch_step?
|
202
|
+
end
|
203
|
+
|
204
|
+
def branch_arc_guard_attachable?
|
205
|
+
false
|
206
|
+
end
|
207
|
+
|
208
|
+
def redirection_configurable?
|
209
|
+
false
|
210
|
+
end
|
211
|
+
|
212
|
+
def branch_configurable?
|
213
|
+
false
|
214
|
+
end
|
215
|
+
|
216
|
+
def transition_trigger_required?
|
217
|
+
false
|
218
|
+
end
|
219
|
+
|
220
|
+
def fallback_branch_required?
|
221
|
+
false
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
private
|
226
|
+
|
227
|
+
def update_verified
|
228
|
+
self.verified = valid?
|
229
|
+
end
|
230
|
+
|
231
|
+
def find_or_create_input_place(workflow, input_place_or_transition)
|
232
|
+
if input_place_or_transition.is_a? FlowCore::Transition
|
233
|
+
input_place_or_transition.output_places.create! workflow: workflow
|
234
|
+
elsif input_place_or_transition.is_a? FlowCore::Place
|
235
|
+
input_place_or_transition
|
236
|
+
elsif workflow.start_place
|
237
|
+
workflow.start_place
|
238
|
+
else
|
239
|
+
workflow.create_start_place!
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def copy_transition_trigger_to(transition)
|
244
|
+
return unless transition_trigger_attachable?
|
245
|
+
return unless transition_trigger
|
246
|
+
|
247
|
+
trigger = transition_trigger.dup
|
248
|
+
trigger.transition = transition
|
249
|
+
trigger.pipeline = nil
|
250
|
+
trigger.step = nil
|
251
|
+
|
252
|
+
trigger.save!
|
253
|
+
end
|
254
|
+
|
255
|
+
def copy_transition_callbacks_to(transition)
|
256
|
+
return unless transition_callback_attachable?
|
257
|
+
|
258
|
+
transition_callbacks.find_each do |cb|
|
259
|
+
new_cb = cb.dup
|
260
|
+
new_cb.transition = transition
|
261
|
+
new_cb.pipeline = nil
|
262
|
+
new_cb.step = nil
|
263
|
+
new_cb.save!
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def deploy_branches_to(workflow, input_transition, append_to_place_or_transition)
|
268
|
+
return unless multi_branch_step?
|
269
|
+
|
270
|
+
branches.includes(:steps, :arc_guards).find_each do |branch|
|
271
|
+
if branch.steps.empty?
|
272
|
+
if append_to_place_or_transition.is_a?(FlowCore::Place)
|
273
|
+
arc = input_transition.output_arcs.create! place: append_to_place_or_transition, fallback_arc: branch.fallback_branch?
|
274
|
+
else
|
275
|
+
place = workflow.places.create! workflow: workflow
|
276
|
+
arc = append_to_place_or_transition.input_arcs.create! place: place, fallback_arc: branch.fallback_branch?
|
277
|
+
end
|
278
|
+
branch.copy_arc_guards_to arc
|
279
|
+
|
280
|
+
next
|
281
|
+
end
|
282
|
+
|
283
|
+
place = workflow.places.create! workflow: workflow
|
284
|
+
arc = input_transition.output_arcs.create! place: place, fallback_arc: branch.fallback_branch?
|
285
|
+
branch.copy_arc_guards_to arc
|
286
|
+
|
287
|
+
place_or_transition = nil
|
288
|
+
branch.steps.each do |step|
|
289
|
+
place_or_transition = step.deploy_to_workflow!(workflow, place_or_transition || place)
|
290
|
+
end
|
291
|
+
next unless place_or_transition
|
292
|
+
|
293
|
+
if place_or_transition.is_a? FlowCore::Transition
|
294
|
+
if append_to_place_or_transition.is_a?(FlowCore::Place)
|
295
|
+
place_or_transition.output_places << append_to_place_or_transition
|
296
|
+
else
|
297
|
+
place = place_or_transition.output_places.create! workflow: workflow
|
298
|
+
place.output_transitions << append_to_place_or_transition
|
299
|
+
end
|
300
|
+
elsif append_to_place_or_transition.is_a?(FlowCore::Place)
|
301
|
+
place_or_transition.input_arcs.update place: append_to_place_or_transition
|
302
|
+
place_or_transition.reload.destroy!
|
303
|
+
else
|
304
|
+
place_or_transition.output_places << append_to_place_or_transition
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def reorder_by_append_to_on_create
|
310
|
+
return unless append_to
|
311
|
+
|
312
|
+
if append_to.to_s == "start"
|
313
|
+
move_to_top
|
314
|
+
return
|
315
|
+
end
|
316
|
+
|
317
|
+
append_to_step = self.class.find_by id: append_to
|
318
|
+
return unless append_to_step && append_to_step.branch_id == branch_id
|
319
|
+
|
320
|
+
insert_at(append_to_step.position + 1)
|
321
|
+
end
|
322
|
+
|
323
|
+
def recheck_redirection_steps_on_destroy
|
324
|
+
return unless branch
|
325
|
+
|
326
|
+
branch.steps.to_a.select(&:redirection_step?).each do |step|
|
327
|
+
unless step.redirectable_steps.include? step.redirect_to_step
|
328
|
+
step.update! redirect_to_step: nil
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
def update_parent
|
334
|
+
self.parent = branch&.step
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|