workflowable 1.0

Sign up to get free protection for your applications and to get access to all the features.
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