bumbleworks-gui 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/.gitignore +17 -0
  2. data/.rspec +3 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +5 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +23 -0
  7. data/Rakefile +9 -0
  8. data/bumbleworks-gui.gemspec +31 -0
  9. data/config.ru +39 -0
  10. data/lib/bumbleworks/gui.rb +22 -0
  11. data/lib/bumbleworks/gui/assets/css/application.css +65 -0
  12. data/lib/bumbleworks/gui/assets/css/ruote-fluo.css +62 -0
  13. data/lib/bumbleworks/gui/assets/css/side-menu.css +203 -0
  14. data/lib/bumbleworks/gui/assets/js/application.js +36 -0
  15. data/lib/bumbleworks/gui/assets/js/fluo_helper.js +30 -0
  16. data/lib/bumbleworks/gui/assets/js/foolbox.min.js +3 -0
  17. data/lib/bumbleworks/gui/assets/js/jquery.js +26 -0
  18. data/lib/bumbleworks/gui/assets/js/list.min.js +1 -0
  19. data/lib/bumbleworks/gui/assets/js/list.pagination.min.js +1 -0
  20. data/lib/bumbleworks/gui/assets/js/ruote-fluo.min.js +3 -0
  21. data/lib/bumbleworks/gui/config/application.rb +9 -0
  22. data/lib/bumbleworks/gui/config/routes.rb +18 -0
  23. data/lib/bumbleworks/gui/controllers/application_controller.rb +15 -0
  24. data/lib/bumbleworks/gui/controllers/dashboards_controller.rb +17 -0
  25. data/lib/bumbleworks/gui/controllers/entities_controller.rb +26 -0
  26. data/lib/bumbleworks/gui/controllers/expressions_controller.rb +28 -0
  27. data/lib/bumbleworks/gui/controllers/processes_controller.rb +13 -0
  28. data/lib/bumbleworks/gui/controllers/tasks_controller.rb +13 -0
  29. data/lib/bumbleworks/gui/controllers/trackers_controller.rb +13 -0
  30. data/lib/bumbleworks/gui/version.rb +5 -0
  31. data/lib/bumbleworks/gui/views/dashboards/show.html.erb +21 -0
  32. data/lib/bumbleworks/gui/views/entities/index.html.erb +46 -0
  33. data/lib/bumbleworks/gui/views/entities/show.html.erb +9 -0
  34. data/lib/bumbleworks/gui/views/entities/types.html.erb +3 -0
  35. data/lib/bumbleworks/gui/views/expressions/actions.html.erb +11 -0
  36. data/lib/bumbleworks/gui/views/expressions/show.html.erb +32 -0
  37. data/lib/bumbleworks/gui/views/layouts/default.html.erb +58 -0
  38. data/lib/bumbleworks/gui/views/processes/index.html.erb +3 -0
  39. data/lib/bumbleworks/gui/views/processes/show.html.erb +46 -0
  40. data/lib/bumbleworks/gui/views/shared/entity_types.html.erb +23 -0
  41. data/lib/bumbleworks/gui/views/shared/expressions.html.erb +27 -0
  42. data/lib/bumbleworks/gui/views/shared/list_js_script.html.erb +29 -0
  43. data/lib/bumbleworks/gui/views/shared/processes.html.erb +45 -0
  44. data/lib/bumbleworks/gui/views/shared/tasks.html.erb +28 -0
  45. data/lib/bumbleworks/gui/views/shared/trackers.html.erb +25 -0
  46. data/lib/bumbleworks/gui/views/tasks/index.html.erb +3 -0
  47. data/lib/bumbleworks/gui/views/tasks/show.html.erb +13 -0
  48. data/lib/bumbleworks/gui/views/trackers/index.html.erb +3 -0
  49. data/lib/bumbleworks/gui/views/trackers/show.html.erb +13 -0
  50. data/spec/features/dashboard_display_spec.rb +18 -0
  51. data/spec/features/entity_administration_spec.rb +38 -0
  52. data/spec/features/expression_administration_spec.rb +48 -0
  53. data/spec/features/process_administration_spec.rb +24 -0
  54. data/spec/features/task_administration_spec.rb +22 -0
  55. data/spec/features/tracker_administration_spec.rb +23 -0
  56. data/spec/fixtures/bumbleworks_config.rb +10 -0
  57. data/spec/fixtures/entities/mock_entity.rb +38 -0
  58. data/spec/fixtures/entities/widget.rb +9 -0
  59. data/spec/fixtures/entities/widgety_fidget.rb +5 -0
  60. data/spec/fixtures/participants.rb +3 -0
  61. data/spec/fixtures/participants/naughty_participant.rb +8 -0
  62. data/spec/fixtures/processes/task_process.rb +9 -0
  63. data/spec/fixtures/processes/waiting_process.rb +8 -0
  64. data/spec/spec_helper.rb +41 -0
  65. data/spec/support/drivers/dashboard_detail.rb +5 -0
  66. data/spec/support/drivers/entity_detail.rb +9 -0
  67. data/spec/support/drivers/entity_index.rb +13 -0
  68. data/spec/support/drivers/entity_type_index.rb +11 -0
  69. data/spec/support/drivers/expression_detail.rb +11 -0
  70. data/spec/support/drivers/process_detail.rb +17 -0
  71. data/spec/support/drivers/process_index.rb +11 -0
  72. data/spec/support/drivers/task_detail.rb +5 -0
  73. data/spec/support/drivers/task_index.rb +11 -0
  74. data/spec/support/drivers/tracker_detail.rb +5 -0
  75. data/spec/support/drivers/tracker_index.rb +11 -0
  76. data/spec/support/drivers/window_driver.rb +9 -0
  77. data/spec/support/path_helpers.rb +10 -0
  78. data/spec/support/process_testing_helpers.rb +9 -0
  79. metadata +288 -0
@@ -0,0 +1,3 @@
1
+ <div>
2
+ <%= render 'shared/processes', :locals => { :processes => processes } %>
3
+ </div>
@@ -0,0 +1,46 @@
1
+ <h2><%= process.id %></h2>
2
+
3
+ <div id="fluo"></div>
4
+ <dl>
5
+ <dt>Definition Name</dt>
6
+ <dd><%= process.definition_name %></dd>
7
+
8
+ <dt>Tasks</dt>
9
+ <dd>
10
+ <%= render 'shared/tasks', :locals => { :tasks => process.tasks } %>
11
+ </dd>
12
+
13
+ <% if process.has_entity? && entity = process.entity %>
14
+ <dt>Entity</dt>
15
+ <dd>
16
+ <a href="<%= path_to 'entities_show', :type => entity.class.entity_type, :id => entity.identifier %>"><%= process.entity_name %></a>
17
+ </dd>
18
+ <% end %>
19
+
20
+ <dt>Trackers</dt>
21
+ <dd>
22
+ <%= render 'shared/trackers', :locals => { :trackers => process.trackers } %>
23
+ </dd>
24
+
25
+ <dt>Leaves</dt>
26
+ <dd>
27
+ <%= render 'shared/expressions', :locals => { :expressions => process.leaves } %>
28
+ </dd>
29
+
30
+ <script>
31
+ var Fluos = {
32
+ 'fluo': {
33
+ 'tree': <%= Rufus::Json.encode(process.original_tree) %>,
34
+ 'pins': [
35
+ <% process.leaves.each do |l| %>
36
+ <% if l.error %>
37
+ { 'expid': '<%= l.expid %>', 'type': 'error', 'label': 'er' },
38
+ <% else %>
39
+ { 'expid': '<%= l.expid %>', 'type': 'workitem' },
40
+ <% end %>
41
+ <% end %>
42
+ ]
43
+ }
44
+ }
45
+ </script>
46
+ </dl>
@@ -0,0 +1,23 @@
1
+ <div id="classes">
2
+ <table class="pure-table pure-table-bordered">
3
+ <thead>
4
+ <tr>
5
+ <th class="sort" data-sort="class">Class</th>
6
+ <th class="sort" data-sort="count">Count</th>
7
+ </tr>
8
+ </thead>
9
+ <tbody class="list">
10
+ <% entity_classes.each do |entity_class| %>
11
+ <tr>
12
+ <td class="class"><a href="<%= path_to 'entities_index', :type => entity_class.entity_type %>"><%= Bumbleworks::Support.titleize(entity_class.entity_type) %></a></td>
13
+ <td class="count"><%= entity_class.count %></td>
14
+ </tr>
15
+ <% end %>
16
+ </tbody>
17
+ </table>
18
+ </div>
19
+
20
+ <%= render 'shared/list_js_script', :locals => {
21
+ :list_id => 'classes',
22
+ :rows => entity_classes.count
23
+ } %>
@@ -0,0 +1,27 @@
1
+ <div id="expressions">
2
+ <table class="pure-table pure-table-bordered">
3
+ <thead>
4
+ <tr>
5
+ <th class="sort" data-sort="id">ID</th>
6
+ <th class="sort" data-sort="tree">Expression</th>
7
+ <th class="sort" data-sort="error">Error</th>
8
+ <th></th>
9
+ </tr>
10
+ </thead>
11
+ <tbody class="list">
12
+ <% expressions.each do |exp| %>
13
+ <tr>
14
+ <td class="id"><a href="<%= path_to 'expressions_show', :pid => exp.process.id, :id => exp.expid %>"><%= exp.expid %></a></td>
15
+ <td class="tree"><%= exp.tree %></td>
16
+ <td class="error"><%= exp.error.message if exp.error %></td>
17
+ <td><%= render 'expressions/actions', :locals => { :expression => exp } %></td>
18
+ </tr>
19
+ <% end %>
20
+ </tbody>
21
+ </table>
22
+ </div>
23
+
24
+ <%= render 'shared/list_js_script', :locals => {
25
+ :list_id => 'expressions',
26
+ :rows => expressions.count
27
+ } %>
@@ -0,0 +1,29 @@
1
+ <%
2
+ per_page ||= 10
3
+ pagination = rows > per_page
4
+ %>
5
+
6
+ <script>
7
+ $(document).ready(function() {
8
+
9
+ <% if pagination %>
10
+ var pagDiv = '<div class="pagination pure-menu pure-menu-open pure-menu-horizontal"></div>'
11
+ $('#<%= list_id %>').prepend(pagDiv);
12
+ $('#<%= list_id %>').append(pagDiv);
13
+ $('.pagination').first().prepend('<ul class="paginationTop"></ul>');
14
+ $('.pagination').last().prepend('<ul class="paginationBottom"></ul>');
15
+ <% end %>
16
+
17
+ var <%= list_id %>ListOptions = {
18
+ valueNames: $('#<%= list_id %> th').map(function() { return $(this).data('sort') }),
19
+ page: <%= per_page %>,
20
+ <% if pagination %>
21
+ plugins: [
22
+ ListPagination({name: "paginationTop", paginationClass: 'paginationTop', outerWindow: 1}),
23
+ ListPagination({name: "paginationBottom", paginationClass: 'paginationBottom', outerWindow: 1}),
24
+ ]
25
+ <% end %>
26
+ };
27
+ var <%= list_id %>List = new List('<%= list_id %>', <%= list_id %>ListOptions);
28
+ });
29
+ </script>
@@ -0,0 +1,45 @@
1
+ <% existing_wfids = Bumbleworks.dashboard.process_wfids %>
2
+ <div id="processes">
3
+ <table class="pure-table pure-table-bordered">
4
+ <thead>
5
+ <tr>
6
+ <th class="sort" data-sort="id">ID</th>
7
+ <th class="sort" data-sort="entity">Entity</th>
8
+ <th class="sort" data-sort="definition">Type</th>
9
+ <% if false # see below %>
10
+ <th class="sort" data-sort="subscribed-events">Subscribed Events</th>
11
+ <th class="sort" data-sort="task-count">Tasks</th>
12
+ <th class="sort" data-sort="error-count">Errors</th>
13
+ <th class="sort" data-sort="tracker-count">Trackers</th>
14
+ <% end %>
15
+ </tr>
16
+ </thead>
17
+ <tbody class="list">
18
+ <% processes.each do |process| %>
19
+ <% if existing_wfids.include?(process.id) %>
20
+ <tr>
21
+ <td class="id"><a href="<%= path_to 'processes_show', :id => process.id %>"><%= process.id %></a></td>
22
+ <td class="entity"><%= process.entity_name %></td>
23
+ <td class="definition"><%= process.definition_name %></td>
24
+ <% if false # need optimization before these will work %>
25
+ <td class="subscribed-events"><%= process.subscribed_events %></td>
26
+ <td class="task-count"><%= process.tasks.count %></td>
27
+ <td class="error-count"><%= process.errors.count %></td>
28
+ <td class="tracker-count"><%= process.trackers.count %></td>
29
+ <% end %>
30
+ </tr>
31
+ <% else %>
32
+ <tr>
33
+ <td colspan="3"><em>Process <%= process.id %> no longer exists.</em></td>
34
+ </tr>
35
+ <% end %>
36
+ <% end %>
37
+ </tbody>
38
+ </table>
39
+ </div>
40
+
41
+ <%= render 'shared/list_js_script', :locals => {
42
+ :list_id => 'processes',
43
+ :rows => processes.count
44
+ } %>
45
+
@@ -0,0 +1,28 @@
1
+ <div id="tasks">
2
+ <table class="pure-table pure-table-bordered">
3
+ <thead>
4
+ <tr>
5
+ <th class="sort" data-sort="id">ID</th>
6
+ <th class="sort" data-sort="name">Name</th>
7
+ <th class="sort" data-sort="role">Role</th>
8
+ <th class="sort" data-sort="claimant">Claimant</th>
9
+ </tr>
10
+ </thead>
11
+ <tbody class="list">
12
+ <% tasks.each do |task| %>
13
+ <tr>
14
+ <td class="id"><a href="<%= path_to 'tasks_show', :id => task.id %>"><%= task.id %></a></td>
15
+ <td class="name"><%= task.to_s %></td>
16
+ <td class="role"><%= task.role %></td>
17
+ <td class="claimant"><%= task.claimant %></td>
18
+ </tr>
19
+ <% end %>
20
+ </tbody>
21
+ </table>
22
+ </div>
23
+
24
+
25
+ <%= render 'shared/list_js_script', :locals => {
26
+ :list_id => 'tasks',
27
+ :rows => tasks.count
28
+ } %>
@@ -0,0 +1,25 @@
1
+ <div id="trackers">
2
+ <table class="pure-table pure-table-bordered">
3
+ <thead>
4
+ <tr>
5
+ <th class="sort" data-sort="id">ID</th>
6
+ <th class="sort" data-sort="action">Action</th>
7
+ <th class="sort" data-sort="conditions">Conditions</th>
8
+ </tr>
9
+ </thead>
10
+ <tbody class="list">
11
+ <% trackers.each do |tracker| %>
12
+ <tr>
13
+ <td class="id"><a href="<%= path_to 'trackers_show', :id => tracker.id %>"><%= tracker.id %></a></td>
14
+ <td class="action"><%= tracker.action %></td>
15
+ <td class="conditions"><%= tracker.conditions %></td>
16
+ </tr>
17
+ <% end %>
18
+ </tbody>
19
+ </table>
20
+ </div>
21
+
22
+ <%= render 'shared/list_js_script', :locals => {
23
+ :list_id => 'trackers',
24
+ :rows => trackers.count
25
+ } %>
@@ -0,0 +1,3 @@
1
+ <div>
2
+ <%= render 'shared/tasks', :locals => { :tasks => tasks } %>
3
+ </div>
@@ -0,0 +1,13 @@
1
+ <dl>
2
+ <dt>ID</dt>
3
+ <dd><%= task.id %></dd>
4
+
5
+ <dt>Process</dt>
6
+ <dd><a href="<%= path_to 'processes_show', :id => task.wfid %>"><%= task.wfid %></a></dd>
7
+
8
+ <dt>Role</dt>
9
+ <dd><%= task.role %></dd>
10
+
11
+ <dt>Claimant</dt>
12
+ <dd><%= task.claimant || '<em>unclaimed</em>' %></dd>
13
+ </dl>
@@ -0,0 +1,3 @@
1
+ <div>
2
+ <%= render 'shared/trackers', :locals => { :trackers => trackers} %>
3
+ </div>
@@ -0,0 +1,13 @@
1
+ <dl>
2
+ <dt>ID</dt>
3
+ <dd><%= tracker.id %></dd>
4
+
5
+ <dt>Process</dt>
6
+ <dd><a href="<%= path_to 'processes_show', :id => tracker.wfid %>"><%= tracker.wfid %></a></dd>
7
+
8
+ <dt>Expressions</dt>
9
+ <dd><%= tracker.waiting_expression %></dd>
10
+
11
+ <dt>Original Hash</dt>
12
+ <dd><%= tracker.original_hash %></dd>
13
+ </dl>
@@ -0,0 +1,18 @@
1
+ feature "Dashboard display" do
2
+ let(:dashboard_detail) { DashboardDetail.new(Capybara) }
3
+
4
+ scenario "Admin views dashboard" do
5
+ process1 = Bumbleworks.launch!('task_process')
6
+ process2 = Bumbleworks.launch!('waiting_process')
7
+ wait_until {
8
+ process1.tasks.count == 2 &&
9
+ process2.reload.trackers.count == 4
10
+ }
11
+
12
+ visit_scoped '/'
13
+
14
+ expect(dashboard_detail).to have_count_of(Bumbleworks::Process.all)
15
+ expect(dashboard_detail).to have_count_of(Bumbleworks::Task.all)
16
+ expect(dashboard_detail).to have_count_of(Bumbleworks::Tracker.all)
17
+ end
18
+ end
@@ -0,0 +1,38 @@
1
+ feature "Entity management" do
2
+ let(:entity_index) { EntityIndex.new(Capybara) }
3
+ let(:entity_detail) { EntityDetail.new(Capybara) }
4
+ let(:entity_type_index) { EntityTypeIndex.new(Capybara) }
5
+
6
+ before(:each) do
7
+ Widget.truncate!
8
+ WidgetyFidget.truncate!
9
+ @widgets = [Widget.new(12), Widget.new(38), Widget.new(5)]
10
+ @widgety_fidgets = [WidgetyFidget.new(5), WidgetyFidget.new(3)]
11
+ end
12
+
13
+ scenario "Admin views entity index" do
14
+ visit_scoped '/entities'
15
+
16
+ expect(entity_index.entity_count('Widget')).to eq 3
17
+ expect(entity_index.entity_count('Widgety Fidget')).to eq 2
18
+ end
19
+
20
+ scenario "Admin views index for entity type" do
21
+ visit_scoped '/entities/widget'
22
+
23
+ expect(entity_type_index).to have_entities(@widgets)
24
+ expect(entity_type_index).not_to have_entities(@widgety_fidgets)
25
+ expect(entity_type_index).to have_registered_process('task_process')
26
+ end
27
+
28
+ scenario "Admin views entity detail" do
29
+ widget = @widgets.first
30
+ process = widget.launch_process('task_process')
31
+ wait_until { process.tasks.count == 2 }
32
+
33
+ visit_scoped "/entities/widget/#{widget.identifier}"
34
+
35
+ expect(entity_detail).to have_entity(widget)
36
+ expect(entity_detail).to have_process(process)
37
+ end
38
+ end
@@ -0,0 +1,48 @@
1
+ feature "Expression administration" do
2
+ let(:expression_detail) { ExpressionDetail.new(Capybara) }
3
+ let(:process_detail) { ProcessDetail.new(Capybara) }
4
+ let(:process) {
5
+ process = Bumbleworks.launch!('task_process')
6
+ wait_until { process.reload.tasks.count == 2 }
7
+ process
8
+ }
9
+ let(:error_expression) {
10
+ process.tasks.each { |t| t.complete }
11
+ wait_until { process.reload.leaves.first.error }
12
+ process.leaves.first
13
+ }
14
+
15
+ scenario "Admin views expression" do
16
+ expression = process.leaves.first
17
+
18
+ visit_scoped "/processes/#{process.id}/expressions/#{expression.expid}"
19
+
20
+ expect(expression_detail).to have_expression(expression)
21
+ end
22
+
23
+ scenario "Admin cancels expression" do
24
+ expression = process.leaves.first
25
+
26
+ visit_scoped "/processes/#{process.id}/expressions/#{expression.expid}"
27
+ click_button 'Cancel'
28
+
29
+ wait_until { process.reload.tasks.count == 1 }
30
+ visit_scoped "/processes/#{process.id}"
31
+ expect(process_detail).not_to have_expression(expression)
32
+ end
33
+
34
+ scenario "Admin kills expression" do
35
+ visit_scoped "/processes/#{process.id}/expressions/#{error_expression.expid}"
36
+ click_button 'Kill'
37
+
38
+ wait_until { process.reload.errors.empty? }
39
+ visit_scoped "/processes/#{process.id}"
40
+ expect(process_detail).not_to have_error(NaughtyParticipant::StupidError.new("Oh crumb."))
41
+ end
42
+
43
+ scenario "Admin views expression errors" do
44
+ visit_scoped "/processes/#{process.id}/expressions/#{error_expression.expid}"
45
+
46
+ expect(expression_detail).to have_error(NaughtyParticipant::StupidError.new("Oh crumb."))
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ feature "Process management" do
2
+ let(:process_index) { ProcessIndex.new(Capybara) }
3
+ let(:process_detail) { ProcessDetail.new(Capybara) }
4
+
5
+ scenario "Admin views process index" do
6
+ process1 = Bumbleworks.launch!('task_process', :entity => Widget.new(41))
7
+ process2 = Bumbleworks.launch!('task_process')
8
+ wait_until { process1.tasks.count == 2 && process2.tasks.count == 2 }
9
+
10
+ visit_scoped '/processes'
11
+
12
+ expect(process_index).to have_processes([process1, process2])
13
+ end
14
+
15
+ scenario "Admin views process detail" do
16
+ process = Bumbleworks.launch!('task_process', :entity => Widget.new(56))
17
+ wait_until { process.tasks.count == 2 }
18
+
19
+ visit_scoped "/processes/#{process.id}"
20
+
21
+ expect(process_detail).to have_process(process)
22
+ expect(process_detail).to have_entity(Widget.new(56))
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ feature "Task management" do
2
+ let(:task_index) { TaskIndex.new(Capybara) }
3
+ let(:task_detail) { TaskDetail.new(Capybara) }
4
+
5
+ scenario "Admin views task index" do
6
+ process = Bumbleworks.launch!('task_process')
7
+ wait_until { process.tasks.count == 2 }
8
+
9
+ visit_scoped '/tasks'
10
+
11
+ expect(task_index).to have_tasks(process.tasks.all)
12
+ end
13
+
14
+ scenario "Admin views task detail" do
15
+ process = Bumbleworks.launch!('task_process')
16
+ task = process.tasks.next_available
17
+
18
+ visit_scoped "/tasks/#{task.id}"
19
+
20
+ expect(task_detail).to have_task(task)
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ feature "Tracker management" do
2
+ let(:tracker_index) { TrackerIndex.new(Capybara) }
3
+ let(:tracker_detail) { TrackerDetail.new(Capybara) }
4
+
5
+ scenario "Admin views tracker index" do
6
+ process1 = Bumbleworks.launch!('waiting_process')
7
+ process2 = Bumbleworks.launch!('waiting_process')
8
+ wait_until { process1.reload.trackers.count == 4 && process2.reload.trackers.count == 4 }
9
+ visit_scoped '/trackers'
10
+
11
+ expect(tracker_index).to have_trackers(process1.trackers + process2.trackers)
12
+ end
13
+
14
+ scenario "Admin views tracker detail" do
15
+ process = Bumbleworks.launch!('waiting_process')
16
+ wait_until { process.reload.trackers.count == 4 }
17
+ tracker = process.trackers.first
18
+
19
+ visit_scoped "/trackers/#{tracker.id}"
20
+
21
+ expect(tracker_detail).to have_tracker(tracker)
22
+ end
23
+ end