resque-web-clone 0.0.6

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 (103) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +89 -0
  3. data/Rakefile +34 -0
  4. data/app/assets/images/resque_web/idle.png +0 -0
  5. data/app/assets/images/resque_web/lifebuoy.png +0 -0
  6. data/app/assets/images/resque_web/poll.png +0 -0
  7. data/app/assets/images/resque_web/rails.png +0 -0
  8. data/app/assets/images/resque_web/working.png +0 -0
  9. data/app/assets/javascripts/resque_web/application.js +16 -0
  10. data/app/assets/javascripts/resque_web/bootstrap.js.coffee +4 -0
  11. data/app/assets/javascripts/resque_web/failure.js.coffee +7 -0
  12. data/app/assets/javascripts/resque_web/jquery.relative-date.js +47 -0
  13. data/app/assets/javascripts/resque_web/polling.js.coffee +25 -0
  14. data/app/assets/javascripts/resque_web/relative_date.js.coffee +27 -0
  15. data/app/assets/stylesheets/resque_web/application.css +13 -0
  16. data/app/assets/stylesheets/resque_web/bootstrap_and_overrides.css.scss.erb +146 -0
  17. data/app/controllers/resque_web/application_controller.rb +25 -0
  18. data/app/controllers/resque_web/failures_controller.rb +62 -0
  19. data/app/controllers/resque_web/overview_controller.rb +7 -0
  20. data/app/controllers/resque_web/queues_controller.rb +22 -0
  21. data/app/controllers/resque_web/stats_controller.rb +36 -0
  22. data/app/controllers/resque_web/workers_controller.rb +34 -0
  23. data/app/controllers/resque_web/working_controller.rb +8 -0
  24. data/app/helpers/resque_web/application_helper.rb +69 -0
  25. data/app/helpers/resque_web/failures_helper.rb +58 -0
  26. data/app/helpers/resque_web/overview_helper.rb +6 -0
  27. data/app/helpers/resque_web/queues_helper.rb +72 -0
  28. data/app/helpers/resque_web/stats_helper.rb +54 -0
  29. data/app/helpers/resque_web/workers_helper.rb +16 -0
  30. data/app/helpers/resque_web/working_helper.rb +19 -0
  31. data/app/views/layouts/resque_web/application.html.erb +58 -0
  32. data/app/views/resque_web/failures/_failed_job.html.erb +53 -0
  33. data/app/views/resque_web/failures/_overview.html.erb +24 -0
  34. data/app/views/resque_web/failures/index.html.erb +32 -0
  35. data/app/views/resque_web/failures/show.html.erb +20 -0
  36. data/app/views/resque_web/overview/show.html.erb +4 -0
  37. data/app/views/resque_web/queues/_queues.html.erb +4 -0
  38. data/app/views/resque_web/queues/_queues_advanced.html.erb +14 -0
  39. data/app/views/resque_web/queues/_queues_basic.html.erb +17 -0
  40. data/app/views/resque_web/queues/index.html.erb +1 -0
  41. data/app/views/resque_web/queues/show.html.erb +30 -0
  42. data/app/views/resque_web/stats/key.html.erb +26 -0
  43. data/app/views/resque_web/stats/keys.html.erb +17 -0
  44. data/app/views/resque_web/stats/redis.html.erb +14 -0
  45. data/app/views/resque_web/stats/resque.html.erb +14 -0
  46. data/app/views/resque_web/workers/index.html.erb +19 -0
  47. data/app/views/resque_web/workers/show.html.erb +38 -0
  48. data/app/views/resque_web/working/_working.html.erb +34 -0
  49. data/app/views/resque_web/working/index.html.erb +1 -0
  50. data/config/initializers/resque_config.rb +2 -0
  51. data/config/routes.rb +34 -0
  52. data/lib/resque_web/engine.rb +13 -0
  53. data/lib/resque_web/version.rb +3 -0
  54. data/lib/resque_web.rb +4 -0
  55. data/test/dummy/Rakefile +6 -0
  56. data/test/dummy/app/assets/javascripts/application.js +13 -0
  57. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  58. data/test/dummy/app/controllers/application_controller.rb +5 -0
  59. data/test/dummy/app/helpers/application_helper.rb +2 -0
  60. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  61. data/test/dummy/bin/bundle +3 -0
  62. data/test/dummy/bin/rails +4 -0
  63. data/test/dummy/bin/rake +4 -0
  64. data/test/dummy/config/application.rb +23 -0
  65. data/test/dummy/config/boot.rb +5 -0
  66. data/test/dummy/config/database.yml +25 -0
  67. data/test/dummy/config/environment.rb +5 -0
  68. data/test/dummy/config/environments/development.rb +29 -0
  69. data/test/dummy/config/environments/production.rb +80 -0
  70. data/test/dummy/config/environments/test.rb +36 -0
  71. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  72. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  73. data/test/dummy/config/initializers/inflections.rb +16 -0
  74. data/test/dummy/config/initializers/mime_types.rb +5 -0
  75. data/test/dummy/config/initializers/secret_token.rb +12 -0
  76. data/test/dummy/config/initializers/session_store.rb +3 -0
  77. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  78. data/test/dummy/config/locales/en.yml +23 -0
  79. data/test/dummy/config/routes.rb +4 -0
  80. data/test/dummy/config.ru +4 -0
  81. data/test/dummy/db/schema.rb +16 -0
  82. data/test/dummy/public/404.html +58 -0
  83. data/test/dummy/public/422.html +58 -0
  84. data/test/dummy/public/500.html +57 -0
  85. data/test/dummy/public/favicon.ico +0 -0
  86. data/test/functional/failures_controller_test.rb +74 -0
  87. data/test/functional/overview_controller_test.rb +37 -0
  88. data/test/functional/queues_controller_test.rb +58 -0
  89. data/test/functional/stats_controller_test.rb +70 -0
  90. data/test/functional/workers_controller_test.rb +26 -0
  91. data/test/functional/working_controller_test.rb +19 -0
  92. data/test/integration/plugin_integration_test.rb +72 -0
  93. data/test/support/controller_test_helpers.rb +22 -0
  94. data/test/test_helper.rb +23 -0
  95. data/test/unit/helpers/failures_helper_test.rb +15 -0
  96. data/test/unit/helpers/jobs_helper_test.rb +4 -0
  97. data/test/unit/helpers/overview_helper_test.rb +4 -0
  98. data/test/unit/helpers/queues_helper_test.rb +4 -0
  99. data/test/unit/helpers/retry_controller_helper_test.rb +4 -0
  100. data/test/unit/helpers/stats_helper_test.rb +4 -0
  101. data/test/unit/helpers/workers_helper_test.rb +4 -0
  102. data/test/unit/helpers/working_helper_test.rb +4 -0
  103. metadata +263 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 104e4126b4c0a02f04e36e862407b720af1207f8
4
+ data.tar.gz: 8168053bfed19ff1ad0446eef499b009d58fde55
5
+ SHA512:
6
+ metadata.gz: 382604fafcc67a152ba8df691c35c26e47989127a27b2613374d0abfef61ae29a8fe4d53062cefdc83a2b83acf72b19658513effa964272e4ef22dafabd75bf0
7
+ data.tar.gz: 1d7bfa320a70d15a14fbd3c2dc0bd7dc8a12f372ab561850a07beb8639e8e599787e612f7e5d55ef4bf49df3f837a0cd5a0229f1c8bd989101ada280406ed3f8
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ resque-web
2
+ ==========
3
+ [![Gem Version](http://img.shields.io/gem/v/resque-web.svg)](https://rubygems.org/gems/resque-web)
4
+ [![Build Status](https://img.shields.io/travis/resque/resque_web/master.svg)](https://travis-ci.org/resque/resque-web)
5
+ [![Dependency Status](https://img.shields.io/gemnasium/resque/resque-web.svg)](https://gemnasium.com/resque/resque-web)
6
+ [![Code Climate](https://img.shields.io/codeclimate/github/resque/resque-web.svg)](https://codeclimate.com/github/resque/resque-web)
7
+ [![Coverage Status](https://img.shields.io/coveralls/resque/resque-web/master.svg)](https://coveralls.io/r/resque/resque-web)
8
+
9
+ A Rails-based frontend to the [Resque](https://github.com/resque/resque) job
10
+ queue system. This provides a similar interface to the existing Sinatra
11
+ application that comes bundled with Resque, but deploys like a Rails application
12
+ and leverages Rails conventions for factoring things like controllers, helpers,
13
+ and views.
14
+
15
+ # NOTICE
16
+ Note this is NOT the old sinatra interface that comes with Resque 1-x. This is
17
+ a new project based on rails. If you have any issues with old web server,
18
+ please file an issue on the [resque](https://github.com/resque/resque) project.
19
+ Note that the sinatra web interface will be gone in Resque 2.0 and this is
20
+ meant to be the replacement.
21
+
22
+ More documentation coming soon!
23
+
24
+ ## Starting
25
+ Resque web is built as a rails engine.
26
+
27
+ Add it to your gemfile.
28
+
29
+ ```Ruby
30
+ gem 'resque-web', require: 'resque_web'
31
+ ```
32
+
33
+ Mount it in your config/routes.rb.
34
+
35
+ ```Ruby
36
+ require "resque_web"
37
+
38
+ MyApp::Application.routes.draw do
39
+ mount ResqueWeb::Engine => "/resque_web"
40
+ end
41
+ ```
42
+
43
+ If you need a non-default resque server, use this environment variable.
44
+
45
+ ```
46
+ RAILS_RESQUE_REDIS=123.x.0.456:6712
47
+ ```
48
+ ## Security
49
+
50
+ You almost certainly want to limit access when using resque-web in production. Using [routes constraints](http://guides.rubyonrails.org/routing.html#request-based-constraints) is one way to achieve this:
51
+
52
+ ```ruby
53
+ # config/routes.rb
54
+
55
+ resque_web_constraint = lambda { |request| request.remote_ip == '127.0.0.1' }
56
+ constraints resque_web_constraint do
57
+ mount ResqueWeb::Engine => "/resque_web"
58
+ end
59
+
60
+ ```
61
+
62
+ Another example of a route constraint using the current user when using Devise or another warden based authentication system:
63
+
64
+ ```ruby
65
+ # config/routes.rb
66
+ resque_web_constraint = lambda do |request|
67
+ current_user = request.env['warden'].user
68
+ current_user.present? && current_user.respond_to?(:is_admin?) && current_user.is_admin?
69
+ end
70
+
71
+ constraints resque_web_constraint do
72
+ mount ResqueWeb::Engine => "/resque_web"
73
+ end
74
+
75
+ ```
76
+
77
+ ### HTTP Basic Authentication
78
+
79
+ HTTP Basic Authentication is supported out of the box. Simply set the environment variables `RESQUE_WEB_HTTP_BASIC_AUTH_USER` and `RESQUE_WEB_HTTP_BASIC_AUTH_PASSWORD` to turn it on. If you're using Resque with Heroku run `heroku config:set RESQUE_WEB_HTTP_BASIC_AUTH_USER=user RESQUE_WEB_HTTP_BASIC_AUTH_PASSWORD=secret` to get ResqueWeb secured.
80
+
81
+ ## Plugins
82
+
83
+ In the past with the sinatra app it was fairly simple to just monkey-patch the
84
+ server to add more functionality/tabs. With this rails version you have to write
85
+ an engine under a specific namespace. Read more in PLUGINS.md.
86
+
87
+ ## Screenshot
88
+
89
+ ![Screenshot](http://i.imgur.com/LkNgl.png)
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'ResqueWeb'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.libs << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+
34
+ task :default => :test
@@ -0,0 +1,16 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require twitter/bootstrap
16
+ //= require_tree .
@@ -0,0 +1,4 @@
1
+ jQuery ->
2
+ $("a[rel=popover]").popover()
3
+ $(".tooltip").tooltip()
4
+ $("a[rel=tooltip]").tooltip()
@@ -0,0 +1,7 @@
1
+ jQuery ->
2
+ $(".backtrace").click (e) ->
3
+ e.preventDefault()
4
+ $(this).next().toggle()
5
+
6
+ $("ul.failed li").hover ->
7
+ $(this).toggleClass "hover"
@@ -0,0 +1,47 @@
1
+ /**
2
+ * jQ plugin adapted from 37s' relative date tool
3
+ * Takes the format of "Jan 15, 2007 15:45:00 GMT" and converts it to a relative time
4
+ * @see http://37signals.com/svn/posts/1557-javascript-makes-relative-times-compatible-with-caching
5
+ */
6
+ (function($, window, undefined){
7
+
8
+ $.fn.relativeDate = function(opts){
9
+ var defaults = {
10
+ dateGetter: function(el){
11
+ return $(el).text();
12
+ }
13
+ },
14
+ options = $.extend({}, defaults, opts),
15
+ time_ago_in_words_with_parsing = function(from) {
16
+ var date = new Date;
17
+ date.setTime(Date.parse(from));
18
+ return time_ago_in_words(date);
19
+ },
20
+ time_ago_in_words = function(from) {
21
+ return distance_of_time_in_words(new Date, from);
22
+ },
23
+ distance_of_time_in_words = function(to, from) {
24
+ var distance_in_seconds = ((to - from) / 1000);
25
+ var distance_in_minutes = Math.floor(distance_in_seconds / 60);
26
+
27
+ if (distance_in_minutes == 0) { return 'less than a minute ago'; }
28
+ if (distance_in_minutes == 1) { return 'a minute ago'; }
29
+ if (distance_in_minutes < 45) { return distance_in_minutes + ' minutes ago'; }
30
+ if (distance_in_minutes < 90) { return 'about 1 hour ago'; }
31
+ if (distance_in_minutes < 1440) { return 'about ' + Math.round(distance_in_minutes / 60) + ' hours ago'; }
32
+ if (distance_in_minutes < 2880) { return '1 day ago'; }
33
+ if (distance_in_minutes < 43200) { return Math.floor(distance_in_minutes / 1440) + ' days ago'; }
34
+ if (distance_in_minutes < 86400) { return 'about 1 month ago'; }
35
+ if (distance_in_minutes < 525960) { return Math.floor(distance_in_minutes / 43200) + ' months ago'; }
36
+ if (distance_in_minutes < 1051199) { return 'about 1 year ago'; }
37
+
38
+ return 'over ' + Math.floor(distance_in_minutes / 525960) + ' years ago';
39
+ }
40
+
41
+ return $(this).each(function(){
42
+ date_str = options.dateGetter(this);
43
+ $(this).html(time_ago_in_words_with_parsing(date_str));
44
+ });
45
+ };
46
+
47
+ })(jQuery, window);
@@ -0,0 +1,25 @@
1
+ jQuery ->
2
+ poll_interval = 2
3
+
4
+ poll_start = (el) ->
5
+ href = el.attr("href")
6
+ el.parent().text "Starting..."
7
+ $("#main").addClass "polling"
8
+ setInterval (->
9
+ $.ajax
10
+ dataType: "text"
11
+ type: "get"
12
+ url: href
13
+ success: (data) ->
14
+ $("#main").html data
15
+ $("#main .time").relativeDate()
16
+ ), poll_interval * 1000
17
+ location.hash = "#poll"
18
+
19
+ # auto start if hash is poll
20
+ poll_start $("a[rel=poll]") if location.hash == "#poll"
21
+
22
+ # start when click on link
23
+ $("a[rel=poll]").click (e) ->
24
+ e.preventDefault()
25
+ poll_start $(this)
@@ -0,0 +1,27 @@
1
+ jQuery ->
2
+ relatizer = ->
3
+ dt = $(this).text()
4
+ $(this).relativeDate()
5
+ relatized = $(this).text()
6
+ if $(this).parents("a").size() > 0 || $(this).is("a")
7
+ $(this).relativeDate()
8
+ $(this).attr("title", dt) unless $(this).attr("title")
9
+ else
10
+ $(this).html """
11
+ <a href='#'' class='toggle_format' title='#{dt}'>
12
+ <span class='date_time'>#{dt}</span>
13
+ <span class='relatized_time'>#{relatized}</span>
14
+ </a>
15
+ """
16
+
17
+ format_toggler = (e) ->
18
+ e.preventDefault()
19
+ $(".time a.toggle_format span").toggle()
20
+ $(this).attr "title", $("span:hidden", this).text()
21
+
22
+ # changed html when doom is ready
23
+ $(".time").each relatizer
24
+ $(".time a.toggle_format .date_time").hide()
25
+
26
+ # add event on click in relative time to show date_time
27
+ $(".time").on "click", "a.toggle_format", format_toggler
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,146 @@
1
+ /*
2
+ =require twitter-bootstrap-static/bootstrap
3
+
4
+ Use Font Awesome icons (default)
5
+ To use Glyphicons sprites instead of Font Awesome, replace with "require twitter-bootstrap-static/sprites"
6
+ =require twitter-bootstrap-static/fontawesome
7
+ */
8
+
9
+ html {
10
+ background: #efefef;
11
+ }
12
+
13
+ body {
14
+ padding-top: 40px;
15
+ }
16
+
17
+ .navbar {
18
+ border-bottom: 5px solid #ce1212;
19
+ }
20
+
21
+ .navbar .brand, .navbar .navbar-brand {
22
+ color: white;
23
+ }
24
+
25
+ .navbar-fixed-top .navbar-inner, .navbar-static-top .navbar-inner {
26
+ border-width: 0;
27
+ }
28
+
29
+ .navbar-inverse .nav>.active {
30
+ background: #fa2424; /* Old browsers */
31
+ background: -moz-linear-gradient(top, #fa2424 0%, #ce1212 100%); /* FF3.6+ */
32
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fa2424), color-stop(100%,#ce1212)); /* Chrome,Safari4+ */
33
+ background: -webkit-linear-gradient(top, #fa2424 0%,#ce1212 100%); /* Chrome10+,Safari5.1+ */
34
+ background: -o-linear-gradient(top, #fa2424 0%,#ce1212 100%); /* Opera 11.10+ */
35
+ background: -ms-linear-gradient(top, #fa2424 0%,#ce1212 100%); /* IE10+ */
36
+ background: linear-gradient(to bottom, #fa2424 0%,#ce1212 100%); /* W3C */
37
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fa2424', endColorstr='#ce1212',GradientType=0 ); /* IE6-8 */
38
+ }
39
+
40
+ .navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus {
41
+ background: none;
42
+ }
43
+
44
+ .container h1 { color:#ce1212; font-size: 24px; }
45
+
46
+ .label-info[href], .badge-info[href] {
47
+ background-color: #3A87AD;
48
+ }
49
+
50
+ .logo {
51
+ float: left;
52
+ margin: 2px 5px;
53
+ width: 36px;
54
+ height: 36px;
55
+ }
56
+
57
+ /* The remaining CSS rules come from the legacy Resque application */
58
+ .subnav { padding: 8px 10px 7px 10px; background:#ce1212; font-size:90%;}
59
+ .subnav li { display:inline; line-height: 16px; }
60
+ .subnav li a { color:#fff; text-decoration:none; margin:3px; display:inline-block; background:#dd5b5b; padding:5px; -webkit-border-radius:3px; -moz-border-radius:3px;}
61
+ .subnav li.current a { background:#fff; font-weight:bold; color:#ce1212;}
62
+ .subnav li a:active { background:#b00909;}
63
+
64
+ .container span.hl { background:#efefef; padding:2px;}
65
+ .container h2 { margin:10px 0; font-size:130%;}
66
+ .container table tr th { background:#efefef; color:#888; font-size:15px; font-weight:bold; min-width: 16px; }
67
+ .container table tr td.no-data { text-align:center; padding:40px 0; color:#999; font-style:italic; font-size:130%;}
68
+ .container p { margin:5px 0;}
69
+ .container p.intro { margin-bottom:15px; font-size:85%; color:#999; margin-top:0; line-height:1.3;}
70
+ .container h1.wi { margin-bottom:5px;}
71
+ .container p.sub { font-size:95%; color:#999;}
72
+
73
+ .container table.queues { width:40%;}
74
+ .container table.queues td.queue { font-weight:bold; width:50%;}
75
+ .container table.queues tr.failure td { background:#ffecec; color:#d37474;}
76
+ .container table.queues tr.failure td a{ color:#d37474;}
77
+ .container table.queues td.failure .badge a { color: white; }
78
+ .container table.queues tr.first_failure td { border-top:2px solid #d37474; }
79
+
80
+ .container table.jobs td.class { font-family:Monaco, "Courier New", monospace; font-size:90%; width:50%;}
81
+ .container table.jobs td.args{ width:50%;}
82
+
83
+ .container table.workers td.icon {width:1%; background:#efefef;text-align:center;}
84
+ .container table.workers td.icon img { height: 16px; width: 16px; }
85
+ .container table.workers td.where { width:25%;}
86
+ .container table.workers td.queues { width:35%;}
87
+ .container table.workers td.queues.queue { width:10%;}
88
+ .container table.workers td.process { width:35%;}
89
+ .container table.workers td.process span.waiting { color:#999; font-size:90%;}
90
+ .container table.workers td.process small { font-size:80%; margin-left:5px;}
91
+ .container table.workers td.process code { font-family:Monaco, "Courier New", monospace; font-size:90%;}
92
+ .container table.workers td.process small a { color:#999;}
93
+ .container.polling table.workers tr.working td { background:#f4ffe4; color:#7ac312;}
94
+ .container.polling table.workers tr.working td.where a { color:#7ac312;}
95
+ .container.polling table.workers tr.working td.process code { font-weight:bold;}
96
+
97
+
98
+ .container table.stats th { font-size:100%; width:40%; color:#000;}
99
+ .container hr { border:0; border-top:5px solid #efefef; margin:15px 0;}
100
+
101
+ #footer { padding:10px 5%; background:#efefef; color:#999; font-size:85%; line-height:1.5; border-top:5px solid #ccc; padding-top:10px;}
102
+ #footer p a { color:#999;}
103
+
104
+ .container p.poll { background:url(image-url('<%= asset_path('resque_web/poll.png') %>')) no-repeat 0 2px; padding:3px 0; padding-left:23px; float:right; font-size:85%; }
105
+
106
+ .container ul.failed {margin-top: 20px;}
107
+ .container ul.failed li {
108
+ background: #efefef; /* Old browsers */
109
+ background: -moz-linear-gradient(top, #efefef 0%, #fff 100%); /* FF3.6+ */
110
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#efefef), color-stop(100%,#fff)); /* Chrome,Safari4+ */
111
+ background: -webkit-linear-gradient(top, #efefef 0%,#fff 100%); /* Chrome10+,Safari5.1+ */
112
+ background: -o-linear-gradient(top, #efefef 0%,#fff 100%); /* Opera 11.10+ */
113
+ background: -ms-linear-gradient(top, #efefef 0%,#fff 100%); /* IE10+ */
114
+ background: linear-gradient(to bottom, #efefef 0%,#fff 100%); /* W3C */
115
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#efefef', endColorstr='#fff',GradientType=0 ); /* IE6-8 */
116
+
117
+ margin-top:10px;
118
+ padding:10px;
119
+ overflow:hidden;
120
+ border:1px solid #ccc;
121
+ -webkit-border-radius:5px;
122
+ -moz-border-radius:5px;
123
+ border-radius:5px;
124
+ }
125
+ .container ul.failed li dl dt {font-size:80%; color:#999; width:60px; float:left; padding-top:1px; text-align:right;}
126
+ .container ul.failed li dl dd {margin-bottom:10px; margin-left:70px;}
127
+ .container ul.failed li dl dd .retried { float:right; text-align: right; }
128
+ .container ul.failed li dl dd .retried .remove { display:none; margin-top: 8px; }
129
+ .container ul.failed li.hover dl dd .retried .remove { display:block; }
130
+ .container ul.failed li dl dd .controls { display:none; float:right; }
131
+ .container ul.failed li.hover dl dd .controls { display:block; }
132
+ .container ul.failed li dl dd code, .container ul.failed li dl dd pre { font-family:Monaco, "Courier New", monospace; font-size:90%; white-space: pre-wrap;}
133
+ .container ul.failed li dl dd.error a {font-family:Monaco, "Courier New", monospace; font-size:90%; }
134
+ .container ul.failed li dl dd.error pre { margin-top:3px; line-height:1.3;}
135
+
136
+ .container p.pagination { background:#efefef; padding:10px; overflow:hidden;}
137
+ .container p.pagination a.less { float:left;}
138
+ .container p.pagination a.more { float:right;}
139
+
140
+ .container form {float:right; margin-top:-10px;margin-left:10px;}
141
+
142
+ .container .time a.toggle_format {text-decoration:none;}
143
+
144
+ #failed tr.total td {background-color: #FFECEC; color: #D37474; font-size: 15px; font-weight: bold;}
145
+ #failed .center {text-align: center;}
146
+ #failed .failed_class { padding-left: 20px; font-size:12px; }
@@ -0,0 +1,25 @@
1
+ module ResqueWeb
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery
4
+ before_filter :set_subtabs, :authorize
5
+
6
+ helper :all
7
+
8
+ def self.subtabs(*tab_names)
9
+ return defined?(@subtabs) ? @subtabs : [] if tab_names.empty?
10
+ @subtabs = tab_names
11
+ end
12
+
13
+ def set_subtabs(subtabs = self.class.subtabs)
14
+ @subtabs = subtabs
15
+ end
16
+
17
+ private
18
+
19
+ def authorize
20
+ if ENV["RESQUE_WEB_HTTP_BASIC_AUTH_USER"] && ENV["RESQUE_WEB_HTTP_BASIC_AUTH_PASSWORD"]
21
+ authenticate_or_request_with_http_basic {|u, p| u == ENV["RESQUE_WEB_HTTP_BASIC_AUTH_USER"] && p == ENV["RESQUE_WEB_HTTP_BASIC_AUTH_PASSWORD"] }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,62 @@
1
+ module ResqueWeb
2
+ class FailuresController < ApplicationController
3
+
4
+ # Display all jobs in the failure queue
5
+ #
6
+ # @param [Hash] params
7
+ # @option params [String] :class filters failures shown by class
8
+ # @option params [String] :queue filters failures shown by failure queue name
9
+ def index
10
+ end
11
+
12
+ # remove an individual job from the failure queue
13
+ def destroy
14
+ Resque::Failure.remove(params[:id])
15
+ redirect_to failures_path(redirect_params)
16
+ end
17
+
18
+ # destroy all jobs from the failure queue
19
+ def destroy_all
20
+ queue = params[:queue] || 'failed'
21
+ Resque::Failure.clear(queue)
22
+ redirect_to failures_path(redirect_params)
23
+ end
24
+
25
+ # retry an individual job from the failure queue
26
+ def retry
27
+ reque_single_job(params[:id])
28
+ redirect_to failures_path(redirect_params)
29
+ end
30
+
31
+ # retry all jobs from the failure queue
32
+ def retry_all
33
+ if params[:queue].present? && params[:queue]!="failed"
34
+ Resque::Failure.requeue_queue(params[:queue])
35
+ else
36
+ (Resque::Failure.count-1).downto(0).each { |id| reque_single_job(id) }
37
+ end
38
+ redirect_to failures_path(redirect_params)
39
+ end
40
+
41
+ private
42
+
43
+ #API agnostic for Resque 2 with duck typing on requeue_and_remove
44
+ def reque_single_job(id)
45
+ if Resque::Failure.respond_to?(:requeue_and_remove)
46
+ Resque::Failure.requeue_and_remove(id)
47
+ else
48
+ Resque::Failure.requeue(id)
49
+ Resque::Failure.remove(id)
50
+ end
51
+ end
52
+
53
+ def redirect_params
54
+ {}.tap do |p|
55
+ if params[:queue].present?
56
+ p[:queue] = params[:queue]
57
+ end
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,7 @@
1
+ module ResqueWeb
2
+ class OverviewController < ApplicationController
3
+ def show
4
+ render :layout => !request.xhr?, :locals => { :polling => request.xhr? }
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ module ResqueWeb
2
+ class QueuesController < ApplicationController
3
+
4
+ def index
5
+ end
6
+
7
+ def show
8
+ set_subtabs view_context.queue_names
9
+ end
10
+
11
+ def destroy
12
+ Resque.remove_queue(params[:id])
13
+ redirect_to queues_path
14
+ end
15
+
16
+ def clear
17
+ Resque.redis.del("queue:#{params[:id]}")
18
+ redirect_to queue_path(params[:id])
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,36 @@
1
+ module ResqueWeb
2
+ class StatsController < ApplicationController
3
+ subtabs :resque, :redis, :keys
4
+
5
+ def index
6
+ redirect_to action: "resque"
7
+ end
8
+
9
+ def resque
10
+ respond_to do |format|
11
+ format.html
12
+ format.json { render json: Hash[Resque.info.sort] }
13
+ end
14
+ end
15
+
16
+ def redis
17
+ respond_to do |format|
18
+ format.html
19
+ format.json { render json: Hash[Resque.redis.info.sort] }
20
+ end
21
+ end
22
+
23
+ def keys
24
+ respond_to do |format|
25
+ format.html do
26
+ if params[:id]
27
+ render 'key'
28
+ else
29
+ render 'keys'
30
+ end
31
+ end
32
+ format.json { render json: Resque.keys.sort }
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ module ResqueWeb
2
+ class WorkersController < ApplicationController
3
+ before_filter :display_subtabs
4
+
5
+ def index
6
+ end
7
+
8
+ def show
9
+ if params[:id] && params[:id] != 'all'
10
+ @workers = view_context.worker_hosts[params[:id]].map { |id| Resque::Worker.find(id) }
11
+ else
12
+ @workers = Resque.workers
13
+ end
14
+ end
15
+
16
+ # def destroy
17
+ # Resque::Failure.remove(params[:id])
18
+ # redirect_to failures_path(redirect_params)
19
+ # end
20
+
21
+ def destroy
22
+ Resque::Worker.find(params[:id]).unregister_worker
23
+ format.html { redirect_to workers_path, notice: 'Worker successully killed.' }
24
+ end
25
+
26
+
27
+ private
28
+
29
+ def display_subtabs
30
+ set_subtabs view_context.worker_hosts.map(&:first)
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,8 @@
1
+ module ResqueWeb
2
+ class WorkingController < ApplicationController
3
+
4
+ def index
5
+ end
6
+
7
+ end
8
+ end