rocketjob_mission_control 2.1.1 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/app/assets/stylesheets/rocket_job_mission_control/callout.scss +1 -1
  4. data/app/assets/stylesheets/rocket_job_mission_control/worker_processes.scss +2 -2
  5. data/app/controllers/rocket_job_mission_control/active_workers_controller.rb +15 -0
  6. data/app/controllers/rocket_job_mission_control/dirmon_entries/index_filters_controller.rb +8 -13
  7. data/app/controllers/rocket_job_mission_control/dirmon_entries_controller.rb +3 -14
  8. data/app/controllers/rocket_job_mission_control/jobs/failures_controller.rb +6 -11
  9. data/app/controllers/rocket_job_mission_control/jobs/index_filters_controller.rb +35 -14
  10. data/app/controllers/rocket_job_mission_control/jobs_controller.rb +12 -15
  11. data/app/controllers/rocket_job_mission_control/servers/index_filters_controller.rb +49 -0
  12. data/app/controllers/rocket_job_mission_control/servers_controller.rb +93 -0
  13. data/app/datatables/rocket_job_mission_control/abstract_datatable.rb +62 -0
  14. data/app/datatables/rocket_job_mission_control/active_workers_datatable.rb +47 -0
  15. data/app/datatables/rocket_job_mission_control/completed_jobs_datatable.rb +1 -1
  16. data/app/datatables/rocket_job_mission_control/dirmon_entries_datatable.rb +10 -72
  17. data/app/datatables/rocket_job_mission_control/interrupted_jobs_datatable.rb +1 -1
  18. data/app/datatables/rocket_job_mission_control/jobs_datatable.rb +16 -91
  19. data/app/datatables/rocket_job_mission_control/queued_jobs_datatable.rb +1 -1
  20. data/app/datatables/rocket_job_mission_control/running_jobs_datatable.rb +23 -12
  21. data/app/datatables/rocket_job_mission_control/scheduled_jobs_datatable.rb +1 -1
  22. data/app/datatables/rocket_job_mission_control/servers_datatable.rb +67 -0
  23. data/app/helpers/rocket_job_mission_control/{workers_helper.rb → servers_helper.rb} +9 -9
  24. data/app/models/job_failures.rb +3 -16
  25. data/app/models/rocket_job_mission_control/query.rb +51 -0
  26. data/app/views/layouts/rocket_job_mission_control/partials/_header.html.haml +3 -3
  27. data/app/views/layouts/rocket_job_mission_control/partials/_sidebar.html.haml +2 -2
  28. data/app/views/rocket_job_mission_control/{active_processes → active_workers}/index.html.haml +3 -3
  29. data/app/views/rocket_job_mission_control/dirmon_entries/_properties.html.haml +7 -18
  30. data/app/views/rocket_job_mission_control/dirmon_entries/_status.html.haml +0 -5
  31. data/app/views/rocket_job_mission_control/dirmon_entries/show.html.haml +4 -3
  32. data/app/views/rocket_job_mission_control/jobs/_status.html.haml +22 -17
  33. data/app/views/rocket_job_mission_control/jobs/edit.html.haml +1 -1
  34. data/app/views/rocket_job_mission_control/jobs/exceptions.html.haml +29 -0
  35. data/app/views/rocket_job_mission_control/jobs/failures/index.html.haml +7 -7
  36. data/app/views/rocket_job_mission_control/jobs/show.html.haml +23 -11
  37. data/app/views/rocket_job_mission_control/servers/_actions.html.haml +9 -0
  38. data/app/views/rocket_job_mission_control/servers/_sidebar.html.haml +20 -0
  39. data/app/views/rocket_job_mission_control/{workers → servers}/index.html.haml +9 -9
  40. data/app/views/rocket_job_mission_control/{workers → servers}/index_filters/paused.html.haml +8 -8
  41. data/app/views/rocket_job_mission_control/{workers → servers}/index_filters/running.html.haml +8 -8
  42. data/app/views/rocket_job_mission_control/{workers → servers}/index_filters/starting.html.haml +8 -8
  43. data/app/views/rocket_job_mission_control/{workers → servers}/index_filters/stopping.html.haml +8 -8
  44. data/config/locales/en.yml +2 -2
  45. data/config/routes.rb +7 -6
  46. data/lib/rocket_job_mission_control/engine.rb +0 -12
  47. data/lib/rocket_job_mission_control/version.rb +1 -1
  48. data/spec/controllers/dirmon_entries/index_filters_controller_spec.rb +2 -4
  49. data/spec/controllers/dirmon_entries_controller_spec.rb +15 -72
  50. data/spec/controllers/jobs/index_filters_controller_spec.rb +1 -1
  51. data/spec/controllers/workers/index_filters_controller_spec.rb +9 -9
  52. data/spec/controllers/workers_controller_spec.rb +47 -47
  53. data/spec/dummy/config/mongoid.yml +88 -0
  54. data/spec/dummy/config/symmetric-encryption.yml +8 -0
  55. data/spec/dummy/log/test.log +89072 -0
  56. data/spec/helpers/servers_helper_spec.rb +16 -0
  57. data/spec/spec_helper.rb +3 -0
  58. metadata +31 -45
  59. data/app/controllers/rocket_job_mission_control/active_processes_controller.rb +0 -27
  60. data/app/controllers/rocket_job_mission_control/workers/index_filters_controller.rb +0 -50
  61. data/app/controllers/rocket_job_mission_control/workers_controller.rb +0 -93
  62. data/app/datatables/rocket_job_mission_control/active_processes_datatable.rb +0 -79
  63. data/app/datatables/rocket_job_mission_control/workers_datatable.rb +0 -127
  64. data/app/interactors/rocket_job_mission_control/dirmon_entries/search.rb +0 -19
  65. data/app/interactors/rocket_job_mission_control/jobs/search.rb +0 -19
  66. data/app/interactors/rocket_job_mission_control/workers/search.rb +0 -19
  67. data/app/views/rocket_job_mission_control/workers/_actions.html.haml +0 -9
  68. data/app/views/rocket_job_mission_control/workers/_sidebar.html.haml +0 -20
  69. data/spec/dummy/config/mongo.yml +0 -15
  70. data/spec/helpers/workers_helper_spec.rb +0 -16
  71. data/spec/interactors/jobs/search_spec.rb +0 -35
@@ -1,21 +1,21 @@
1
1
  module RocketJobMissionControl
2
- module WorkersHelper
3
- def worker_counts_by_state(state)
4
- RocketJob::Worker.counts_by_state.fetch(state.downcase.to_sym, 0)
2
+ module ServersHelper
3
+ def server_counts_by_state(state)
4
+ RocketJob::Server.counts_by_state.fetch(state.downcase.to_sym, 0)
5
5
  end
6
6
 
7
- def worker_icon(worker)
7
+ def server_icon(server)
8
8
  state =
9
- if worker.zombie?
9
+ if server.zombie?
10
10
  'zombie'
11
11
  else
12
- worker.state
12
+ server.state
13
13
  end
14
14
  state_icon(state)
15
15
  end
16
16
 
17
- def worker_card_class(worker)
18
- if worker.zombie?
17
+ def server_card_class(server)
18
+ if server.zombie?
19
19
  'callout-zombie'
20
20
  else
21
21
  map = {
@@ -23,7 +23,7 @@ module RocketJobMissionControl
23
23
  paused: 'callout-warning',
24
24
  stopping: 'callout-alert',
25
25
  }
26
- map[worker.state] || 'callout-info'
26
+ map[server.state] || 'callout-info'
27
27
  end
28
28
  end
29
29
  end
@@ -10,24 +10,11 @@ class JobFailures
10
10
  end
11
11
 
12
12
  def list
13
- @slice_errors ||= job.input.collection.aggregate(
14
- [
15
- {
16
- '$match' => {state: 'failed'}
17
- },
18
- {
19
- '$group' => {
20
- _id: {error_class: '$exception.class_name'},
21
- messages: {'$addToSet' => '$exception.message'},
22
- count: {'$sum' => 1}
23
- },
24
- }
25
- ]
26
- )
13
+ @slice_errors ||= job.input.group_exceptions
27
14
  end
28
15
 
29
16
  def for_error(error_type, page_offset=0)
30
- query = {'state' => 'failed', 'exception.class_name' => error_type}
31
- @job.input.collection.find(query).limit(1).skip(page_offset)
17
+ query = {'exception.class_name' => error_type}
18
+ job.input.failed.where(query).limit(1).skip(page_offset).first
32
19
  end
33
20
  end
@@ -0,0 +1,51 @@
1
+ module RocketJobMissionControl
2
+ class Query
3
+ attr_reader :scope, :default_order
4
+ attr_accessor :search_term, :order_by, :search_term, :start, :page_size,
5
+ :search_columns, :display_columns
6
+
7
+ def initialize(scope, default_order = {})
8
+ @scope = scope
9
+ @order_by = @default_order = default_order
10
+ @search_columns = []
11
+ @display_columns = []
12
+ end
13
+
14
+ # Returns the filtered query expression
15
+ def unsorted_query
16
+ records = scope
17
+ # Text Search
18
+ if search_term
19
+ escaped = Regexp.escape(search_term)
20
+ regexp = Regexp.new(escaped, Regexp::IGNORECASE)
21
+ if search_columns.size == 1
22
+ records = records.where(search_columns.first => regexp)
23
+ else
24
+ cols = search_columns.collect { |col| {col => regexp} }
25
+ records = records.where('$or' => cols)
26
+ end
27
+ end
28
+
29
+ # Pagination
30
+ if start && page_size
31
+ records = records.skip(start).limit(page_size)
32
+ end
33
+ records
34
+ end
35
+
36
+ # Returns the filtered query expression with the sort applied
37
+ def query
38
+ # Sort must be applied last
39
+ order_by ? unsorted_query.sort(order_by) : unsorted_query
40
+ end
41
+
42
+ def count
43
+ unsorted_query.count
44
+ end
45
+
46
+ def unfiltered_count
47
+ scope.count
48
+ end
49
+
50
+ end
51
+ end
@@ -16,13 +16,13 @@
16
16
  %i.fa.fa-home
17
17
  Jobs
18
18
  %li
19
- = link_to workers_path, class: active_page(workers_path) do
19
+ = link_to servers_path, class: active_page(servers_path) do
20
20
  %i.fa.fa-database
21
21
  Servers
22
22
  %li
23
- = link_to active_processes_path, class: active_page(active_processes_path) do
23
+ = link_to active_workers_path, class: active_page(active_workers_path) do
24
24
  %i.fa.fa-circle-o-notch
25
- Activity
25
+ Workers
26
26
  %li
27
27
  = link_to enabled_dirmon_entries_path, class: active_page(enabled_dirmon_entries_path) do
28
28
  %i.fa.fa-folder-o
@@ -7,5 +7,5 @@
7
7
  = render partial: 'rocket_job_mission_control/jobs/sidebar'
8
8
  - if @dirmon_sidebar
9
9
  = render partial: 'rocket_job_mission_control/dirmon_entries/sidebar'
10
- - if @workers_sidebar
11
- = render partial: 'rocket_job_mission_control/workers/sidebar'
10
+ - if @servers_sidebar
11
+ = render partial: 'rocket_job_mission_control/servers/sidebar'
@@ -6,10 +6,10 @@
6
6
  .col-sm-2
7
7
  .btn.btn-default.pull-right.dt-reload{ data: { behavior: 'reload' } }
8
8
  %i.fa.fa-refresh
9
- %table.table.datatable.active-processes-datatable{ style: "width: 100%", data: { source: "#{active_processes_url(format: 'json')}", column_num: 4 } }
9
+ %table.table.datatable.active-workers-datatable{ style: "width: 100%", data: { source: "#{active_workers_url(format: 'json')}", column_num: 4 } }
10
10
  %thead
11
11
  %tr
12
- %th Hostname : PID
12
+ %th Worker Name
13
13
  %th Class
14
14
  %th Description
15
15
  %th Started
@@ -18,7 +18,7 @@
18
18
  :javascript
19
19
  jQuery(function() {
20
20
  new RjmcDatatable(
21
- $('.active-processes-datatable'),
21
+ $('.active-workers-datatable'),
22
22
  [{data: '0'}, {data: '1'}, {data: '2'}, {data: '3'}],
23
23
  {ordering: false, searching: false});
24
24
  });
@@ -1,34 +1,23 @@
1
1
  - if @dirmon_entry.job_class
2
2
  .arguments
3
3
  .job_arguments.form-group
4
- - count = @dirmon_entry.job_class.rocket_job_argument_count
5
- - count.times do |counter|
6
- - argument = @dirmon_entry.arguments[counter]
7
- = f.label "Argument #{counter + 1}:"
8
- = f.text_field :arguments,
9
- value: argument.is_a?(Hash) || argument.is_a?(Array) ? argument.to_json : argument,
10
- name: 'rocket_job_dirmon_entry[arguments][]',
11
- rows: 10,
12
- placeholder: '{"argument1":"value1", "argument2":"value2", "argument3":"value3"}',
13
- class: 'form-control'
14
4
  = f.fields_for :properties do |properties|
15
- - @dirmon_entry.job_class.rocket_job_properties.each do |property_name|
16
- - next if property_name == :arguments
17
- - key = @dirmon_entry.job_class.keys[property_name.to_s]
18
- - next unless key && key.type
19
- - placeholder = key.default? ? key.default : nil
5
+ - @dirmon_entry.job_class.user_editable_fields.each do |property_name|
6
+ - field = @dirmon_entry.job_class.fields[property_name.to_s]
7
+ - next unless field && field.type
8
+ - placeholder = field.default_val
20
9
  .form-group
21
10
  = properties.label property_name.to_s
22
- - case key.type.name
11
+ - case field.type.name
23
12
  - when 'Integer'
24
13
  = properties.number_field property_name, value: @dirmon_entry.properties[property_name], class: 'form-control', placeholder: placeholder
25
14
  - when 'Hash'
26
15
  - value = @dirmon_entry.properties[property_name]
27
- = properties.text_field property_name, value: value ? value.to_json : '', class: 'form-control', placeholder: '{"argument1":"value1", "argument2":"value2", "argument3":"value3"}'
16
+ = properties.text_field property_name, value: value ? value.to_json : '', class: 'form-control', placeholder: '{"key1":"value1", "key2":"value2", "key3":"value3"}'
28
17
  - when 'Array'
29
18
  - options = Array(@dirmon_entry.properties[property_name])
30
19
  = properties.select property_name, options_for_select(options, options), {include_hidden: false}, {class: 'selectize', multiple: true}
31
- - when 'Boolean'
20
+ - when 'Mongoid::Boolean'
32
21
  - name = "#{property_name}_true".to_sym
33
22
  .radio-buttons
34
23
  = properties.label name, 'true'
@@ -10,11 +10,6 @@
10
10
  %div
11
11
  %label Archive Directory:
12
12
  = @dirmon_entry.archive_directory
13
- -if @dirmon_entry.arguments.size > 0
14
- .parameters
15
- %label Arguments:
16
- %pre
17
- %code= pretty_print_array_or_hash(@dirmon_entry.arguments)
18
13
  - @dirmon_entry.properties.each_pair do |name, value|
19
14
  .parameters
20
15
  %label= "#{name.to_s.titleize}:"
@@ -8,14 +8,15 @@
8
8
  = @dirmon_entry.state
9
9
 
10
10
  .btn-toolbar.job-actions.pull-right
11
- .btn-group{ style: 'margin-right: 1em;' }
12
- = link_to "Destroy", dirmon_entry_path(@dirmon_entry), method: :delete, class: 'btn btn-default', :data => { :confirm => 'Are you sure?' }
11
+ .btn-group
12
+ = link_to "Edit", edit_dirmon_entry_path(@dirmon_entry), class: "btn btn-default"
13
+ .btn-group
13
14
  - if @dirmon_entry.disabled? || @dirmon_entry.pending?
14
15
  = link_to "Enable", enable_dirmon_entry_path(@dirmon_entry.id), method: :put, class: "btn btn-default"
15
16
  - if @dirmon_entry.enabled?
16
17
  = link_to "Disable", disable_dirmon_entry_path(@dirmon_entry.id), method: :put, class: "btn btn-default", :data => { :confirm => 'Are you sure?' }
17
18
  .btn-group
18
- = link_to "Edit", edit_dirmon_entry_path(@dirmon_entry), class: "btn btn-default"
19
+ = link_to "Destroy", dirmon_entry_path(@dirmon_entry), method: :delete, class: 'btn btn-default', :data => { :confirm => 'Are you sure?' }
19
20
 
20
21
  .clearfix
21
22
 
@@ -1,31 +1,36 @@
1
1
  - status = job.status(Time.zone)
2
2
  .id
3
3
  %label ID:
4
- = status.delete('id')
5
- .status-message
6
- %label Description:
7
- = status.delete('description')
8
- .status-message
9
- %label Duration:
10
- = status.delete('duration')
11
- .status-message
12
- %label Record Count:
13
- = status.delete('record_count')
4
+ = status.delete('_id')
5
+ - if description = status.delete('description')
6
+ .status-message
7
+ %label Description:
8
+ = description
9
+ - if duration = status.delete('duration')
10
+ .status-message
11
+ %label Duration:
12
+ = duration
13
+ - if record_count = status.delete('record_count')
14
+ .status-message
15
+ %label Record Count:
16
+ = record_count
14
17
  .created_at
15
18
  %label Created At:
16
19
  = status.delete('created_at')
17
- .status-message
18
- %label Started At:
19
- = status.delete('started_at')
20
- .status-message
21
- %label % Complete:
22
- = status.delete('percent_complete')
20
+ - if started_at = status.delete('started_at')
21
+ .status-message
22
+ %label Started At:
23
+ = started_at
24
+ - if percent_complete = status.delete('percent_complete')
25
+ .status-message
26
+ %label % Complete:
27
+ = percent_complete
23
28
 
24
29
  - remaining = {}
25
30
  - status.each_pair do |key, value|
26
31
  - next if value.blank?
27
32
  .status-message
28
- - if ['state', '_type'].include?(key)
33
+ - if ['state', '_type', 'sub_state'].include?(key)
29
34
  - elsif value.kind_of?(Hash) || value.kind_of?(Array)
30
35
  - remaining[key] = value
31
36
  - else
@@ -18,7 +18,7 @@
18
18
  = f.number_field :priority, value: @job.priority, class: 'form-control'
19
19
  .col-md-4
20
20
  = f.label :log_level
21
- = f.select :log_level, ['trace', 'debug', 'info', 'warn', 'error', 'fatal'], { include_blank: true }, { class: 'form-control' }
21
+ = f.select :log_level, SemanticLogger::LEVELS.collect(&:to_s), { include_blank: true }, { class: 'form-control' }
22
22
  - if @job.respond_to?(:max_active_workers)
23
23
  .col-md-4
24
24
  = f.label :max_active_workers
@@ -0,0 +1,29 @@
1
+ .job-list
2
+ .list
3
+ .row
4
+ .col-sm-10
5
+ %h2 Exceptions
6
+ = link_to(@job.class.name, job_path(@job))
7
+ = h(@job.description)
8
+ .col-sm-2
9
+ .btn.btn-default.pull-right.dt-reload{ data: { behavior: 'reload' } }
10
+ %i.fa.fa-refresh
11
+ %table.table.datatable.jobs-datatable{ style: 'width: 100%', data: { source: "#{jobs_url(format: 'json')}" } }
12
+ %thead
13
+ %tr
14
+ %th Count
15
+ %th Exception Class
16
+ %th Exception Messages
17
+ %tbody
18
+ - class_name = nil
19
+ - @exceptions.each do |exception|
20
+ - exception.messages.each do |message|
21
+ %tr
22
+ %th
23
+ = exception.count if exception.class_name != class_name
24
+ %th
25
+ - if exception.class_name != class_name
26
+ = link_to(exception.class_name, job_failures_path(@job, error_type: exception.class_name), class: "card callout")
27
+ %th
28
+ = message
29
+ - class_name = exception.class_name
@@ -8,25 +8,25 @@
8
8
  .clearfix
9
9
  .list
10
10
  - @slice_errors.each do |slice_error|
11
- = link_to(job_failures_path(@job, error_type: slice_error['_id']['error_class']), class: "card callout") do
11
+ = link_to(job_failures_path(@job, error_type: slice_error.class_name), class: "card callout") do
12
12
  .inner
13
13
  .title
14
14
  .lead
15
- = slice_error['_id']['error_class']
15
+ = slice_error.class_name
16
16
 
17
17
  .description
18
- = "Occurrences: #{slice_error['count'].to_i}"
18
+ = "Occurrences: #{slice_error.count}"
19
19
 
20
20
  - if @failure_exception
21
21
  .col-md-8
22
22
  .job-status
23
23
  .failures
24
- .lead= @failure_exception['class_name']
25
- .pagination-buttons.pull-right= render partial: 'pagination', locals: { error_type: @failure_exception['class_name'], pagination: @pagination }
24
+ .lead= @failure_exception.class_name
25
+ .pagination-buttons.pull-right= render partial: 'pagination', locals: { error_type: @failure_exception.class_name, pagination: @pagination }
26
26
 
27
27
  .clearfix
28
28
  .message
29
29
  %pre
30
- %code= @failure_exception['message']
30
+ %code= @failure_exception.message
31
31
  .error
32
- %pre.small= @failure_exception['backtrace'].join("\n")
32
+ %pre.small= @failure_exception.backtrace.join("\n")
@@ -4,21 +4,26 @@
4
4
  .lead= @job.class.name
5
5
 
6
6
  .job-state.inline-block
7
- .left state
7
+ .left State
8
8
  .right{ class: @job.state.to_s }
9
9
  = @job.state
10
+ - if sub_state = @job['sub_state']
11
+ .job-state.inline-block
12
+ .left Batch
13
+ .right{ class: 'running' }
14
+ = sub_state
10
15
 
11
16
  .btn-toolbar.job-actions.pull-right
12
- .btn-group
13
- - valid_events = @job.aasm.events.collect{ |e| e.name }
14
- - if valid_events.include?(:abort)
15
- = job_action_link('Abort', rocket_job_mission_control.abort_job_path(@job), :patch)
17
+ - if @job.respond_to?(:input) && @job.input.failed.count > 0
18
+ .btn-group
19
+ = link_to('Show Exceptions', exceptions_job_path(@job), class: 'btn btn-default')
16
20
 
17
- - if @job.completed? || @job.aborted?
18
- = job_action_link('Destroy', rocket_job_mission_control.job_path(@job), :delete)
21
+ - if @job.scheduled?
22
+ .btn-group
23
+ = job_action_link('Run', rocket_job_mission_control.run_now_job_path(@job), :patch)
19
24
 
20
- - if valid_events.include?(:fail)
21
- = job_action_link('Fail', rocket_job_mission_control.fail_job_path(@job), :patch)
25
+ .btn-group
26
+ - valid_events = @job.aasm.events.collect{ |e| e.name }
22
27
 
23
28
  - if valid_events.include?(:pause)
24
29
  = job_action_link('Pause', rocket_job_mission_control.pause_job_path(@job), :patch)
@@ -29,8 +34,15 @@
29
34
  - if valid_events.include?(:retry)
30
35
  = job_action_link('Retry', rocket_job_mission_control.retry_job_path(@job), :patch)
31
36
 
32
- - if @job.respond_to?(:input) && @job.input.failed_count > 0
33
- = link_to('View Errors', job_failures_path(@job), class: 'btn btn-default')
37
+ .btn-group
38
+ - if valid_events.include?(:fail)
39
+ = job_action_link('Fail', rocket_job_mission_control.fail_job_path(@job), :patch)
40
+
41
+ - if valid_events.include?(:abort)
42
+ = job_action_link('Abort', rocket_job_mission_control.abort_job_path(@job), :patch)
43
+
44
+ = job_action_link('Destroy', rocket_job_mission_control.job_path(@job), :delete)
45
+
34
46
  - unless @job.completed? || @job.aborted?
35
47
  .btn-group
36
48
  = link_to "Edit", edit_job_path(@job), class: "btn btn-default"
@@ -0,0 +1,9 @@
1
+ - if server.stopping?
2
+ %p Server is stopping...
3
+ = link_to "destroy", rocket_job_mission_control.server_path(server), method: :delete, class: 'btn btn-danger'
4
+ -else
5
+ = link_to "stop", rocket_job_mission_control.stop_server_path(server), method: :patch, class: 'btn btn-danger'
6
+ - if server.paused?
7
+ = link_to "resume", rocket_job_mission_control.resume_server_path(server), method: :patch, class: 'btn btn-default'
8
+ - else
9
+ = link_to "pause", rocket_job_mission_control.pause_server_path(server), method: :patch, class: 'btn btn-default'
@@ -0,0 +1,20 @@
1
+ %ul#lg-menu.nav.hidden-xs
2
+ %li
3
+ = link_to(servers_path) do
4
+ %i.fa.fa-list
5
+ All
6
+ - RocketJob::Server.aasm.states.map { |s| s.name.to_s }.each do |state|
7
+ %li{class: state}
8
+ = link_to("#{state}_servers".to_sym) do
9
+ %i.fa{class: state_icon(state)}
10
+ = state.to_s.capitalize!
11
+ = "(#{server_counts_by_state(state)})"
12
+ / tiny only nav
13
+ %ul#xs-menu.nav.visible-xs
14
+ %li
15
+ = link_to(servers_path) do
16
+ %i.fa.fa-list
17
+ - RocketJob::Server.aasm.states.map { |s| s.name.to_s }.each do |state|
18
+ %li{class: state}
19
+ = link_to("#{state}_servers".to_sym) do
20
+ %i.fa{class: state_icon(state)}