petri_flow 0.1.8 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6b2bb56ad2f157e6a7fe5d3cbee2bfab0e3fcef64f9137bd709ac37ea27949b9
4
- data.tar.gz: c2721a5074ba1fac6462ad95bef1012c7f00bfb74ff61a1eb6ae284f97c6b013
3
+ metadata.gz: 8edfa5f265e495edad2726cb2d812e0dea76978623cc7f9e0c03d2aaa27c7e90
4
+ data.tar.gz: 8d4b8737d9fb6d4b36977d873a078d57cbba1bbffebe0d357a12e62904de4025
5
5
  SHA512:
6
- metadata.gz: 3f0f933aa496d45610048de363e7fd189586dab4af85bfb012e2b93a55703104163f0183655f61a4a8c60d7f3a20c1f9c69c64d451eb601c3da73e68e0f7b4d1
7
- data.tar.gz: 78f35f561c65b366a7c21e20420d9235813b1368f1d06e0e87a35e888a0f8755317272854dd96224acae9ca42626635d44a1551d9b2e9853411348f45a87f2e1
6
+ metadata.gz: 36a38a82bc4b3b45b0879c5019e52417589a5868192828854091b9ead9e8f34384c7063325e0d1405e6bcfe18c318f11451630226354e0f966a2277ed5ba4e2f
7
+ data.tar.gz: 8b7d014f64cfd03d7d794d87f2556c115a4b095e23dbdb4b5e67f73f7e62b4f44924769c73ad66dec1b9362264f64df7e09fe7f92df549a044f8e62c9aa91498
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "wf/application_controller"
4
+
5
+ module Wf
6
+ class StaticAssignmentsController < ApplicationController
7
+ def new
8
+ @transition = Wf::Transition.find(params[:transition_id])
9
+ @static_assignment = @transition.transition_static_assignments.new
10
+ end
11
+
12
+ def create
13
+ @transition = Wf::Transition.find(params[:transition_id])
14
+ @party = Wf::Party.find(permit_params[:party_id])
15
+ @static_assignment = @transition.transition_static_assignments.new(party: @party)
16
+ if @static_assignment.save
17
+ redirect_to workflow_transition_path(@transition.workflow, @transition), notice: "static assignment was successfully created."
18
+ else
19
+ render :new
20
+ end
21
+ end
22
+
23
+ def destroy
24
+ @transition = Wf::Transition.find(params[:transition_id])
25
+ @static_assignment = @transition.transition_static_assignments.find(params[:id])
26
+ @static_assignment.destroy
27
+ render js: "window.location.reload()"
28
+ end
29
+
30
+ def permit_params
31
+ params.fetch(:transition_static_assignment, {}).permit(:party_id)
32
+ end
33
+ end
34
+ end
@@ -12,6 +12,11 @@ module Wf
12
12
  breadcrumb @workflow.name, workflow_path(@workflow)
13
13
  end
14
14
 
15
+ def show
16
+ @workflow = Wf::Workflow.find(params[:workflow_id])
17
+ @transition = @workflow.transitions.find(params[:id])
18
+ end
19
+
15
20
  def create
16
21
  @workflow = Wf::Workflow.find(params[:workflow_id])
17
22
  tp = transition_params.merge(form: GlobalID::Locator.locate(transition_params[:form]))
@@ -65,7 +70,9 @@ module Wf
65
70
  :unassignment_callback,
66
71
  :notification_callback,
67
72
  :deadline_callback,
68
- :sub_workflow_id
73
+ :sub_workflow_id,
74
+ :multiple_instance,
75
+ :finish_condition
69
76
  )
70
77
  end
71
78
  end
@@ -11,11 +11,7 @@ module Wf
11
11
  breadcrumb "Workflows", :workflows_path
12
12
 
13
13
  def index
14
- current_party_ids = [
15
- wf_current_user,
16
- Wf.org_classes.map { |org, _org_class| wf_current_user&.public_send(org) }
17
- ].flatten.map { |x| x&.party&.id }.compact
18
- @workitems = Wf::Workitem.joins(:workitem_assignments).where(Wf::WorkitemAssignment.table_name => { party_id: current_party_ids })
14
+ @workitems = Wf::Workitem.todo(wf_current_user)
19
15
  @workitems = @workitems.where(state: params[:state].intern) if params[:state]
20
16
  @workitems = @workitems.where(state: params[:state].intern) if params[:state].present?
21
17
  @workitems = @workitems.distinct.order("id desc").page(params[:page])
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wf
4
+ module StaticAssignmentsHelper
5
+ end
6
+ end
@@ -26,8 +26,25 @@ module Wf::CaseCommand
26
26
  workitem.workitem_assignments.create!(party: party)
27
27
  new_users = party.partable.users.to_a
28
28
  to_notify = new_users - notified_users
29
+ transition = workitem.transition
29
30
  to_notify.each do |user|
30
- workitem.transition.notification_callback.constantize.new(workitem, user.id).perform_now
31
+ # TODO: multiple instance + sub workflow
32
+ if transition.multiple_instance? && !workitem.forked?
33
+ next if workitem.children.where(holding_user: user).exists?
34
+
35
+ child = workitem.children.create!(
36
+ workflow_id: workitem.workflow_id,
37
+ transition_id: workitem.transition_id,
38
+ state: :enabled,
39
+ trigger_time: workitem.trigger_time,
40
+ forked: true,
41
+ holding_user: user,
42
+ case_id: workitem.case_id
43
+ )
44
+ workitem.transition.notification_callback.constantize.new(child, user.id).perform_now
45
+ else
46
+ workitem.transition.notification_callback.constantize.new(workitem, user.id).perform_now
47
+ end
31
48
  end
32
49
  end
33
50
  end
@@ -10,8 +10,22 @@ module Wf::CaseCommand
10
10
 
11
11
  def call
12
12
  Wf::ApplicationRecord.transaction do
13
- FireTransitionInternal.call(workitem)
14
- SweepAutomaticTransitions.call(workitem.case)
13
+ if workitem.forked?
14
+ workitem.update!(finished_at: Time.zone.now, state: :finished)
15
+ Wf::Workitem.increment_counter(:children_finished_count, workitem.parent_id)
16
+ if parent = workitem.parent
17
+ if (parent.children_finished_count >= parent.children_count) || workitem.transition.finish_condition.constantize.new.perform(workitem)
18
+ parent.children.where(state: %i[started enabled]).find_each do |wi|
19
+ wi.update!(overridden_at: Time.zone.now, state: :overridden)
20
+ end
21
+ FireTransitionInternal.call(parent)
22
+ SweepAutomaticTransitions.call(parent.case)
23
+ end
24
+ end
25
+ else
26
+ FireTransitionInternal.call(workitem)
27
+ SweepAutomaticTransitions.call(workitem.case)
28
+ end
15
29
  end
16
30
  end
17
31
  end
@@ -10,6 +10,7 @@ module Wf::CaseCommand
10
10
  end
11
11
 
12
12
  def call
13
+ raise("The workitem can not run by user.") unless workitem.real?
13
14
  raise("The workitem is not in state #{workitem.state}") unless workitem.enabled?
14
15
 
15
16
  # TODO: holding timeout
@@ -52,7 +52,7 @@ module Wf
52
52
  when "datetime"
53
53
  "datetime_field"
54
54
  when "boolean"
55
- "radio_button"
55
+ "check_box"
56
56
  when "text"
57
57
  "text_area"
58
58
  else
@@ -50,21 +50,11 @@ module Wf
50
50
  end
51
51
  end
52
52
 
53
- def check_exp(entry, workitem)
54
- form_hash = if entry
55
- entry.for_mini_racer
56
- else
57
- {}
58
- end
59
-
60
- target_hash = workitem&.case&.targetable&.attributes || {}
61
- user_hash = workitem&.holding_user&.attributes || {}
62
-
53
+ def check_exp(_entry, workitem)
63
54
  # 1000ms, 200mb
64
55
  context = MiniRacer::Context.new(timeout: 1000, max_memory: 200_000_000)
65
- context.eval("let form = #{form_hash.to_json};")
66
- context.eval("let user = #{user_hash.to_json};")
67
56
  context.eval("let target = #{target_hash.to_json};")
57
+ context.eval("let workitem = #{workitem.to_json};")
68
58
  exp_value = context.eval(exp)
69
59
  yes_or_no?(exp_value, value)
70
60
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wf
4
+ module MultipleInstances
5
+ class AllFinish
6
+ def perform(_workitem)
7
+ false
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
-
3
2
  # == Schema Information
4
3
  #
5
4
  # Table name: wf_transitions
@@ -24,6 +23,8 @@
24
23
  # unassignment_callback :string default("Wf::Callbacks::UnassignmentDefault")
25
24
  # form_type :string default("Wf::Form")
26
25
  # sub_workflow_id :integer
26
+ # multiple_instance :boolean default("false")
27
+ # finish_condition :string default("Wf::MultipleInstances::AllFinish")
27
28
  #
28
29
 
29
30
  module Wf
@@ -17,5 +17,11 @@ module Wf
17
17
  belongs_to :workflow
18
18
  belongs_to :transition
19
19
  belongs_to :party
20
+
21
+ validates :party_id, uniqueness: { scope: %i[workflow_id transition_id] }
22
+
23
+ before_validation do
24
+ self.workflow_id = transition&.workflow_id
25
+ end
20
26
  end
21
27
  end
@@ -119,8 +119,13 @@ module Wf
119
119
 
120
120
  tg_mapping = {}
121
121
  transitions.each do |t|
122
+ peripheries = if t.multiple_instance?
123
+ 3
124
+ else
125
+ 1
126
+ end
122
127
  tg = graph.add_nodes(t.graph_id, label: t.name, shape: :box, style: :filled, fillcolor: "#d6ddfa", color: "#d6ddfa",
123
- fontcolor: "#2c50ed", fontname: fontfamily,
128
+ fontcolor: "#2c50ed", fontname: fontfamily, peripheries: peripheries,
124
129
  href: Wf::Engine.routes.url_helpers.edit_workflow_transition_path(self, t))
125
130
  tg_mapping[t] = tg
126
131
  # NOTICE: if sub_workflow is transition's workflow, then graph will loop infinite, this is valid for workflow definition.
@@ -4,21 +4,25 @@
4
4
  #
5
5
  # Table name: wf_workitems
6
6
  #
7
- # id :integer not null, primary key
8
- # case_id :integer
9
- # workflow_id :integer
10
- # transition_id :integer
11
- # state :integer default("0")
12
- # enabled_at :datetime
13
- # started_at :datetime
14
- # canceled_at :datetime
15
- # finished_at :datetime
16
- # overridden_at :datetime
17
- # deadline :datetime
18
- # created_at :datetime not null
19
- # updated_at :datetime not null
20
- # trigger_time :datetime
21
- # holding_user_id :string
7
+ # id :integer not null, primary key
8
+ # case_id :integer
9
+ # workflow_id :integer
10
+ # transition_id :integer
11
+ # state :integer default("0")
12
+ # enabled_at :datetime
13
+ # started_at :datetime
14
+ # canceled_at :datetime
15
+ # finished_at :datetime
16
+ # overridden_at :datetime
17
+ # deadline :datetime
18
+ # created_at :datetime not null
19
+ # updated_at :datetime not null
20
+ # trigger_time :datetime
21
+ # holding_user_id :string
22
+ # children_count :integer default("0")
23
+ # children_finished_count :integer default("0")
24
+ # forked :boolean default("false")
25
+ # parent_id :integer
22
26
  #
23
27
 
24
28
  module Wf
@@ -26,6 +30,7 @@ module Wf
26
30
  belongs_to :workflow
27
31
  belongs_to :transition
28
32
  belongs_to :case
33
+ belongs_to :parent, class_name: "Wf::Workitem", optional: true, counter_cache: :children_count
29
34
  belongs_to :holding_user, foreign_key: :holding_user_id, class_name: Wf.user_class.to_s, optional: true
30
35
  has_many :workitem_assignments
31
36
  has_many :parties, through: :workitem_assignments, source: "party"
@@ -33,6 +38,8 @@ module Wf
33
38
  has_many :entries, class_name: Wf.entry_class.to_s
34
39
  has_one :started_case, foreign_key: :started_by_workitem_id, class_name: "Wf::Case"
35
40
 
41
+ has_many :children, foreign_key: :parent_id, class_name: "Wf::Workitem"
42
+
36
43
  enum state: {
37
44
  enabled: 0,
38
45
  started: 1,
@@ -41,6 +48,39 @@ module Wf
41
48
  overridden: 4
42
49
  }
43
50
 
51
+ def self.todo(wf_current_user)
52
+ current_party_ids = [
53
+ wf_current_user,
54
+ Wf.org_classes.map { |org, _org_class| wf_current_user&.public_send(org) }
55
+ ].flatten.map { |x| x&.party&.id }.compact
56
+ Wf::Workitem.where(forked: false).joins(:workitem_assignments).where(Wf::WorkitemAssignment.table_name => { party_id: current_party_ids })
57
+ end
58
+
59
+ def self.doing(wf_current_user)
60
+ where(holding_user: wf_current_user).where(state: %i[started enabled])
61
+ end
62
+
63
+ def self.done(wf_current_user)
64
+ where(holding_user: wf_current_user).where(state: [:finished])
65
+ end
66
+
67
+ def for_mini_racer
68
+ attr = attributes
69
+ attr = attr.merge(holding_user: holding_user&.attributes || {})
70
+ attr = attr.merge(form: entries.to_a.first&.for_mini_racer || {})
71
+ children_attrs = if forked?
72
+ []
73
+ else
74
+ children.includes(:holding_user, entries: :field_values).map(&:for_mini_racer)
75
+ end
76
+ attr = attr.merge(children: children_attrs)
77
+ attr
78
+ end
79
+
80
+ def parent?
81
+ !forked
82
+ end
83
+
44
84
  def name
45
85
  "Workitem -> #{id}"
46
86
  end
@@ -54,12 +94,19 @@ module Wf
54
94
  end
55
95
  end
56
96
 
97
+ def real?
98
+ return false if transition.multiple_instance? && parent_id.nil?
99
+ return false if transition.sub_workflow_id.present?
100
+
101
+ true
102
+ end
103
+
57
104
  def started_by?(user)
58
- enabled? && owned_by?(user)
105
+ real? && enabled? && owned_by?(user)
59
106
  end
60
107
 
61
108
  def finished_by?(user)
62
- started? && owned_by?(user) && holding_user == user
109
+ real? && started? && owned_by?(user) && holding_user == user
63
110
  end
64
111
 
65
112
  def owned_by?(user)
@@ -22,7 +22,7 @@
22
22
  </div>
23
23
 
24
24
  <div class="form-group">
25
- <%= f.label :exp, class: "label" %> <small>JavaScript with build-in variable <span class="badge badge-danger">user</span>, <span class="badge badge-danger">form</span>, <span class="badge badge-danger">target</span>.</small>
25
+ <%= f.label :exp, class: "label" %> <small>JavaScript with build-in variable <span class="badge badge-danger">workitem</span>, <span class="badge badge-danger">target</span>.</small>
26
26
  <%= f.text_area :exp, class: "form-control", placeholder: "Exp", rows: 8 %>
27
27
  </div>
28
28
 
@@ -0,0 +1,27 @@
1
+ <%= form_with(model: static_assignment, url: transition_static_assignments_path(static_assignment.transition), local: true) do |f| %>
2
+ <% if static_assignment.errors.any? %>
3
+ <article class="message is-danger">
4
+ <div class="message-header">
5
+ <p>
6
+ <%= pluralize(static_assignment.errors.count, "error") %> prohibited this static_assignment from being saved:
7
+ </p>
8
+ </div>
9
+ <div class="message-body content">
10
+ <ul>
11
+ <% static_assignment.errors.full_messages.each do |message| %>
12
+ <li><%= message %></li>
13
+ <% end %>
14
+ </ul>
15
+ </div>
16
+ </article>
17
+ <% end %>
18
+
19
+ <div class="form-group">
20
+ <%= f.label :party, class: "label" %>
21
+ <%= f.select :party_id, Wf::Party.all.map{|x| [x.party_name, x.id]}, {}, class: "form-control custom-select", placeholder: "fieldable" %>
22
+ </div>
23
+
24
+ <div class="form-group">
25
+ <%= f.submit class: "btn btn-primary", value: 'Create Static Assignment', data: {disable_with: 'Waiting...'} %>
26
+ </div>
27
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <div class="card card-body">
2
+ <%= render "form", static_assignment: @static_assignment %>
3
+ </div>
@@ -16,79 +16,114 @@
16
16
  </article>
17
17
  <% end %>
18
18
 
19
- <div class="form-group">
20
- <%= f.label :name, class: "label" %>
21
- <%= f.text_field :name, class: "form-control", placeholder: "Name" %>
22
- </div>
19
+ <div class="card">
20
+ <h5 class="card-header">Basic Information</h5>
21
+ <div class="card-body">
22
+ <div class="form-group">
23
+ <%= f.label :name, class: "label" %>
24
+ <%= f.text_field :name, class: "form-control", placeholder: "Name" %>
25
+ </div>
23
26
 
24
- <div class="form-group">
25
- <%= f.label :description, class: "label" %>
26
- <%= f.text_area :description, class: "form-control", placeholder: "Description" %>
27
- </div>
27
+ <div class="form-group">
28
+ <%= f.label :description, class: "label" %>
29
+ <%= f.text_area :description, class: "form-control", placeholder: "Description" %>
30
+ </div>
28
31
 
29
- <div class="form-group">
30
- <%= f.label :trigger_limit, class: "label" %>
31
- <%= f.text_field :trigger_limit, class: "form-control", placeholder: "Trigger Limit" %>
32
- </div>
32
+ <div class="form-group">
33
+ <%= f.label :trigger_limit, class: "label" %>
34
+ <%= f.text_field :trigger_limit, class: "form-control", placeholder: "Trigger Limit" %>
35
+ </div>
33
36
 
34
- <div class="form-group">
35
- <%= f.label :sort_order, class: "label" %>
36
- <%= f.text_field :sort_order, class: "form-control", placeholder: "Sort Order" %>
37
- </div>
37
+ <div class="form-group">
38
+ <%= f.label :sort_order, class: "label" %>
39
+ <%= f.text_field :sort_order, class: "form-control", placeholder: "Sort Order" %>
40
+ </div>
38
41
 
39
- <div class="form-group">
40
- <%= f.label :trigger_type, class: "label" %>
41
- <%= f.select :trigger_type, Wf::Transition.trigger_types.keys, {}, class: "form-control custom-select", placeholder: "Trigger Type" %>
42
+ <div class="form-group">
43
+ <%= f.label :trigger_type, class: "label" %>
44
+ <%= f.select :trigger_type, Wf::Transition.trigger_types.keys, {}, class: "form-control custom-select", placeholder: "Trigger Type" %>
45
+ </div>
46
+ </div>
42
47
  </div>
43
48
 
44
- <div class="form-group">
45
- <%= f.label :sub_workflow, class: "label" %>
46
- <%= f.select :sub_workflow_id, options_for_select(Wf::Workflow.valid.all.map{|x| [x.name, x.id]} || []), {include_blank: 'Start a sub workflow?'}, class: "form-control custom-select", placeholder: "Sub Workflow" %>
47
- </div>
48
49
 
49
- <div class="form-group">
50
- <%= f.label :form, class: "label" %>
51
- <%= f.select :form, options_for_select(Wf.form_class.constantize.all.map{|x| [x.name, x.to_global_id]} || [], selected: f.object&.form&.to_global_id), {include_blank: 'user can input from custom form?'}, class: "form-control custom-select", placeholder: "Form" %>
50
+ <div class="card">
51
+ <h5 class="card-header">Sub Workflow</h5>
52
+ <div class="card-body">
53
+ <div class="form-group">
54
+ <%= f.label :sub_workflow, class: "label" %>
55
+ <%= f.select :sub_workflow_id, options_for_select(Wf::Workflow.valid.all.map{|x| [x.name, x.id]} || []), {include_blank: 'Start a sub workflow?'}, class: "form-control custom-select", placeholder: "Sub Workflow" %>
56
+ </div>
52
57
  </div>
53
58
 
54
- <div class="form-group">
55
- <%= f.label :enable_callback, class: "label" %>
56
- <%= f.select :enable_callback, Wf.enable_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
59
+ <div class="card">
60
+ <h5 class="card-header">Dynimac Form</h5>
61
+ <div class="card-body">
62
+ <div class="form-group">
63
+ <%= f.label :form, class: "label" %>
64
+ <%= f.select :form, options_for_select(Wf.form_class.constantize.all.map{|x| [x.name, x.to_global_id]} || [], selected: f.object&.form&.to_global_id), {include_blank: 'user can input from custom form?'}, class: "form-control custom-select", placeholder: "Form" %>
65
+ </div>
66
+ </div>
57
67
  </div>
58
68
 
59
- <div class="form-group">
60
- <%= f.label :fire_callback, class: "label" %>
61
- <%= f.select :fire_callback, Wf.fire_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
62
- </div>
69
+ <div class="card">
70
+ <h5 class="card-header">Callbacks</h5>
71
+ <div class="card-body">
63
72
 
64
- <div class="form-group">
65
- <%= f.label :deadline_callback, class: "label" %>
66
- <%= f.select :deadline_callback, Wf.deadline_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
67
- </div>
73
+ <div class="form-group">
74
+ <%= f.label :enable_callback, class: "label" %>
75
+ <%= f.select :enable_callback, Wf.enable_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
76
+ </div>
68
77
 
69
- <div class="form-group">
70
- <%= f.label :time_callback, class: "label" %>
71
- <%= f.select :time_callback, Wf.time_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
72
- </div>
78
+ <div class="form-group">
79
+ <%= f.label :fire_callback, class: "label" %>
80
+ <%= f.select :fire_callback, Wf.fire_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
81
+ </div>
73
82
 
74
- <div class="form-group">
75
- <%= f.label :hold_timeout_callback, class: "label" %>
76
- <%= f.select :hold_timeout_callback, Wf.hold_timeout_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
77
- </div>
83
+ <div class="form-group">
84
+ <%= f.label :deadline_callback, class: "label" %>
85
+ <%= f.select :deadline_callback, Wf.deadline_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
86
+ </div>
78
87
 
79
- <div class="form-group">
80
- <%= f.label :assignment_callback, class: "label" %>
81
- <%= f.select :assignment_callback, Wf.assignment_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
82
- </div>
88
+ <div class="form-group">
89
+ <%= f.label :time_callback, class: "label" %>
90
+ <%= f.select :time_callback, Wf.time_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
91
+ </div>
83
92
 
84
- <div class="form-group">
85
- <%= f.label :unassignment_callback, class: "label" %>
86
- <%= f.select :unassignment_callback, Wf.unassignment_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
93
+ <div class="form-group">
94
+ <%= f.label :hold_timeout_callback, class: "label" %>
95
+ <%= f.select :hold_timeout_callback, Wf.hold_timeout_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
96
+ </div>
97
+
98
+ <div class="form-group">
99
+ <%= f.label :assignment_callback, class: "label" %>
100
+ <%= f.select :assignment_callback, Wf.assignment_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
101
+ </div>
102
+
103
+ <div class="form-group">
104
+ <%= f.label :unassignment_callback, class: "label" %>
105
+ <%= f.select :unassignment_callback, Wf.unassignment_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
106
+ </div>
107
+
108
+ <div class="form-group">
109
+ <%= f.label :notification_callback, class: "label" %>
110
+ <%= f.select :notification_callback, Wf.notification_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
111
+ </div>
112
+ </div>
87
113
  </div>
88
114
 
89
- <div class="form-group">
90
- <%= f.label :notification_callback, class: "label" %>
91
- <%= f.select :notification_callback, Wf.notification_callbacks, {}, class: "form-control custom-select", placeholder: "Callback" %>
115
+ <div class="card">
116
+ <h5 class="card-header">Multiple Instances</h5>
117
+ <div class="card-body">
118
+ <div class="form-group">
119
+ <%= f.label :multiple_instance, class: "label" %>
120
+ <%= f.check_box :multiple_instance %>
121
+ </div>
122
+ <div class="form-group">
123
+ <%= f.label :finish_condition, class: "label" %>
124
+ <%= f.select :finish_condition, Wf.finish_conditions, {}, class: "form-control custom-select", placeholder: "Finish_condition" %>
125
+ </div>
126
+ </div>
92
127
  </div>
93
128
 
94
129
  <div class="form-group">
@@ -0,0 +1,83 @@
1
+ <div class="card card-body">
2
+ <div class="float-right">
3
+ <%= link_to 'Edit Transition', edit_workflow_transition_path(@workflow, @transition), class: 'btn btn-primary' %>
4
+ <%= link_to 'Create Static Assignments', new_transition_static_assignment_path(@transition), class: 'btn btn-primary' %>
5
+ </div>
6
+ <div>
7
+ <h2>Transition Detail</h2>
8
+ <table class="table table-view">
9
+ <tbody>
10
+ <tr>
11
+ <th scope="row">ID</th>
12
+ <td><%= @transition.id %></td>
13
+ </tr>
14
+ <tr>
15
+ <th scope="row">Name</th>
16
+ <td><%= @transition.name %></td>
17
+ </tr>
18
+ <tr>
19
+ <th scope="row">Trigger Limit</th>
20
+ <td><%= @transition.trigger_limit %></td>
21
+ </tr>
22
+ <tr>
23
+ <th scope="row">Trigger Type</th>
24
+ <td><%= @transition.trigger_type %></td>
25
+ </tr>
26
+ <tr>
27
+ <th>Form</th>
28
+ <td>
29
+ <% if @transition.form %>
30
+ <%= link_to @transition.form.name, form_path(@transition.form) %>
31
+ <% else %>
32
+ No Form
33
+ <% end %>
34
+ </td>
35
+ </tr>
36
+
37
+ <tr>
38
+ <th>Sub Workflow</th>
39
+ <td>
40
+ <% if @transition.sub_workflow %>
41
+ <%= link_to @transition.sub_workflow.name, workflow_path(@transition.sub_workflow_id) %>
42
+ <% else %>
43
+ No
44
+ <% end %>
45
+ </td>
46
+ </tr>
47
+
48
+ <tr>
49
+ <th scope="row">Multiple Instance?</th>
50
+ <td><%= @transition.multiple_instance %></td>
51
+ </tr>
52
+ <tr>
53
+ <th scope="row">Finish Condition</th>
54
+ <td><%= @transition.finish_condition %></td>
55
+ </tr>
56
+ </tbody>
57
+ </table>
58
+ </div>
59
+
60
+ <div>
61
+ <h2>Static Assignments</h2>
62
+ <table class="table table-view">
63
+ <thead>
64
+ <tr>
65
+ <th scope="col">ID</th>
66
+ <th scope="col">Party Name</th>
67
+ <th scope="col">Party Type</th>
68
+ <th scope="col">Actions</th>
69
+ </tr>
70
+ </thead>
71
+ <tbody>
72
+ <% @transition.transition_static_assignments.each do |assign| %>
73
+ <tr>
74
+ <td><%= assign.id %></td>
75
+ <td><%= assign.party.party_name %></td>
76
+ <td><%= assign.party.partable_type %></td>
77
+ <td><%= link_to 'Delete', transition_static_assignment_path(@transition, assign), remote: true, method: :delete, data: {confirm: 'confirm?'}, class: 'btn btn-sm btn-info' %></td>
78
+ </tr>
79
+ <% end %>
80
+ </tbody>
81
+ </table>
82
+ </div>
83
+ </div>
data/config/routes.rb CHANGED
@@ -16,6 +16,10 @@ Wf::Engine.routes.draw do
16
16
  resources :fields
17
17
  end
18
18
 
19
+ resources :transitions do
20
+ resources :static_assignments
21
+ end
22
+
19
23
  resources :workitems do
20
24
  resources :workitem_assignments, only: %i[new create destroy]
21
25
  resources :comments, only: %i[new create destroy]
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddMultiInstance < ActiveRecord::Migration[6.0]
4
+ def change
5
+ add_column :wf_transitions, :multiple_instance, :boolean, default: false, comment: "multiple instance mode or not"
6
+ add_column :wf_transitions, :finish_condition, :string, comment: "set finish condition for parent workitem.", default: "Wf::MultipleInstances::AllFinish"
7
+ add_column :wf_workitems, :children_count, :integer, default: 0
8
+ add_column :wf_workitems, :children_finished_count, :integer, default: 0
9
+ add_column :wf_workitems, :forked, :boolean, default: false
10
+ add_column :wf_workitems, :parent_id, :bigint, comment: "parent workitem id"
11
+ end
12
+ end
data/lib/wf/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wf
4
- VERSION = "0.1.8"
4
+ VERSION = "0.2.1"
5
5
  end
data/lib/wf.rb CHANGED
@@ -19,6 +19,8 @@ module Wf
19
19
 
20
20
  attr_accessor :user_class
21
21
  attr_accessor :org_classes
22
+
23
+ attr_accessor :finish_conditions
22
24
  end
23
25
 
24
26
  self.enable_callbacks = ["Wf::Callbacks::EnableDefault"]
@@ -34,4 +36,5 @@ module Wf
34
36
  self.field_class = "::Wf::Field"
35
37
  self.user_class = "::Wf::User"
36
38
  self.org_classes = { group: "::Wf::Group" }
39
+ self.finish_conditions = ["Wf::MultipleInstances::AllFinish"]
37
40
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: petri_flow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hooopo Wang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-20 00:00:00.000000000 Z
11
+ date: 2020-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bootstrap
@@ -204,6 +204,7 @@ files:
204
204
  - app/assets/stylesheets/wf/forms.css
205
205
  - app/assets/stylesheets/wf/guards.css
206
206
  - app/assets/stylesheets/wf/places.css
207
+ - app/assets/stylesheets/wf/static_assignments.css
207
208
  - app/assets/stylesheets/wf/transitions.css
208
209
  - app/assets/stylesheets/wf/uikit/_colors.scss
209
210
  - app/assets/stylesheets/wf/uikit/_variables.scss
@@ -224,6 +225,7 @@ files:
224
225
  - app/controllers/wf/forms_controller.rb
225
226
  - app/controllers/wf/guards_controller.rb
226
227
  - app/controllers/wf/places_controller.rb
228
+ - app/controllers/wf/static_assignments_controller.rb
227
229
  - app/controllers/wf/transitions_controller.rb
228
230
  - app/controllers/wf/workflows_controller.rb
229
231
  - app/controllers/wf/workitem_assignments_controller.rb
@@ -236,6 +238,7 @@ files:
236
238
  - app/helpers/wf/forms_helper.rb
237
239
  - app/helpers/wf/guards_helper.rb
238
240
  - app/helpers/wf/places_helper.rb
241
+ - app/helpers/wf/static_assignments_helper.rb
239
242
  - app/helpers/wf/transitions_helper.rb
240
243
  - app/helpers/wf/workflows_helper.rb
241
244
  - app/helpers/wf/workitem_assignments_helper.rb
@@ -293,6 +296,7 @@ files:
293
296
  - app/models/wf/form.rb
294
297
  - app/models/wf/group.rb
295
298
  - app/models/wf/guard.rb
299
+ - app/models/wf/multiple_instances/all_finish.rb
296
300
  - app/models/wf/party.rb
297
301
  - app/models/wf/place.rb
298
302
  - app/models/wf/token.rb
@@ -330,9 +334,12 @@ files:
330
334
  - app/views/wf/places/_form.html.erb
331
335
  - app/views/wf/places/edit.html.erb
332
336
  - app/views/wf/places/new.html.erb
337
+ - app/views/wf/static_assignments/_form.html.erb
338
+ - app/views/wf/static_assignments/new.html.erb
333
339
  - app/views/wf/transitions/_form.html.erb
334
340
  - app/views/wf/transitions/edit.html.erb
335
341
  - app/views/wf/transitions/new.html.erb
342
+ - app/views/wf/transitions/show.html.erb
336
343
  - app/views/wf/workflows/_form.html.erb
337
344
  - app/views/wf/workflows/edit.html.erb
338
345
  - app/views/wf/workflows/index.html.erb
@@ -353,6 +360,7 @@ files:
353
360
  - db/migrate/20200213130900_remove_workflow_id_from_form_related.rb
354
361
  - db/migrate/20200220070839_remove_unused_column.rb
355
362
  - db/migrate/20200220072512_add_sub_workflow.rb
363
+ - db/migrate/20200222150432_add_multi_instance.rb
356
364
  - lib/tasks/wf_tasks.rake
357
365
  - lib/wf.rb
358
366
  - lib/wf/engine.rb