petri_flow 0.1.0
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +34 -0
- data/app/assets/config/wf_manifest.js +2 -0
- data/app/assets/javascripts/wf/application.js +4 -0
- data/app/assets/stylesheets/wf/application.scss +2 -0
- data/app/assets/stylesheets/wf/arcs.css +4 -0
- data/app/assets/stylesheets/wf/cases.css +4 -0
- data/app/assets/stylesheets/wf/comments.css +4 -0
- data/app/assets/stylesheets/wf/fields.css +4 -0
- data/app/assets/stylesheets/wf/forms.css +4 -0
- data/app/assets/stylesheets/wf/guards.css +4 -0
- data/app/assets/stylesheets/wf/places.css +4 -0
- data/app/assets/stylesheets/wf/transitions.css +4 -0
- data/app/assets/stylesheets/wf/workflows.css +4 -0
- data/app/assets/stylesheets/wf/workitem_assignments.css +4 -0
- data/app/assets/stylesheets/wf/workitems.css +4 -0
- data/app/controllers/wf/application_controller.rb +14 -0
- data/app/controllers/wf/arcs_controller.rb +61 -0
- data/app/controllers/wf/cases_controller.rb +48 -0
- data/app/controllers/wf/comments_controller.rb +30 -0
- data/app/controllers/wf/fields_controller.rb +54 -0
- data/app/controllers/wf/forms_controller.rb +59 -0
- data/app/controllers/wf/guards_controller.rb +58 -0
- data/app/controllers/wf/places_controller.rb +53 -0
- data/app/controllers/wf/transitions_controller.rb +69 -0
- data/app/controllers/wf/workflows_controller.rb +59 -0
- data/app/controllers/wf/workitem_assignments_controller.rb +30 -0
- data/app/controllers/wf/workitems_controller.rb +79 -0
- data/app/helpers/wf/application_helper.rb +6 -0
- data/app/helpers/wf/arcs_helper.rb +6 -0
- data/app/helpers/wf/cases_helper.rb +6 -0
- data/app/helpers/wf/comments_helper.rb +6 -0
- data/app/helpers/wf/fields_helper.rb +6 -0
- data/app/helpers/wf/forms_helper.rb +6 -0
- data/app/helpers/wf/guards_helper.rb +6 -0
- data/app/helpers/wf/places_helper.rb +6 -0
- data/app/helpers/wf/transitions_helper.rb +6 -0
- data/app/helpers/wf/workflows_helper.rb +6 -0
- data/app/helpers/wf/workitem_assignments_helper.rb +6 -0
- data/app/helpers/wf/workitems_helper.rb +6 -0
- data/app/jobs/wf/application_job.rb +6 -0
- data/app/jobs/wf/fire_timed_workitem_job.rb +15 -0
- data/app/mailers/wf/application_mailer.rb +8 -0
- data/app/models/wf/application_record.rb +7 -0
- data/app/models/wf/arc.rb +42 -0
- data/app/models/wf/callbacks/assignment_default.rb +12 -0
- data/app/models/wf/callbacks/deadline_default.rb +11 -0
- data/app/models/wf/callbacks/enable_default.rb +11 -0
- data/app/models/wf/callbacks/fire_default.rb +11 -0
- data/app/models/wf/callbacks/hold_timeout_default.rb +11 -0
- data/app/models/wf/callbacks/notification_default.rb +11 -0
- data/app/models/wf/callbacks/time_default.rb +11 -0
- data/app/models/wf/callbacks/unassignment_default.rb +11 -0
- data/app/models/wf/case.rb +44 -0
- data/app/models/wf/case_assignment.rb +22 -0
- data/app/models/wf/case_command/add_comment.rb +17 -0
- data/app/models/wf/case_command/add_manual_assignment.rb +17 -0
- data/app/models/wf/case_command/add_token.rb +20 -0
- data/app/models/wf/case_command/add_workitem_assignment.rb +35 -0
- data/app/models/wf/case_command/begin_workitem_action.rb +33 -0
- data/app/models/wf/case_command/cancel.rb +17 -0
- data/app/models/wf/case_command/cancel_workitem.rb +20 -0
- data/app/models/wf/case_command/clear_manual_assignments.rb +16 -0
- data/app/models/wf/case_command/clear_workitem_assignments.rb +20 -0
- data/app/models/wf/case_command/consume_token.rb +23 -0
- data/app/models/wf/case_command/enable_transitions.rb +33 -0
- data/app/models/wf/case_command/end_workitem_action.rb +25 -0
- data/app/models/wf/case_command/finish_workitem.rb +18 -0
- data/app/models/wf/case_command/finished_p.rb +28 -0
- data/app/models/wf/case_command/fire_message_transition.rb +20 -0
- data/app/models/wf/case_command/fire_transition_internal.rb +41 -0
- data/app/models/wf/case_command/lock_token.rb +21 -0
- data/app/models/wf/case_command/new.rb +17 -0
- data/app/models/wf/case_command/release_token.rb +20 -0
- data/app/models/wf/case_command/remove_manual_assignment.rb +17 -0
- data/app/models/wf/case_command/remove_workitem_assignment.rb +24 -0
- data/app/models/wf/case_command/resume.rb +17 -0
- data/app/models/wf/case_command/set_workitem_assignments.rb +32 -0
- data/app/models/wf/case_command/start_case.rb +19 -0
- data/app/models/wf/case_command/start_workitem.rb +26 -0
- data/app/models/wf/case_command/suspend.rb +17 -0
- data/app/models/wf/case_command/sweep_automatic_transitions.rb +31 -0
- data/app/models/wf/case_command/sweep_timed_transitions.rb +16 -0
- data/app/models/wf/case_command/workitem_action.rb +20 -0
- data/app/models/wf/comment.rb +21 -0
- data/app/models/wf/demo_target.rb +18 -0
- data/app/models/wf/entry.rb +33 -0
- data/app/models/wf/field.rb +53 -0
- data/app/models/wf/field_value.rb +30 -0
- data/app/models/wf/form.rb +18 -0
- data/app/models/wf/group.rb +21 -0
- data/app/models/wf/guard.rb +73 -0
- data/app/models/wf/party.rb +22 -0
- data/app/models/wf/place.rb +28 -0
- data/app/models/wf/token.rb +37 -0
- data/app/models/wf/transition.rb +49 -0
- data/app/models/wf/transition_static_assignment.rb +21 -0
- data/app/models/wf/user.rb +26 -0
- data/app/models/wf/workflow.rb +182 -0
- data/app/models/wf/workitem.rb +78 -0
- data/app/models/wf/workitem_assignment.rb +19 -0
- data/app/views/layouts/wf/_alert.html.erb +4 -0
- data/app/views/layouts/wf/_footer.html.erb +13 -0
- data/app/views/layouts/wf/_nav.html.erb +13 -0
- data/app/views/layouts/wf/_notice.html.erb +4 -0
- data/app/views/layouts/wf/application.html.erb +34 -0
- data/app/views/wf/arcs/_form.html.erb +40 -0
- data/app/views/wf/arcs/edit.html.erb +1 -0
- data/app/views/wf/arcs/new.html.erb +1 -0
- data/app/views/wf/arcs/show.html.erb +67 -0
- data/app/views/wf/cases/_form.html.erb +27 -0
- data/app/views/wf/cases/index.html.erb +35 -0
- data/app/views/wf/cases/new.html.erb +1 -0
- data/app/views/wf/cases/show.html.erb +113 -0
- data/app/views/wf/comments/new.html.erb +27 -0
- data/app/views/wf/fields/_form.html.erb +42 -0
- data/app/views/wf/fields/edit.html.erb +1 -0
- data/app/views/wf/fields/new.html.erb +1 -0
- data/app/views/wf/forms/_form.html.erb +32 -0
- data/app/views/wf/forms/edit.html.erb +1 -0
- data/app/views/wf/forms/index.html.erb +32 -0
- data/app/views/wf/forms/new.html.erb +1 -0
- data/app/views/wf/forms/show.html.erb +53 -0
- data/app/views/wf/guards/_form.html.erb +43 -0
- data/app/views/wf/guards/edit.html.erb +1 -0
- data/app/views/wf/guards/new.html.erb +1 -0
- data/app/views/wf/places/_form.html.erb +43 -0
- data/app/views/wf/places/edit.html.erb +1 -0
- data/app/views/wf/places/new.html.erb +1 -0
- data/app/views/wf/transitions/_form.html.erb +92 -0
- data/app/views/wf/transitions/edit.html.erb +1 -0
- data/app/views/wf/transitions/new.html.erb +1 -0
- data/app/views/wf/workflows/_form.html.erb +32 -0
- data/app/views/wf/workflows/edit.html.erb +1 -0
- data/app/views/wf/workflows/index.html.erb +38 -0
- data/app/views/wf/workflows/new.html.erb +1 -0
- data/app/views/wf/workflows/show.html.erb +177 -0
- data/app/views/wf/workitem_assignments/new.html.erb +27 -0
- data/app/views/wf/workitems/index.html.erb +68 -0
- data/app/views/wf/workitems/pre_finish.html.erb +33 -0
- data/app/views/wf/workitems/show.html.erb +211 -0
- data/config/routes.rb +30 -0
- data/db/migrate/20200130201043_init.rb +226 -0
- data/db/migrate/20200130201641_init_some_data.rb +15 -0
- data/db/migrate/20200131200455_create_wf_entries.rb +19 -0
- data/db/migrate/20200201001543_add_target_field_name_for_guard.rb +7 -0
- data/lib/tasks/wf_tasks.rake +5 -0
- data/lib/wf/engine.rb +10 -0
- data/lib/wf/version.rb +5 -0
- data/lib/wf.rb +7 -0
- metadata +312 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_field_values
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# workflow_id :integer
|
9
|
+
# transition_id :integer
|
10
|
+
# form_id :integer
|
11
|
+
# field_id :integer
|
12
|
+
# value :text
|
13
|
+
# created_at :datetime not null
|
14
|
+
# updated_at :datetime not null
|
15
|
+
# entry_id :integer
|
16
|
+
#
|
17
|
+
|
18
|
+
module Wf
|
19
|
+
class FieldValue < ApplicationRecord
|
20
|
+
belongs_to :workflow, optional: true
|
21
|
+
belongs_to :transition, optional: true
|
22
|
+
belongs_to :form
|
23
|
+
belongs_to :field
|
24
|
+
belongs_to :entry
|
25
|
+
|
26
|
+
def value_after_cast
|
27
|
+
field.type_for_cast.cast(value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_forms
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# name :string
|
9
|
+
# description :text
|
10
|
+
# created_at :datetime not null
|
11
|
+
# updated_at :datetime not null
|
12
|
+
#
|
13
|
+
|
14
|
+
module Wf
|
15
|
+
class Form < ApplicationRecord
|
16
|
+
has_many :fields, dependent: :destroy
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_groups
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# name :string
|
9
|
+
# created_at :datetime not null
|
10
|
+
# updated_at :datetime not null
|
11
|
+
#
|
12
|
+
|
13
|
+
module Wf
|
14
|
+
class Group < ApplicationRecord
|
15
|
+
has_many :users
|
16
|
+
has_one :party, as: :partable
|
17
|
+
after_create do
|
18
|
+
create_party(party_name: name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_guards
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# arc_id :integer
|
9
|
+
# workflow_id :integer
|
10
|
+
# fieldable_type :string
|
11
|
+
# fieldable_id :string
|
12
|
+
# op :string
|
13
|
+
# value :string
|
14
|
+
# exp :string
|
15
|
+
# created_at :datetime not null
|
16
|
+
# updated_at :datetime not null
|
17
|
+
# target_attr_name :string
|
18
|
+
#
|
19
|
+
|
20
|
+
module Wf
|
21
|
+
class Guard < ApplicationRecord
|
22
|
+
belongs_to :workflow
|
23
|
+
belongs_to :arc, touch: true, counter_cache: true
|
24
|
+
belongs_to :fieldable, polymorphic: true, optional: true
|
25
|
+
|
26
|
+
before_validation do
|
27
|
+
self.workflow = arc.workflow
|
28
|
+
end
|
29
|
+
|
30
|
+
OP = %w[
|
31
|
+
=
|
32
|
+
>
|
33
|
+
<
|
34
|
+
>=
|
35
|
+
<=
|
36
|
+
is_empty
|
37
|
+
].freeze
|
38
|
+
|
39
|
+
def value_after_cast
|
40
|
+
field = fieldable
|
41
|
+
if fieldable
|
42
|
+
fieldable.type_for_cast.cast(value)
|
43
|
+
else
|
44
|
+
# TODO
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def pass?(entry)
|
49
|
+
fv = entry.field_values.where(field_id: fieldable_id).first
|
50
|
+
return unless fv
|
51
|
+
|
52
|
+
if op == "="
|
53
|
+
fv.value_after_cast == value_after_cast
|
54
|
+
elsif op == ">"
|
55
|
+
fv.value_after_cast > value_after_cast
|
56
|
+
elsif op == "<"
|
57
|
+
fv.value_after_cast < value_after_cast
|
58
|
+
elsif op == ">="
|
59
|
+
fv.value_after_cast >= value_after_cast
|
60
|
+
elsif op == "<="
|
61
|
+
fv.value_after_cast <= value_after_cast
|
62
|
+
elsif op == "is_empty"
|
63
|
+
fv.value_after_cast.blank?
|
64
|
+
else
|
65
|
+
false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def inspect
|
70
|
+
%(#{fieldable&.form&.name}.#{fieldable&.name} #{op} #{value})
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_parties
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# partable_type :string
|
9
|
+
# partable_id :string
|
10
|
+
# party_name :string
|
11
|
+
# created_at :datetime not null
|
12
|
+
# updated_at :datetime not null
|
13
|
+
#
|
14
|
+
|
15
|
+
module Wf
|
16
|
+
class Party < ApplicationRecord
|
17
|
+
# TODO: use acts_as_partable for sync group or role or user to party
|
18
|
+
belongs_to :partable, polymorphic: true
|
19
|
+
has_many :transition_static_assignments
|
20
|
+
has_many :workitem_assignments
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_places
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# workflow_id :integer
|
9
|
+
# name :string
|
10
|
+
# description :text
|
11
|
+
# sort_order :integer default("0")
|
12
|
+
# place_type :integer default("0")
|
13
|
+
# created_at :datetime not null
|
14
|
+
# updated_at :datetime not null
|
15
|
+
#
|
16
|
+
|
17
|
+
module Wf
|
18
|
+
class Place < ApplicationRecord
|
19
|
+
belongs_to :workflow, touch: true
|
20
|
+
has_many :arcs
|
21
|
+
has_many :tokens
|
22
|
+
enum place_type: {
|
23
|
+
start: 0,
|
24
|
+
normal: 1,
|
25
|
+
end: 2
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_tokens
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# workflow_id :integer
|
9
|
+
# case_id :integer
|
10
|
+
# targetable_type :string
|
11
|
+
# targetable_id :string
|
12
|
+
# place_id :integer
|
13
|
+
# state :integer default("0")
|
14
|
+
# locked_workitem_id :integer
|
15
|
+
# produced_at :datetime
|
16
|
+
# locked_at :datetime
|
17
|
+
# canceled_at :datetime
|
18
|
+
# consumed_at :datetime
|
19
|
+
# created_at :datetime not null
|
20
|
+
# updated_at :datetime not null
|
21
|
+
#
|
22
|
+
|
23
|
+
module Wf
|
24
|
+
class Token < ApplicationRecord
|
25
|
+
belongs_to :workflow
|
26
|
+
belongs_to :case
|
27
|
+
belongs_to :place
|
28
|
+
belongs_to :locked_workitem, class_name: "Wf::Workitem", optional: true
|
29
|
+
|
30
|
+
enum state: {
|
31
|
+
free: 0,
|
32
|
+
locked: 1,
|
33
|
+
canceled: 2,
|
34
|
+
consumed: 3
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_transitions
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# name :string
|
9
|
+
# description :text
|
10
|
+
# workflow_id :integer
|
11
|
+
# sort_order :integer default("0")
|
12
|
+
# trigger_limit :integer
|
13
|
+
# trigger_type :integer default("0")
|
14
|
+
# created_at :datetime not null
|
15
|
+
# updated_at :datetime not null
|
16
|
+
# form_id :integer
|
17
|
+
# enable_callback :string default("Wf::Callbacks::EnableDefault")
|
18
|
+
# fire_callback :string default("Wf::Callbacks::FireDefault")
|
19
|
+
# notification_callback :string default("Wf::Callbacks::NotificationDefault")
|
20
|
+
# time_callback :string default("Wf::Callbacks::TimeDefault")
|
21
|
+
# deadline_callback :string default("Wf::Callbacks::DeadlineDefault")
|
22
|
+
# hold_timeout_callback :string default("Wf::Callbacks::HoldTimeoutDefault")
|
23
|
+
# assignment_callback :string default("Wf::Callbacks::AssignmentDefault")
|
24
|
+
# unassignment_callback :string default("Wf::Callbacks::UnassignmentDefault")
|
25
|
+
#
|
26
|
+
|
27
|
+
module Wf
|
28
|
+
class Transition < ApplicationRecord
|
29
|
+
belongs_to :workflow, touch: true
|
30
|
+
has_many :arcs
|
31
|
+
has_many :transition_static_assignments
|
32
|
+
has_many :static_parties, through: :transition_static_assignments, source: "party"
|
33
|
+
has_many :workitems
|
34
|
+
belongs_to :form, optional: true
|
35
|
+
|
36
|
+
enum trigger_type: {
|
37
|
+
user: 0,
|
38
|
+
automatic: 1,
|
39
|
+
message: 2,
|
40
|
+
time: 3
|
41
|
+
}
|
42
|
+
|
43
|
+
def explicit_or_split?
|
44
|
+
arcs.out.sum(:guards_count) >= 1
|
45
|
+
end
|
46
|
+
|
47
|
+
validates :name, presence: true
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_transition_static_assignments
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# party_id :integer
|
9
|
+
# transition_id :integer
|
10
|
+
# workflow_id :integer
|
11
|
+
# created_at :datetime not null
|
12
|
+
# updated_at :datetime not null
|
13
|
+
#
|
14
|
+
|
15
|
+
module Wf
|
16
|
+
class TransitionStaticAssignment < ApplicationRecord
|
17
|
+
belongs_to :workflow
|
18
|
+
belongs_to :transition
|
19
|
+
belongs_to :party
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_users
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# name :string
|
9
|
+
# created_at :datetime not null
|
10
|
+
# updated_at :datetime not null
|
11
|
+
# group_id :integer
|
12
|
+
#
|
13
|
+
|
14
|
+
module Wf
|
15
|
+
class User < ApplicationRecord
|
16
|
+
belongs_to :group, optional: true
|
17
|
+
has_one :party, as: :partable
|
18
|
+
|
19
|
+
# NOTICE: group or user or role all has_many users
|
20
|
+
has_many :users, foreign_key: :id
|
21
|
+
|
22
|
+
after_create do
|
23
|
+
create_party(party_name: name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_workflows
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# name :string
|
9
|
+
# description :text
|
10
|
+
# is_valid :boolean default("false")
|
11
|
+
# creator_id :string
|
12
|
+
# error_msg :text
|
13
|
+
# created_at :datetime not null
|
14
|
+
# updated_at :datetime not null
|
15
|
+
#
|
16
|
+
|
17
|
+
module Wf
|
18
|
+
class Workflow < ApplicationRecord
|
19
|
+
has_many :places, dependent: :destroy
|
20
|
+
has_many :transitions, dependent: :destroy
|
21
|
+
has_many :arcs, dependent: :destroy
|
22
|
+
has_many :transition_static_assignments
|
23
|
+
has_many :cases
|
24
|
+
has_many :workitems
|
25
|
+
has_many :tokens
|
26
|
+
|
27
|
+
validates :name, presence: true
|
28
|
+
|
29
|
+
# TODO: move to config
|
30
|
+
def self.enable_callbacks
|
31
|
+
[Wf::Callbacks::EnableDefault]
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.fire_callbacks
|
35
|
+
[Wf::Callbacks::FireDefault]
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.assignment_callbacks
|
39
|
+
[Wf::Callbacks::AssignmentDefault]
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.unassignment_callbacks
|
43
|
+
[Wf::Callbacks::UnassignmentDefault]
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.notification_callbacks
|
47
|
+
[Wf::Callbacks::NotificationDefault]
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.deadline_callbacks
|
51
|
+
[Wf::Callbacks::DeadlineDefault]
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.time_callbacks
|
55
|
+
[Wf::Callbacks::TimeDefault]
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.hold_timeout_callbacks
|
59
|
+
[Wf::Callbacks::HoldTimeoutDefault]
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.user_class
|
63
|
+
::Wf::User
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.org_classes
|
67
|
+
{
|
68
|
+
group: ::Wf::Group
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
after_save do
|
73
|
+
do_validate!
|
74
|
+
end
|
75
|
+
|
76
|
+
after_touch do
|
77
|
+
do_validate!
|
78
|
+
end
|
79
|
+
|
80
|
+
# TODO: can from start place to end place
|
81
|
+
def do_validate!
|
82
|
+
msgs = []
|
83
|
+
msgs << "must have start place" if places.start.blank?
|
84
|
+
msgs << "must have only one start place" if places.start.count > 1
|
85
|
+
msgs << "must have end place" if places.end.blank?
|
86
|
+
msgs << "must have only one end place" if places.end.count > 1
|
87
|
+
if msgs.present?
|
88
|
+
update_columns(is_valid: false, error_msg: msgs.join("\n"))
|
89
|
+
else
|
90
|
+
update_columns(is_valid: true, error_msg: "")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_graph(wf_case = nil)
|
95
|
+
graph = GraphViz.new(name, type: :digraph, rankdir: "LR", splines: true, ratio: :auto)
|
96
|
+
free_token_places = if wf_case
|
97
|
+
wf_case.tokens.free.map(&:place_id)
|
98
|
+
else
|
99
|
+
[]
|
100
|
+
end
|
101
|
+
pg_mapping = {}
|
102
|
+
places.order("place_type ASC").each do |p|
|
103
|
+
if p.start?
|
104
|
+
fillcolor = :yellow
|
105
|
+
shape = :doublecircle
|
106
|
+
elsif p.end?
|
107
|
+
fillcolor = :green
|
108
|
+
shape = :doublecircle
|
109
|
+
else
|
110
|
+
fillcolor = :lightpink
|
111
|
+
shape = :circle
|
112
|
+
end
|
113
|
+
|
114
|
+
token_count = free_token_places.count(p.id)
|
115
|
+
if token_count >= 1
|
116
|
+
label = "•"
|
117
|
+
xlabel = nil
|
118
|
+
fontsize = 25
|
119
|
+
else
|
120
|
+
label = p.name
|
121
|
+
xlabel = nil
|
122
|
+
end
|
123
|
+
|
124
|
+
pg = graph.add_nodes(p.name,
|
125
|
+
label: label,
|
126
|
+
xlabel: xlabel,
|
127
|
+
shape: shape,
|
128
|
+
fixedsize: true,
|
129
|
+
style: :filled,
|
130
|
+
fontsize: fontsize,
|
131
|
+
fillcolor: fillcolor,
|
132
|
+
href: Wf::Engine.routes.url_helpers.edit_workflow_place_path(self, p))
|
133
|
+
pg_mapping[p] = pg
|
134
|
+
end
|
135
|
+
|
136
|
+
tg_mapping = {}
|
137
|
+
transitions.each do |t|
|
138
|
+
tg = graph.add_nodes(t.name, label: t.name, shape: :box, style: :filled, fillcolor: :lightblue, href: Wf::Engine.routes.url_helpers.edit_workflow_transition_path(self, t))
|
139
|
+
tg_mapping[t] = tg
|
140
|
+
end
|
141
|
+
|
142
|
+
arcs.order("direction desc").each do |arc|
|
143
|
+
label = if arc.guards_count > 0
|
144
|
+
arc.guards.map(&:inspect).join(" & ")
|
145
|
+
else
|
146
|
+
""
|
147
|
+
end
|
148
|
+
if arc.in?
|
149
|
+
graph.add_edges(
|
150
|
+
pg_mapping[arc.place],
|
151
|
+
tg_mapping[arc.transition],
|
152
|
+
label: label,
|
153
|
+
weight: 1,
|
154
|
+
labelfloat: false,
|
155
|
+
labelfontcolor: :red,
|
156
|
+
arrowhead: :vee,
|
157
|
+
href: Wf::Engine.routes.url_helpers.edit_workflow_arc_path(self, arc)
|
158
|
+
)
|
159
|
+
else
|
160
|
+
graph.add_edges(
|
161
|
+
tg_mapping[arc.transition],
|
162
|
+
pg_mapping[arc.place],
|
163
|
+
label: label,
|
164
|
+
weight: 1,
|
165
|
+
labelfloat: false,
|
166
|
+
labelfontcolor: :red,
|
167
|
+
arrowhead: :vee,
|
168
|
+
href: Wf::Engine.routes.url_helpers.edit_workflow_arc_path(self, arc)
|
169
|
+
)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
graph
|
173
|
+
end
|
174
|
+
|
175
|
+
def render_graph(wf_case = nil)
|
176
|
+
graph = to_graph(wf_case)
|
177
|
+
path = Rails.root.join("tmp", "#{id}.svg")
|
178
|
+
graph.output(svg: path)
|
179
|
+
File.read(path)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_workitems
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# case_id :integer
|
9
|
+
# workflow_id :integer
|
10
|
+
# transition_id :integer
|
11
|
+
# targetable_type :string
|
12
|
+
# targetable_id :string
|
13
|
+
# state :integer default("0")
|
14
|
+
# enabled_at :datetime
|
15
|
+
# started_at :datetime
|
16
|
+
# canceled_at :datetime
|
17
|
+
# finished_at :datetime
|
18
|
+
# overridden_at :datetime
|
19
|
+
# deadline :datetime
|
20
|
+
# created_at :datetime not null
|
21
|
+
# updated_at :datetime not null
|
22
|
+
# trigger_time :datetime
|
23
|
+
# holding_user_id :string
|
24
|
+
#
|
25
|
+
|
26
|
+
module Wf
|
27
|
+
class Workitem < ApplicationRecord
|
28
|
+
belongs_to :workflow
|
29
|
+
belongs_to :transition
|
30
|
+
belongs_to :case
|
31
|
+
belongs_to :targetable, optional: true
|
32
|
+
belongs_to :holding_user, foreign_key: :holding_user_id, class_name: Workflow.user_class.to_s, optional: true
|
33
|
+
has_many :workitem_assignments
|
34
|
+
has_many :parties, through: :workitem_assignments, source: "party"
|
35
|
+
has_many :comments
|
36
|
+
has_many :entries
|
37
|
+
|
38
|
+
enum state: {
|
39
|
+
enabled: 0,
|
40
|
+
started: 1,
|
41
|
+
canceled: 2,
|
42
|
+
finished: 3,
|
43
|
+
overridden: 4
|
44
|
+
}
|
45
|
+
|
46
|
+
def name
|
47
|
+
"Workitem -> #{id}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# TODO: guards exp && target guards
|
51
|
+
def pass_guard?(arc, has_passed = false)
|
52
|
+
if arc.guards_count == 0
|
53
|
+
!has_passed
|
54
|
+
else
|
55
|
+
entry = entries.where(user: holding_user).first
|
56
|
+
arc.guards.all? { |guard| guard.pass?(entry) }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def started_by?(user)
|
61
|
+
enabled? && owned_by?(user)
|
62
|
+
end
|
63
|
+
|
64
|
+
def finished_by?(user)
|
65
|
+
started? && owned_by?(user) && holding_user == user
|
66
|
+
end
|
67
|
+
|
68
|
+
def owned_by?(user)
|
69
|
+
Wf::Party.joins(workitem_assignments: { workitem: %i[transition case] })
|
70
|
+
.where(Wf::Transition.table_name => { trigger_type: Wf::Transition.trigger_types[:user] })
|
71
|
+
.where(Wf::Case.table_name => { state: Wf::Case.states[:active] })
|
72
|
+
.where(Wf::Workitem.table_name => { state: Wf::Workitem.states.values_at(:started, :enabled) })
|
73
|
+
.where(Wf::Workitem.table_name => { id: id }).map do |party|
|
74
|
+
party.partable.users.to_a
|
75
|
+
end.flatten.include?(user)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# == Schema Information
|
4
|
+
#
|
5
|
+
# Table name: wf_workitem_assignments
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# party_id :integer
|
9
|
+
# workitem_id :integer
|
10
|
+
# created_at :datetime not null
|
11
|
+
# updated_at :datetime not null
|
12
|
+
#
|
13
|
+
|
14
|
+
module Wf
|
15
|
+
class WorkitemAssignment < ApplicationRecord
|
16
|
+
belongs_to :party
|
17
|
+
belongs_to :workitem
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<footer class="footer">
|
2
|
+
<div class="container">
|
3
|
+
<div class="has-text-centered">
|
4
|
+
<p>
|
5
|
+
<strong>
|
6
|
+
<a href="https://github.com/hooopo/petri_flow" target="_blank" rel="nofollow">Petri Flow</a>
|
7
|
+
</strong>
|
8
|
+
crafted by <a href="https://github.com/hooopo" target="_blank" rel="nofollow">Hooopo</a>.
|
9
|
+
The source code is licensed under <a href="http://opensource.org/licenses/mit-license.php">MIT license</a>.
|
10
|
+
</p>
|
11
|
+
</div>
|
12
|
+
</div>
|
13
|
+
</footer>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<nav class="navbar has-shadow" role="navigation" aria-label="main navigation">
|
2
|
+
<div class="container">
|
3
|
+
<div class="navbar-brand">
|
4
|
+
<%= link_to "Petri Flow", root_path, class: "navbar-item" %>
|
5
|
+
</div>
|
6
|
+
|
7
|
+
<div class="navbar-end">
|
8
|
+
<%= link_to current_user&.name, workitems_path %>
|
9
|
+
<%= link_to 'Forms', forms_path, class: "navbar-item #{"is-active" if controller_name == "forms"}" %>
|
10
|
+
<%= link_to 'Workflows', workflows_path, class: "navbar-item #{"is-active" if controller_name.start_with?("workflows")}" %>
|
11
|
+
</div>
|
12
|
+
</div>
|
13
|
+
</nav>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<title>Petri Flow</title>
|
5
|
+
|
6
|
+
<%= csrf_meta_tags %>
|
7
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
8
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
9
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0"/>
|
10
|
+
|
11
|
+
<%= stylesheet_link_tag "wf/application", media: "all", "data-turbolinks-track": "reload" %>
|
12
|
+
<%= javascript_include_tag "wf/application", "data-turbolinks-track": "reload" %>
|
13
|
+
</head>
|
14
|
+
<body>
|
15
|
+
<%= render "layouts/wf/notice" %>
|
16
|
+
<%= render "layouts/wf/alert" %>
|
17
|
+
<%= render "layouts/wf/nav" %>
|
18
|
+
|
19
|
+
<main class="container">
|
20
|
+
<nav aria-label="breadcrumb">
|
21
|
+
<ol class='breadcrumb'>
|
22
|
+
<% breadcrumb_trail do |crumb| %>
|
23
|
+
<li class="breadcrumb-item <%= crumb.current? ? 'active' : '' %>">
|
24
|
+
<%= link_to crumb.name, crumb.url, (crumb.current? ? {'aria-current' => 'page'} : {}) %>
|
25
|
+
</li>
|
26
|
+
<% end %>
|
27
|
+
</ol>
|
28
|
+
</nav>
|
29
|
+
<%= content_for?(:content) ? yield(:content) : yield %>
|
30
|
+
</main>
|
31
|
+
|
32
|
+
<%= render "layouts/wf/footer" %>
|
33
|
+
</body>
|
34
|
+
</html>
|