minicron 0.6.1 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -5
  3. data/Rakefile +3 -0
  4. data/lib/minicron/alert.rb +9 -7
  5. data/lib/minicron/cli/commands.rb +16 -2
  6. data/lib/minicron/constants.rb +1 -1
  7. data/lib/minicron/hub/app.rb +8 -3
  8. data/lib/minicron/hub/assets/app/application.js +31 -10
  9. data/lib/minicron/hub/assets/app/components/schedules.js +1 -1
  10. data/lib/minicron/hub/assets/app/controllers/executions.js +1 -1
  11. data/lib/minicron/hub/assets/app/models/alert.js +21 -0
  12. data/lib/minicron/hub/assets/app/models/execution.js +1 -0
  13. data/lib/minicron/hub/assets/app/router.js +4 -0
  14. data/lib/minicron/hub/assets/app/routes/alert.js +31 -0
  15. data/lib/minicron/hub/assets/app/routes/executions.js +6 -2
  16. data/lib/minicron/hub/assets/app/routes/hosts.js +4 -2
  17. data/lib/minicron/hub/assets/app/routes/jobs.js +4 -2
  18. data/lib/minicron/hub/assets/app/routes/schedules.js +2 -1
  19. data/lib/minicron/hub/assets/css/main.scss +3 -2
  20. data/lib/minicron/hub/assets/css/perfect-scrollbar-0.4.10.min.css +5 -0
  21. data/lib/minicron/hub/assets/js/ember-1.5.1.min.js +19 -0
  22. data/lib/minicron/hub/assets/js/perfect-scrollbar-0.4.10.with-mousewheel.min.js +4 -0
  23. data/lib/minicron/hub/controllers/api/alerts.rb +19 -0
  24. data/lib/minicron/hub/controllers/api/executions.rb +2 -2
  25. data/lib/minicron/hub/controllers/api/jobs.rb +4 -4
  26. data/lib/minicron/hub/db/schema.rb +5 -1
  27. data/lib/minicron/hub/db/schema.sql +7 -3
  28. data/lib/minicron/hub/models/alert.rb +1 -0
  29. data/lib/minicron/hub/models/execution.rb +1 -0
  30. data/lib/minicron/hub/models/schedule.rb +1 -0
  31. data/lib/minicron/hub/serializers/alert.rb +66 -0
  32. data/lib/minicron/hub/views/handlebars/alerts.erb +104 -0
  33. data/lib/minicron/hub/views/handlebars/application.erb +2 -1
  34. data/lib/minicron/hub/views/handlebars/executions.erb +2 -2
  35. data/lib/minicron/hub/views/handlebars/jobs.erb +3 -3
  36. data/lib/minicron/hub/views/index.erb +2 -1
  37. data/lib/minicron/hub/views/layouts/app.erb +1 -3
  38. data/lib/minicron/monitor.rb +3 -0
  39. data/lib/minicron/transport/client.rb +2 -1
  40. data/lib/minicron/transport/faye/extensions/job_handler.rb +47 -35
  41. data/spec/minicron/alert/pagerduty_spec.rb +1 -1
  42. data/spec/minicron/transport/client_spec.rb +3 -3
  43. data/spec/minicron/transport/faye/client_spec.rb +5 -5
  44. data/spec/minicron/transport/server_spec.rb +9 -9
  45. data/spec/spec_helper.rb +1 -1
  46. metadata +12 -5
  47. data/lib/minicron/hub/assets/js/ember-1.4.1.min.js +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b7ae42fc56fc0059a0eb705924d21b3528b79014
4
- data.tar.gz: 272ed05fdf1f737bbaef4decb2945372634f1817
3
+ metadata.gz: 1cd3672f06eb7642d7fe4ff64dd24964e68b0ef3
4
+ data.tar.gz: 89e098edd94ace62fcb9a2dd4108ac02c279ba28
5
5
  SHA512:
6
- metadata.gz: d3d2f0071fe35af38fbba783dc30f97e85b395f801411e2a56a2886ea3949fd5bf927fb7fd8186730d8ec40e1ea986d668eee38e53195a986a10954f3b789b71
7
- data.tar.gz: 94e3536279f6f247bbc7b0bb002ebafc3836a4582af315b7a355aef044aa0b058cbda578a84fb9b9454834f1963da59fbf2e980956a72ed827588ebc047cbb83
6
+ metadata.gz: d0188e3bc5b4cc46674ad7863353e4ce909a4b47e6bf96d722a384e4b3546fd902496dd6a7d4fb8d4df583d04d0270a6376dc6e3cf0f99a30c583cef0681c033
7
+ data.tar.gz: c66dc6903a06686c91639f98b60fd639678cec14fa774b3e15795eeee14cbee43481335ac01d8e3b2b125720fdc7ebb4ae6e7cdf0a4bff8dc89c04f7687b5853
data/README.md CHANGED
@@ -6,7 +6,7 @@ minicron
6
6
  [![Coverage Status](http://img.shields.io/coveralls/jamesrwhite/minicron.svg)](https://coveralls.io/r/jamesrwhite/minicron?branch=master)
7
7
  [![Code Climate](http://img.shields.io/codeclimate/github/jamesrwhite/minicron.svg)](https://codeclimate.com/github/jamesrwhite/minicron)
8
8
  [![Dependency Status](http://img.shields.io/gemnasium/jamesrwhite/minicron.svg)](https://gemnasium.com/jamesrwhite/minicron)
9
- [![Inline docs](http://inch-pages.github.io/github/jamesrwhite/minicron.png)](http://inch-pages.github.io/github/jamesrwhite/minicron)
9
+ [![Inline docs](http://inch-ci.org/github/jamesrwhite/minicron.png)](http://inch-ci.org/github/jamesrwhite/minicron)
10
10
 
11
11
  minicron aims to complement ````cron```` by making it easier to manage and monitor cron jobs, it can largely be
12
12
  thought of as two components that interact together, the CLI and the Hub. The CLI is what is installed on your
@@ -39,8 +39,7 @@ Screenshots
39
39
  Background
40
40
  -----------
41
41
 
42
- I'm developing minicron as part of my dissertation at university which has to be completed by mid May but I plan to continue
43
- its development after that. The inspiration for developing minicron comes largely from my experience and frustrations using cron,
42
+ I initially developed minicron as part of my dissertation at university. The inspiration for developing minicron comes largely from my experience and frustrations using cron,
44
43
  in particular my time spent working at [Miniclip](http://www.miniclip.com) (which is where the name comes from, miniclip.. minicron, get it?)
45
44
  where the management and monitoring of cron jobs at times proved to be tricky!
46
45
 
@@ -106,7 +105,7 @@ but I encourage you to give it a try in a non critical environment and help me t
106
105
 
107
106
  2. On some distributions you may need to install the ````ruby-dev```` and ````build-essential```` packages
108
107
 
109
- 3. To install the latest release (currently 0.6.1) you can ````gem install minicron````, depending on your ruby setup
108
+ 3. To install the latest release (currently 0.7) you can ````gem install minicron````, depending on your ruby setup
110
109
  you may need to run this with ````sudo````
111
110
 
112
111
  4. Set your database configuration options in ````/etc/minicron.toml````, you can use the [minicron.toml](https://github.com/jamesrwhite/minicron/blob/master/config/minicron.toml) as a guide on what options are configurable
@@ -166,7 +165,7 @@ by default it will bind to port 9292 on the host 127.0.0.1 but this can be confi
166
165
  arguments ````--host```` ````--port```` and ````--path```` or in the config file.
167
166
 
168
167
  By default the server will run as a daemon with its process id stored in ````/tmp/minicron.pid````
169
- you can also use the ````stop```` and ````status```` commands to control the server.
168
+ you can also use the ````stop````, ````restart```` and ````status```` commands to control the server.
170
169
 
171
170
  To run the server in debug mode, i.e not as a daemon so you can see its output you can pass the ````--debug````
172
171
  option.
data/Rakefile CHANGED
@@ -20,6 +20,9 @@ namespace :db do
20
20
  # Tell active record where the db dir is
21
21
  Sinatra::ActiveRecordTasks.db_dir = Minicron::HUB_PATH + '/db'
22
22
 
23
+ # Parse the file config in /etc/minicron.toml
24
+ Minicron.parse_file_config(nil)
25
+
23
26
  # Connect to the DB
24
27
  Minicron::Hub::App.setup_db
25
28
  end
@@ -13,9 +13,9 @@ module Minicron
13
13
  # Send an alert using all enabled mediums
14
14
  #
15
15
  # @option options [String] kind 'fail' or 'miss'
16
- # @option options [Integer, nil] schedule_id only applies to 'miss' alerts
17
- # @option options [Integer, nil] execution_id only used by 'fail' alerts
18
16
  # @option options [Integer] job_id used by the #send method
17
+ # @option options [Integer, nil] execution_id only used by 'fail' alerts
18
+ # @option options [Integer, nil] schedule_id only applies to 'miss' alerts
19
19
  # @option options [Time] expected_at only applies to 'miss' alerts
20
20
  def send_all(options = {})
21
21
  Minicron.config['alerts'].each do |medium, value|
@@ -36,9 +36,9 @@ module Minicron
36
36
  # Send an individual alert
37
37
  #
38
38
  # @option options [String] kind 'fail' or 'miss'
39
- # @option options [Integer, nil] schedule_id only applies to 'miss' alerts
40
- # @option options [Integer, nil] execution_id only used by 'fail' alerts
41
39
  # @option options [Integer] job_id used to look up the job name for the alert message
40
+ # @option options [Integer, nil] execution_id only used by 'fail' alerts
41
+ # @option options [Integer, nil] schedule_id only applies to 'miss' alerts
42
42
  # @option options [Time] expected_at when the schedule was expected to execute
43
43
  # @option options [String] medium the medium to send the alert via
44
44
  def send(options = {})
@@ -59,8 +59,9 @@ module Minicron
59
59
 
60
60
  # Store that we sent the alert
61
61
  Minicron::Hub::Alert.create(
62
- :schedule_id => options[:schedule_id],
62
+ :job_id => options[:job_id],
63
63
  :execution_id => options[:execution_id],
64
+ :schedule_id => options[:schedule_id],
64
65
  :kind => options[:kind],
65
66
  :expected_at => options[:expected_at],
66
67
  :medium => options[:medium],
@@ -102,15 +103,16 @@ module Minicron
102
103
  # been sent
103
104
  #
104
105
  # @option options [String] kind 'fail' or 'miss'
105
- # @option options [Integer, nil] schedule_id only applies to 'miss' alerts
106
106
  # @option options [Integer, nil] execution_id only used by 'fail' alerts
107
+ # @option options [Integer, nil] schedule_id only applies to 'miss' alerts
107
108
  # @option options [Time] expected_at when the schedule was expected to execute
108
109
  # @option options [String] medium the medium to send the alert via
109
110
  def sent?(options = {})
110
111
  Minicron::Hub::Alert.exists?(
111
112
  :kind => options[:kind],
112
- :schedule_id => options[:schedule_id],
113
113
  :execution_id => options[:execution_id],
114
+ :schedule_id => options[:schedule_id],
115
+ :job_id => options[:job_id],
114
116
  :expected_at => options[:expected_at],
115
117
  :medium => options[:medium]
116
118
  )
@@ -53,7 +53,7 @@ module Minicron
53
53
  # Add the `minicron server` command
54
54
  def self.add_server_cli_command(cli)
55
55
  cli.command :server do |c|
56
- c.syntax = 'minicron server [start|stop|status]'
56
+ c.syntax = 'minicron server [start|stop|restart|status]'
57
57
  c.description = 'Controls the minicron server.'
58
58
  c.option '--host STRING', String, "The host for the server to listen on. Default: #{Minicron.config['server']['host']}"
59
59
  c.option '--port STRING', Integer, "How port for the server to listed on. Default: #{Minicron.config['server']['port']}"
@@ -89,6 +89,19 @@ module Minicron
89
89
  end
90
90
  when 'stop'
91
91
  insidious.stop!
92
+ when 'restart'
93
+ insidious.restart! do
94
+ # Run the execution monitor (this runs in a separate thread)
95
+ monitor = Minicron::Monitor.new
96
+ monitor.start!
97
+
98
+ # Start the server!
99
+ Minicron::Transport::Server.start!(
100
+ Minicron.config['server']['host'],
101
+ Minicron.config['server']['port'],
102
+ Minicron.config['server']['path']
103
+ )
104
+ end
92
105
  when 'status'
93
106
  if insidious.running?
94
107
  puts 'minicron is running'
@@ -132,7 +145,8 @@ module Minicron
132
145
  Minicron.config['client']['path']
133
146
  )
134
147
 
135
- # Set up the job and get the jexecution and job ids back from the server
148
+ # Set up the job and get the execution and job ids back from the server
149
+ # The execution number is also returned but it's only used by the frontend
136
150
  ids = setup_job(args.first, faye)
137
151
  end
138
152
  rescue Exception => e
@@ -1,6 +1,6 @@
1
1
  # The minicron module
2
2
  module Minicron
3
- VERSION = '0.6.1'
3
+ VERSION = '0.7'
4
4
  DEFAULT_CONFIG_FILE = '/etc/minicron.toml'
5
5
  BASE_PATH = File.expand_path('../../../', __FILE__)
6
6
  LIB_PATH = File.expand_path('../../', __FILE__)
@@ -27,7 +27,7 @@ module Minicron::Hub
27
27
 
28
28
  # Used to enable asset compression, currently nothing else
29
29
  # relies on this
30
- set :environment, :development
30
+ set :environment, :production
31
31
 
32
32
  # Force the encoding to be UTF-8 to prevent assetpack encoding issues
33
33
  Encoding.default_external = Encoding::UTF_8
@@ -45,7 +45,8 @@ module Minicron::Hub
45
45
  # Set up the application css
46
46
  css :app, '/css/all.css', [
47
47
  '/css/bootswatch.min.css',
48
- '/css/main.css'
48
+ '/css/main.css',
49
+ '/css/perfect-scrollbar-0.4.10.min.css'
49
50
  ]
50
51
 
51
52
  # Set up the application javascript
@@ -53,12 +54,13 @@ module Minicron::Hub
53
54
  # Dependencies, the order of these is important
54
55
  '/js/jquery-2.1.0.min.js',
55
56
  '/js/handlebars-1.3.0.min.js',
56
- '/js/ember-1.4.1.min.js',
57
+ '/js/ember-1.5.1.min.js',
57
58
  '/js/ember-data-1.0.0-beta.7.f87cba88.min.js',
58
59
  '/js/faye-browser-1.0.1.min.js',
59
60
  '/js/ansi_up-1.1.1.min.js',
60
61
  '/js/bootstrap-3.1.1.min.js',
61
62
  '/js/moment-2.5.1.min.js',
63
+ '/js/perfect-scrollbar-0.4.10.with-mousewheel.min.js',
62
64
 
63
65
  # Ember application files
64
66
  '/app/**/*.js'
@@ -114,6 +116,9 @@ module Minicron::Hub
114
116
  else
115
117
  fail Exception, "The database #{Minicron.config['database']['type']} is not supported"
116
118
  end
119
+
120
+ # Enable ActiveRecord logging if in verbose mode
121
+ ActiveRecord::Base.logger = Minicron.config['verbose'] ? Logger.new(STDOUT) : nil
117
122
  end
118
123
  end
119
124
 
@@ -14,6 +14,25 @@
14
14
  Ember.$('body').tooltip({
15
15
  selector: '[data-toggle=tooltip]'
16
16
  });
17
+
18
+ // We'll keep on waiting, waiting, waiting on the DOM to change..
19
+ var waitUntilReady = setInterval(function() {
20
+ var $sidebar = Ember.$('.sidebar'),
21
+ $main_panel = Ember.$('.main-panel');
22
+
23
+ if ($sidebar.length && $main_panel.length) {
24
+ // Sidebar perfect scrollbar init
25
+ $sidebar.perfectScrollbar();
26
+
27
+ // Main Panel perfect scrollbar init
28
+ $main_panel.perfectScrollbar();
29
+ $main_panel.scrollTop(0);
30
+ $main_panel.perfectScrollbar('update');
31
+
32
+ // Stop waiting on the DOM to change
33
+ clearInterval(waitUntilReady);
34
+ }
35
+ }, 100);
17
36
  };
18
37
 
19
38
  // Configure Ember Data so it can find the API
@@ -75,28 +94,30 @@
75
94
  if (message.channel.substr(1, 3) === 'job') {
76
95
  var segments = message.channel.split('/');
77
96
  var job_id = segments[2];
78
- var job_execution_id = segments[3];
97
+ var execution_id = segments[3];
79
98
  var type = segments[4];
80
99
  var message_data = message.data.message;
81
100
 
82
101
  // TODO: remove this!
83
- console.log(job_id, job_execution_id, type, message);
102
+ console.log(job_id, execution_id, type, message);
84
103
 
85
104
  // Is it a status message?
86
105
  if (type === 'status') {
87
106
  // Is it a setup message
88
107
  if (typeof message_data.action != 'undefined' && message_data.action === 'SETUP') {
89
108
  // The SETUP message is defined slightly differently, segment 2 contains the
90
- // job hash and segment 3 contains '*job_id*-*job_execution_id*'
91
- var ids = job_execution_id.split('-');
109
+ // job hash and segment 3 contains '*job_id*-*execution_id*-*execution_number*'
110
+ var ids = execution_id.split('-');
92
111
  job_id = ids[0];
93
- job_execution_id = ids[1];
112
+ execution_id = ids[1];
113
+ var execution_number = ids[2];
94
114
 
95
115
  // Append the job relationship to it
96
116
  store.find('job', job_id).then(function(job) {
97
117
  // Create the execution
98
118
  store.push('execution', {
99
- id: job_execution_id,
119
+ id: execution_id,
120
+ number: execution_number,
100
121
  created_at: moment.utc(message.data.ts).format('YYYY-MM-DDTHH:mm:ss[Z]'),
101
122
  job: job
102
123
  }, true);
@@ -104,25 +125,25 @@
104
125
  // Is it a start message?
105
126
  } else if (message_data.substr(0, 5) === 'START') {
106
127
  // Set the execution start time
107
- store.find('execution', job_execution_id).then(function(execution) {
128
+ store.find('execution', execution_id).then(function(execution) {
108
129
  execution.set('started_at', moment.utc(message_data.substr(6)).format('YYYY-MM-DDTHH:mm:ss[Z]'));
109
130
  });
110
131
  // Is it a finish message?
111
132
  } else if (message_data.substr(0, 6) === 'FINISH') {
112
133
  // Set the execution finish time
113
- store.find('execution', job_execution_id).then(function(execution) {
134
+ store.find('execution', execution_id).then(function(execution) {
114
135
  execution.set('finished_at', moment.utc(message_data.substr(7)).format('YYYY-MM-DDTHH:mm:ss[Z]'));
115
136
  });
116
137
  // Is it an exit message?
117
138
  } else if (message_data.substr(0, 4) === 'EXIT') {
118
139
  // Set the execution exit status
119
- store.find('execution', job_execution_id).then(function(execution) {
140
+ store.find('execution', execution_id).then(function(execution) {
120
141
  execution.set('exit_status', +message_data.substr(5));
121
142
  });
122
143
  }
123
144
  // Is it an output message?
124
145
  } else if (type === 'output') {
125
- store.find('execution', job_execution_id).then(function(execution) {
146
+ store.find('execution', execution_id).then(function(execution) {
126
147
  // Add this bit of job execution output
127
148
  var output = store.createRecord('job_execution_output', {
128
149
  id: message.data.job_execution_output_id,
@@ -256,7 +256,7 @@
256
256
  });
257
257
 
258
258
  // Handle when one of the 'every n x' is inputs is changed
259
- Ember.$('#schedule-editor').find('input[type="number"], input[type="checkbox"], input[type="radio"]').on('change', function(e) {
259
+ Ember.$('#schedule-editor').find('input[type="number"], input[type="checkbox"]').on('change', function(e) {
260
260
  if (self.get('read_only')) {
261
261
  e.preventDefault();
262
262
  return false;
@@ -31,6 +31,6 @@
31
31
  sortProperties: ['seq'],
32
32
  content: this.get('content.job_execution_outputs')
33
33
  });
34
- }).property('content.job_execution_outputs')
34
+ }).property('content.job_execution_outputs').cacheable()
35
35
  });
36
36
  })();
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ (function() {
4
+ Minicron.Alert = DS.Model.extend({
5
+ kind: DS.attr('string'),
6
+ medium: DS.attr('string'),
7
+ expected_at: DS.attr('date'),
8
+ sent_at: DS.attr('date'),
9
+
10
+ isFail: function() {
11
+ return this.get('kind') === 'fail';
12
+ }.property('kind'),
13
+ isMiss: function() {
14
+ return this.get('kind') === 'miss';
15
+ }.property('kind'),
16
+
17
+ job: DS.belongsTo('job', { async: true }),
18
+ execution: DS.belongsTo('execution', { async: true }),
19
+ schedule: DS.belongsTo('schedule', { async: true })
20
+ });
21
+ })();
@@ -2,6 +2,7 @@
2
2
 
3
3
  (function() {
4
4
  Minicron.Execution = DS.Model.extend({
5
+ number: DS.attr('number'),
5
6
  created_at: DS.attr('date'),
6
7
  started_at: DS.attr('date'),
7
8
  finished_at: DS.attr('date'),
@@ -27,5 +27,9 @@
27
27
  this.route('edit');
28
28
  });
29
29
  });
30
+
31
+ this.resource('alerts', function() {
32
+ this.resource('alert', { path: ':id' }, function() {});
33
+ });
30
34
  });
31
35
  })();
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ (function() {
4
+ Minicron.AlertsRoute = Ember.Route.extend({
5
+ model: function() {
6
+ return this.store.find('alert');
7
+ },
8
+ afterModel: Minicron.onViewLoad
9
+ });
10
+
11
+ Minicron.AlertsIndexRoute = Ember.Route.extend({
12
+ model: function() {
13
+ return this.store.all('alert');
14
+ },
15
+ afterModel: Minicron.onViewLoad
16
+ });
17
+
18
+ Minicron.AlertRoute = Ember.Route.extend({
19
+ model: function(params) {
20
+ return this.store.find('alert', params.id);
21
+ },
22
+ afterModel: Minicron.onViewLoad
23
+ });
24
+
25
+ Minicron.AlertIndexRoute = Ember.Route.extend({
26
+ model: function() {
27
+ return this.modelFor('alert');
28
+ },
29
+ afterModel: Minicron.onViewLoad
30
+ });
31
+ })();
@@ -4,7 +4,8 @@
4
4
  Minicron.ExecutionsRoute = Ember.Route.extend({
5
5
  model: function() {
6
6
  return this.store.all('execution');
7
- }
7
+ },
8
+ afterModel: Minicron.onViewLoad
8
9
  });
9
10
 
10
11
  Minicron.ExecutionsIndexRoute = Ember.Route.extend({
@@ -14,6 +15,8 @@
14
15
  afterModel: function(executions) {
15
16
  if (typeof executions.objectAt(0) != 'undefined') {
16
17
  this.transitionTo('execution', executions.objectAt(0));
18
+ } else {
19
+ Minicron.onViewLoad();
17
20
  }
18
21
  }
19
22
  });
@@ -21,7 +24,8 @@
21
24
  Minicron.ExecutionRoute = Ember.Route.extend({
22
25
  model: function(params) {
23
26
  return this.store.find('execution', params.id);
24
- }
27
+ },
28
+ afterModel: Minicron.onViewLoad
25
29
  });
26
30
 
27
31
  Minicron.ExecutionIndexRoute = Ember.Route.extend({
@@ -4,7 +4,8 @@
4
4
  Minicron.HostsRoute = Ember.Route.extend({
5
5
  model: function() {
6
6
  return this.store.find('host');
7
- }
7
+ },
8
+ afterModel: Minicron.onViewLoad
8
9
  });
9
10
 
10
11
  Minicron.HostsIndexRoute = Ember.Route.extend({
@@ -20,7 +21,8 @@
20
21
  Minicron.HostRoute = Ember.Route.extend({
21
22
  model: function(params) {
22
23
  return this.store.find('host', params.id);
23
- }
24
+ },
25
+ afterModel: Minicron.onViewLoad
24
26
  });
25
27
 
26
28
  Minicron.HostIndexRoute = Ember.Route.extend({
@@ -4,7 +4,8 @@
4
4
  Minicron.JobsRoute = Ember.Route.extend({
5
5
  model: function() {
6
6
  return this.store.find('job');
7
- }
7
+ },
8
+ afterModel: Minicron.onViewLoad
8
9
  });
9
10
 
10
11
  Minicron.JobsIndexRoute = Ember.Route.extend({
@@ -20,7 +21,8 @@
20
21
  Minicron.JobRoute = Ember.Route.extend({
21
22
  model: function(params) {
22
23
  return this.store.find('job', params.id);
23
- }
24
+ },
25
+ afterModel: Minicron.onViewLoad
24
26
  });
25
27
 
26
28
  Minicron.JobIndexRoute = Ember.Route.extend({