workflowable 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.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +202 -0
  3. data/README.md +23 -0
  4. data/Rakefile +39 -0
  5. data/app/assets/images/workflowable/select2-spinner.gif +0 -0
  6. data/app/assets/images/workflowable/select2.png +0 -0
  7. data/app/assets/images/workflowable/select2x2.png +0 -0
  8. data/app/assets/javascripts/workflowable/application.js +118 -0
  9. data/app/assets/javascripts/workflowable/d3.min.js +5 -0
  10. data/app/assets/javascripts/workflowable/dagre-min.js +2 -0
  11. data/app/assets/javascripts/workflowable/foundation/fastclick.js +9 -0
  12. data/app/assets/javascripts/workflowable/foundation/foundation.min.js +10 -0
  13. data/app/assets/javascripts/workflowable/foundation/modernizr.js +8 -0
  14. data/app/assets/javascripts/workflowable/foundation/placeholder.js +2 -0
  15. data/app/assets/javascripts/workflowable/select2.min.js +22 -0
  16. data/app/assets/javascripts/workflowable/workflow.js +2 -0
  17. data/app/assets/stylesheets/workflowable/application.css +26 -0
  18. data/app/assets/stylesheets/workflowable/dagre-d3.css +19 -0
  19. data/app/assets/stylesheets/workflowable/foundation/foundation.min.css +1 -0
  20. data/app/assets/stylesheets/workflowable/foundation/normalize.css +423 -0
  21. data/app/assets/stylesheets/workflowable/select2.css +646 -0
  22. data/app/assets/stylesheets/workflowable/workflow.css +4 -0
  23. data/app/controllers/workflowable/actions_controller.rb +35 -0
  24. data/app/controllers/workflowable/application_controller.rb +18 -0
  25. data/app/controllers/workflowable/workflows_controller.rb +137 -0
  26. data/app/helpers/workflowable/application_helper.rb +19 -0
  27. data/app/helpers/workflowable/workflow_helper.rb +19 -0
  28. data/app/models/workflowable/action.rb +113 -0
  29. data/app/models/workflowable/stage.rb +104 -0
  30. data/app/models/workflowable/stage_action.rb +24 -0
  31. data/app/models/workflowable/stage_next_step.rb +21 -0
  32. data/app/models/workflowable/workflow.rb +57 -0
  33. data/app/models/workflowable/workflow_action.rb +23 -0
  34. data/app/views/layouts/workflowable/application.html.erb +24 -0
  35. data/app/views/shared/actions/_details.html.erb +30 -0
  36. data/app/views/shared/actions/_fields.html.erb +26 -0
  37. data/app/views/workflowable/actions/_options.html.erb +39 -0
  38. data/app/views/workflowable/actions/options.js.erb +2 -0
  39. data/app/views/workflowable/workflows/_form.html.erb +57 -0
  40. data/app/views/workflowable/workflows/configure_stages.html.erb +34 -0
  41. data/app/views/workflowable/workflows/edit.html.erb +2 -0
  42. data/app/views/workflowable/workflows/index.html.erb +16 -0
  43. data/app/views/workflowable/workflows/new.html.erb +2 -0
  44. data/app/views/workflowable/workflows/show.html.erb +49 -0
  45. data/app/views/workflowable/workflows/stages.json.jbuilder +8 -0
  46. data/config/routes.rb +34 -0
  47. data/db/migrate/20140406195941_create_workflowable_workflows.rb +25 -0
  48. data/db/migrate/20140407170846_create_workflowable_stages.rb +25 -0
  49. data/db/migrate/20140407184821_rename_workflow_initial_stage_to_initial_stage_id.rb +20 -0
  50. data/db/migrate/20140407191620_create_workflowable_stage_next_steps.rb +25 -0
  51. data/db/migrate/20140407193057_create_workflowable_stage_actions.rb +26 -0
  52. data/db/migrate/20140407194247_create_workflowable_actions.rb +26 -0
  53. data/db/migrate/20140408164900_create_workflowable_workflow_actions.rb +25 -0
  54. data/db/migrate/20140708173311_add_order_to_action.rb +20 -0
  55. data/db/migrate/20140818062426_add_position_to_stage_action.rb +20 -0
  56. data/lib/tasks/workflowable_tasks.rake +4 -0
  57. data/lib/workflowable.rb +26 -0
  58. data/lib/workflowable/actions/action.rb +76 -0
  59. data/lib/workflowable/engine.rb +47 -0
  60. data/lib/workflowable/model_additions.rb +152 -0
  61. data/lib/workflowable/railtie.rb +25 -0
  62. data/lib/workflowable/version.rb +18 -0
  63. metadata +301 -0
@@ -0,0 +1,25 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ class CreateWorkflowableWorkflows < ActiveRecord::Migration
17
+ def change
18
+ create_table :workflowable_workflows do |t|
19
+ t.string :name
20
+ t.integer :initial_stage
21
+
22
+ t.timestamps
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ class CreateWorkflowableStages < ActiveRecord::Migration
17
+ def change
18
+ create_table :workflowable_stages do |t|
19
+ t.string :name
20
+ t.references :workflow, index: true
21
+
22
+ t.timestamps
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ class RenameWorkflowInitialStageToInitialStageId < ActiveRecord::Migration
17
+ def change
18
+ rename_column :workflowable_workflows, :initial_stage, :initial_stage_id
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ class CreateWorkflowableStageNextSteps < ActiveRecord::Migration
17
+ def change
18
+ create_table :workflowable_stage_next_steps do |t|
19
+ t.integer :current_stage_id
20
+ t.integer :next_stage_id
21
+
22
+ t.timestamps
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ class CreateWorkflowableStageActions < ActiveRecord::Migration
17
+ def change
18
+ create_table :workflowable_stage_actions do |t|
19
+ t.references :stage, index: true
20
+ t.references :action, index: true
21
+ t.string :event
22
+
23
+ t.timestamps
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ class CreateWorkflowableActions < ActiveRecord::Migration
17
+ def change
18
+ create_table :workflowable_actions do |t|
19
+ t.string :name
20
+ t.text :options
21
+ t.string :action_plugin
22
+
23
+ t.timestamps
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ class CreateWorkflowableWorkflowActions < ActiveRecord::Migration
17
+ def change
18
+ create_table :workflowable_workflow_actions do |t|
19
+ t.references :workflow, index: true
20
+ t.references :action, index: true
21
+
22
+ t.timestamps
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ class AddOrderToAction < ActiveRecord::Migration
17
+ def change
18
+ add_column :workflowable_actions, :position, :integer
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ class AddPositionToStageAction < ActiveRecord::Migration
17
+ def change
18
+ add_column :workflowable_stage_actions, :position, :integer
19
+ end
20
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :workflowable do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,26 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ #require 'workflow/workflowable'
17
+ require 'rails'
18
+ require "workflowable/engine"
19
+ require "workflowable/model_additions"
20
+ require "workflowable/railtie" if defined? Rails
21
+
22
+ module Workflowable
23
+
24
+
25
+
26
+ end
@@ -0,0 +1,76 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ module Workflowable
17
+ module Actions
18
+ class Action
19
+ NAME = ""
20
+ OPTIONS = {}
21
+
22
+ def initialize(options={}, workflow=nil, object=nil, current_stage=nil, next_stage=nil, user=nil)
23
+ options ||={}
24
+ @options = options.with_indifferent_access
25
+ @workflow = workflow
26
+ @object = object
27
+ @current_stage = current_stage
28
+ @next_stage = next_stage
29
+ @user = user
30
+
31
+ errors = validate_options
32
+
33
+ if(errors.present?)
34
+ return errors
35
+ end
36
+
37
+ end
38
+
39
+ def run
40
+
41
+ end
42
+
43
+ def self.autocomplete(field_type=nil, value=nil, options={}, workflow=nil, object=nil, current_stage=nil, next_stage=nil, user=nil)
44
+ end
45
+
46
+ def self.name
47
+ return self::NAME
48
+ end
49
+
50
+ def self.options(options={}, workflow=nil, object=nil, current_stage=nil, next_stage=nil, user=nil)
51
+
52
+ return self::OPTIONS.with_indifferent_access.deep_merge(options)
53
+ end
54
+
55
+ def validate_options
56
+ errors = []
57
+ current_options = self.class.options(@options, @workflow, @object, @current_stage, @next_stage, @user)
58
+ begin
59
+
60
+ @options.assert_valid_keys(current_options.keys)
61
+ rescue ArgumentError=>e
62
+ errors << "#{e.message} for action: #{self.class.name}\n"
63
+ end
64
+
65
+ missing_keys = current_options.reject{|k,v| v[:required] != true }.keys - @options.reject{|k,v| v[:value].blank? }.keys
66
+
67
+ missing_keys.each do |k|
68
+ errors << "#{k} is required\n"
69
+ end
70
+
71
+ return errors.blank? ? nil : errors
72
+ end
73
+
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,47 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require 'rubygems'
17
+ require 'rails'
18
+ require 'jquery-rails'
19
+ require 'jbuilder'
20
+ require 'nested_form'
21
+
22
+
23
+ module Workflowable
24
+ class Engine < ::Rails::Engine
25
+ isolate_namespace Workflowable
26
+
27
+
28
+ config.to_prepare do
29
+ Dir[File.dirname(__FILE__)+ "/actions/*.rb"].each {|file| require file }
30
+ Dir[Rails.root + "lib/workflowable/actions/*.rb"].each {|file| require file } if Rails.root
31
+ end
32
+
33
+
34
+ config.generators do |g|
35
+ g.test_framework :rspec
36
+ g.fixture_replacement :factory_girl, :dir => 'spec/support/factories'
37
+ end
38
+
39
+ end
40
+ end
41
+
42
+
43
+
44
+
45
+
46
+
47
+ #ActiveRecord::Base.send :include, Workflowable::Workflow
@@ -0,0 +1,152 @@
1
+ # Copyright 2014 Netflix, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require 'active_record/railtie'
17
+ require 'active_support/core_ext'
18
+
19
+ module Workflowable
20
+ module ModelAdditions
21
+ #extend ActiveSupport::Concern
22
+
23
+ def self.included(base)
24
+ base.extend ClassMethods
25
+ end
26
+
27
+ module ClassMethods
28
+ def acts_as_workflowable
29
+ include Workflowable::ModelAdditions::LocalInstanceMethods
30
+ class_eval do
31
+ attr_accessor :workflow_options
32
+ attr_accessor :current_user
33
+
34
+ belongs_to :workflow, :class_name => "Workflowable::Workflow"
35
+ belongs_to :stage, :class_name => "Workflowable::Stage"
36
+ before_save :set_default_stage
37
+
38
+ end
39
+ end
40
+ end
41
+
42
+ module LocalInstanceMethods
43
+
44
+
45
+
46
+
47
+ def next_step_options(next_step, options={}, user=nil, unspecified_only=false)
48
+ options ||= {}
49
+
50
+ if(user.nil? && defined? current_user)
51
+ user = current_user
52
+ end
53
+
54
+
55
+
56
+ if(stage)
57
+ next_stage = stage.next_steps.find_by_id(next_step)
58
+ else
59
+ next_stage = workflow.stages.find_by_id(next_step)
60
+ end
61
+
62
+ if(next_stage)
63
+ next_stage_options = {}
64
+ next_stage_options[:global] = workflow.workflow_action_options(options[:global], self, self.stage, next_stage, user)
65
+ next_stage_options[:before] = next_stage.run_before_options(options[:before], self, self.stage, user)
66
+ next_stage_options[:after] = stage.run_after_options(options[:after], self, next_stage, user) if stage
67
+ return next_stage_options
68
+
69
+ else
70
+ return nil
71
+ end
72
+
73
+ end
74
+
75
+
76
+
77
+ def validate_actions(stage_id, options={}, user=nil)
78
+ options ||= {}
79
+ errors=[]
80
+
81
+ if(user.nil? && defined? current_user)
82
+ user = current_user
83
+ end
84
+
85
+ if(stage)
86
+ new_stage = stage.next_steps.find_by_id(stage_id)
87
+ else
88
+ new_stage = workflow.stages.find_by_id(stage_id)
89
+ end
90
+
91
+ if(new_stage)
92
+ workflow_errors = workflow.validate_action_options(options[:global], self, self.stage, new_stage, user)
93
+ after_errors = stage.present? ? stage.validate_after_actions(options[:after], self, new_stage, user) : nil
94
+ before_errors = new_stage.validate_before_actions(options[:before], self, self.stage, user)
95
+ errors << workflow_errors if workflow_errors.present?
96
+ errors << after_errors if after_errors.present?
97
+ errors << before_errors if before_errors.present?
98
+
99
+ if(errors.present?)
100
+ return errors
101
+ end
102
+ return nil
103
+ else
104
+ return errors + ["Could not identify next stage"]
105
+ end
106
+
107
+ end
108
+
109
+ def set_stage(stage_id, options={}, user=nil)
110
+ options ||= {}
111
+ errors=[]
112
+ if(user.nil? && defined? current_user)
113
+ user = current_user
114
+ end
115
+
116
+ errors = validate_actions(stage_id, options, user)
117
+
118
+ if(errors.present?)
119
+ return errors
120
+ end
121
+
122
+ if(stage)
123
+ new_stage = stage.next_steps.find_by_id(stage_id)
124
+ else
125
+ new_stage = workflow.stages.find_by_id(stage_id)
126
+ end
127
+
128
+ if(new_stage)
129
+
130
+ workflow.run_workflow_actions(options[:global], self, self.stage, new_stage, user)
131
+ stage.run_after_actions(options[:after], self, new_stage, user) if stage
132
+ new_stage.run_before_actions(options[:before], self, self.stage, user)
133
+ update_attributes(stage_id: new_stage.id)
134
+ return true
135
+ end
136
+ end
137
+
138
+
139
+
140
+ private
141
+
142
+ def set_default_stage
143
+ self.set_stage(workflow.initial_stage_id, self.workflow_options) if (workflow && workflow.initial_stage_id && self.stage.blank?)
144
+ #self.stage_id = workflow.initial_stage_id
145
+
146
+ end
147
+
148
+
149
+
150
+ end
151
+ end
152
+ end