From d353e142f59b8f839141f7d850f97d97606549a9 Mon Sep 17 00:00:00 2001 From: Nikolay Murga Date: Sat, 19 Jul 2014 21:34:04 +0300 Subject: [PATCH 1/3] Add compatablity for Rails-based resque-web --- .gitignore | 1 + .../resque_status/application.js.coffee | 110 +++++++ .../stylesheets/resque_status/application.css | 71 +++++ .../resque_status/application_controller.rb | 5 + .../resque_status/clear_controller.rb | 9 + .../resque_status/statuses_controller.rb | 33 +++ app/helpers/resque_status/status_helper.rb | 12 + app/views/resque_status/statuses/index.erb | 88 ++++++ app/views/resque_status/statuses/show.erb | 31 ++ config/initializers/resque_config.rb | 2 + config/routes.rb | 15 + lib/resque-status.rb | 3 + lib/resque/plugins/status/hash.rb | 270 +++++++++--------- lib/resque_status.rb | 2 + .../plugins/resque_status/engine.rb | 21 ++ resque-status.gemspec | 25 +- 16 files changed, 535 insertions(+), 163 deletions(-) create mode 100644 app/assets/javascripts/resque_status/application.js.coffee create mode 100644 app/assets/stylesheets/resque_status/application.css create mode 100644 app/controllers/resque_status/application_controller.rb create mode 100644 app/controllers/resque_status/clear_controller.rb create mode 100644 app/controllers/resque_status/statuses_controller.rb create mode 100644 app/helpers/resque_status/status_helper.rb create mode 100644 app/views/resque_status/statuses/index.erb create mode 100644 app/views/resque_status/statuses/show.erb create mode 100644 config/initializers/resque_config.rb create mode 100644 config/routes.rb create mode 100644 lib/resque_status.rb create mode 100644 lib/resque_web/plugins/resque_status/engine.rb diff --git a/.gitignore b/.gitignore index b814b61..e45e3aa 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ doc test/dump.rdb bin/ .bundle +*.iml diff --git a/app/assets/javascripts/resque_status/application.js.coffee b/app/assets/javascripts/resque_status/application.js.coffee new file mode 100644 index 0000000..f773dd6 --- /dev/null +++ b/app/assets/javascripts/resque_status/application.js.coffee @@ -0,0 +1,110 @@ +jQuery ($) -> + $('#main').attr('id', '') + $('#resque-status').attr('id', 'main') + + $('#main').on 'click', "a.status-kill", (e) -> + return false unless confirm("Are you sure you want to kill this job? There is no undo.") + $link = $(this) + $link.animate opacity: 0.5 + $.post $link.attr("href"), -> + $link.remove() + return false + + + kill_all = $('.status-kill-all') + kill_all.on 'click', -> + $link = $(this) + return false if $link.is('.disabled') + return false unless confirm("Are you sure you want to kill this job? There is no undo.") + data = { + id: [] + } + checked = $('.status-jobs-option').filter(':checked') + return false if checked.length == 0 + checked.each (index, value)-> + data['id'].push $(value).val() + + $.post($link.attr('href'), data, -> + checked.remove() + updateKillAll() + ) + return false; + + updateKillAll = -> + jobs_option = $('.status-jobs-option') + if jobs_option.length == 0 + kill_all.remove() + $('input.status-check-all').remove() + return + if jobs_option.is(':checked') + kill_all.removeClass('disabled') + else + kill_all.addClass('disabled') + + $('#main').on 'click', 'input.status-check-all', (e) -> + $('.status-jobs-option').prop('checked', $(this).prop('checked')) + updateKillAll() + + $('.status-jobs-option').on 'click', (e) -> + updateKillAll() + + updateKillAll() + + $('#main').on 'click', 'a.status-clear', (e) -> + return false unless confirm("Are you absolutely sure? This cannot be undone."); + $.ajax + type: "DELETE" + url: $(this).attr('href') + success: -> + window.location.reload() + return + false + + status_map = { + completed: 'progress-success', + failed: 'progress-danger', + working: 'progress-info', + queued: 'progress-info', + killed: 'progress-warning' + } + # itterate over the holders + checkStatus = ($status) -> + status_path = $status.data 'url' + $.getJSON status_path, (json) -> + if json + pct = "0%" + pct = json.pct_complete + "%" if json.pct_complete + + $status.find(".progress .bar").animate width: pct + $status.find(".progress .progress-pct").text pct + $status.find(".status-message").html json.message if json.message + $status.data('status', json.status) + $status.find(".progress").attr("class", "progress "+status_map[json.status]) if json.status + $status.find(".status-time").text new Date(json.time * 1000).toString() if json.time + + $details = $status.find(".status-details-body") + $details.empty() + for key of json + $row = $("").appendTo($details) + $("").text(key).appendTo $row + $("").text(printValue(key, json[key])).appendTo $row + + status = $status.data("status") + if status is "working" or status is "queued" or status is "" + setTimeout (-> + checkStatus($status) + ), 1500 + return + + return + printValue = (key, value) -> + if /(^|_)time$/.test(key) and typeof value is "number" + time = new Date() + time.setTime value * 1000 + time.toUTCString() + else + JSON.stringify value + + $(".status-holder").each -> + checkStatus $(this) + return diff --git a/app/assets/stylesheets/resque_status/application.css b/app/assets/stylesheets/resque_status/application.css new file mode 100644 index 0000000..7fed727 --- /dev/null +++ b/app/assets/stylesheets/resque_status/application.css @@ -0,0 +1,71 @@ + +th.progress { + width: 100px; +} +td.status { + font-weight: bold; +} +/*td.progress .progress-bar {*/ + /*position: absolute;*/ + /*top: 0px;*/ + /*left: 0px;*/ + /*background: #999;*/ + /*display:block;*/ + /*height: 100%;*/ + /*z-index: 0;*/ + /*opacity: 0.5;*/ + /*-moz-opacity: 0.5;*/ + /*-webkit-opacity: 0.5;*/ +/*}*/ +.resque-status .progress { + margin: 0; + position: relative; +} +.resque-status .progress .progress-pct { + z-index: 10; + /*color: #333;*/ + color: #ffffff; + text-shadow: 1px 1px 2px black; + text-align: center; + position: absolute; + width: 100%; +} + +.status-completed { + color:#61BF55; +} +.status-failed { + color: #E47E74; +} +.status-working { + color: #528499; +} +.status-killed { + color: #B84F16; +} + +.status-holder { + background: #F7F7F7; + border: 1px solid #E5E5E5; + padding: 20px; + font-size: 110%; + margin-bottom: 40px; +} +.status-message { + font-weight: bold; +} + +.status-time { + font-size: 70%; + padding: 10px 0px; + color: #999; +} + +#main a.status-kill:link, #main a.status-kill:visited { + color: #B84F16; + font-weight: bold; +} + +.status-clear { + margin-left:5px +} diff --git a/app/controllers/resque_status/application_controller.rb b/app/controllers/resque_status/application_controller.rb new file mode 100644 index 0000000..4841afd --- /dev/null +++ b/app/controllers/resque_status/application_controller.rb @@ -0,0 +1,5 @@ +module ResqueStatus + class ApplicationController < ResqueWeb::ApplicationController + helper :all + end +end diff --git a/app/controllers/resque_status/clear_controller.rb b/app/controllers/resque_status/clear_controller.rb new file mode 100644 index 0000000..5cea3e7 --- /dev/null +++ b/app/controllers/resque_status/clear_controller.rb @@ -0,0 +1,9 @@ +module ResqueStatus + class ClearController < ResqueStatus::ApplicationController + def destroy + params[:id] = nil if params[:id] == 'all' + Resque::Plugins::Status::Hash.clear(params[:id]) + head :no_content + end + end +end diff --git a/app/controllers/resque_status/statuses_controller.rb b/app/controllers/resque_status/statuses_controller.rb new file mode 100644 index 0000000..de02599 --- /dev/null +++ b/app/controllers/resque_status/statuses_controller.rb @@ -0,0 +1,33 @@ +module ResqueStatus + class StatusesController < ResqueStatus::ApplicationController + layout 'resque_web/application' + def show + @status = Resque::Plugins::Status::Hash.get(params[:id]) + @polling = request.xhr? + respond_to do |format| + format.html + format.json { render :json => @status.json } + end + end + + def index + @start = params[:start].to_i + @end = @start + (params[:per_page] || 20)-1 + @statuses = Resque::Plugins::Status::Hash.statuses(@start, @end) + @size = Resque::Plugins::Status::Hash.count + @polling = request.xhr? + @has_killable = @statuses.select(&:killable?).size > 0 + respond_to do |format| + format.html {render :layout => !request.xhr? } + end + end + + def kill + ids = params[:ids] || Array(params[:id]) + ids.each do |id| + Resque::Plugins::Status::Hash.kill(params[:id]) + end + head :no_content + end + end +end diff --git a/app/helpers/resque_status/status_helper.rb b/app/helpers/resque_status/status_helper.rb new file mode 100644 index 0000000..8c4a235 --- /dev/null +++ b/app/helpers/resque_status/status_helper.rb @@ -0,0 +1,12 @@ +module ResqueStatus + module StatusHelper + def status_poll(start) + if @polling + text = "Last Updated: #{Time.now.strftime("%H:%M:%S")}" + else + text = "Live Poll" + end + "

#{text}

" + end + end +end diff --git a/app/views/resque_status/statuses/index.erb b/app/views/resque_status/statuses/index.erb new file mode 100644 index 0000000..02b39b8 --- /dev/null +++ b/app/views/resque_status/statuses/index.erb @@ -0,0 +1,88 @@ +<% unless @polling %> +
+<% end %> +
+

Statuses

+

These are recent jobs created with the Resque::Plugins::Status class

+ + <% unless @statuses.empty? %> + + + <% if @has_killable && !@polling %> + Kill sellected + <% end %> +
+

+ <% end %> + + + + + + + + + + + + + + <% unless @statuses.empty? %> + <% @statuses.each do |status| %> + + + + + + + + + + + <% end %> + <% else %> + + + + <% end %> +
+ <% if @has_killable && !@polling%> + + <% end %> + IDNameStatusLast Updated% CompleteMessageKill
+ <% if status.killable? && !@polling %> + + <%end%> + <%= status.uuid %><%= status.name %><%= status.status %><%= status.time.strftime("%Y/%m/%d %H:%M:%S %z") %> +
+
<%= status.pct_complete ? "#{status.pct_complete}%" : '' %>
+
+ +
+
+
<%= status.message %> + <% if status.killable? %>Kill + <% end %>
No Statuses right now...
+ + <% unless @statuses.empty? %> + <%= pagination :start => @start, :total => @size, :per_page => 20 %> + <% end %> + + <%= status_poll(@start).html_safe%> +
+ +<% unless @polling %> +
+ + <%= javascript_include_tag "resque_status/application" %> + <%= stylesheet_link_tag "resque_status/application", :media => "all" %> +<% end %> diff --git a/app/views/resque_status/statuses/show.erb b/app/views/resque_status/statuses/show.erb new file mode 100644 index 0000000..b67b081 --- /dev/null +++ b/app/views/resque_status/statuses/show.erb @@ -0,0 +1,31 @@ +
+

Statuses: <%= @status.uuid %>/<%= @status.name %>

+ +

Viewing a specific job created with Resque::Plugins::Status. + Return to the list of statuses

+ +
+
+
+
<%= @status.pct_complete %>%
+
+
<%= @status.message %>
+
<%= @status.time? ? @status.time : 'Not started' %>
+

Details

+ +
+ + + + + + + + + +
KeyValue
+
+
+
+<%= javascript_include_tag "resque_status/application" %> +<%= stylesheet_link_tag "resque_status/application", :media => "all" %> diff --git a/config/initializers/resque_config.rb b/config/initializers/resque_config.rb new file mode 100644 index 0000000..3878226 --- /dev/null +++ b/config/initializers/resque_config.rb @@ -0,0 +1,2 @@ +config = ENV.fetch("RAILS_RESQUE_REDIS", "127.0.0.1:6379") +Resque.redis = config diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..a1884f7 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,15 @@ +# Match IDs with dots in them +id_pattern = /[^\/]+/ +ResqueWeb::Plugins::ResqueStatus::Engine.routes.draw do + resources :statuses, :only => [:show,:index] do + member do + post :kill + end + collection do + resources :clear, :only => [:destroy] + end + end + root 'statuses#index' + + +end diff --git a/lib/resque-status.rb b/lib/resque-status.rb index defb135..1feb61a 100644 --- a/lib/resque-status.rb +++ b/lib/resque-status.rb @@ -1 +1,4 @@ require "#{File.dirname(__FILE__)}/resque/status" +require 'resque_status' +require 'resque_web/plugins/resque_status/engine' if defined?(Rails) + diff --git a/lib/resque/plugins/status/hash.rb b/lib/resque/plugins/status/hash.rb index bb5ae89..733a0c7 100644 --- a/lib/resque/plugins/status/hash.rb +++ b/lib/resque/plugins/status/hash.rb @@ -8,170 +8,162 @@ module Status # the common status attributes. It also has a number of class methods for # creating/updating/retrieving status objects from Redis class Hash < ::Hash + class << self + # Create a status, generating a new UUID, passing the message to the status + # Returns the UUID of the new status. + def create(uuid, *messages) + set(uuid, *messages) + redis.zadd(set_key, Time.now.to_i, uuid) + redis.zremrangebyscore(set_key, 0, Time.now.to_i - @expire_in) if @expire_in + uuid + end - # Create a status, generating a new UUID, passing the message to the status - # Returns the UUID of the new status. - def self.create(uuid, *messages) - set(uuid, *messages) - redis.zadd(set_key, Time.now.to_i, uuid) - redis.zremrangebyscore(set_key, 0, Time.now.to_i - @expire_in) if @expire_in - uuid - end - - # Get a status by UUID. Returns a Resque::Plugins::Status::Hash - def self.get(uuid) - val = redis.get(status_key(uuid)) - val ? Resque::Plugins::Status::Hash.new(uuid, decode(val)) : nil - end - - # Get multiple statuses by UUID. Returns array of Resque::Plugins::Status::Hash - def self.mget(uuids) - return [] if uuids.empty? - status_keys = uuids.map{|u| status_key(u)} - vals = redis.mget(*status_keys) - - uuids.zip(vals).map do |uuid, val| + # Get a status by UUID. Returns a Resque::Plugins::Status::Hash + def get(uuid) + val = redis.get(status_key(uuid)) val ? Resque::Plugins::Status::Hash.new(uuid, decode(val)) : nil end - end - # set a status by UUID. messages can be any number of strings or hashes - # that are merged in order to create a single status. - def self.set(uuid, *messages) - val = Resque::Plugins::Status::Hash.new(uuid, *messages) - redis.set(status_key(uuid), encode(val)) - if expire_in - redis.expire(status_key(uuid), expire_in) + # Get multiple statuses by UUID. Returns array of Resque::Plugins::Status::Hash + def mget(uuids) + return [] if uuids.empty? + status_keys = uuids.map { |u| status_key(u) } + vals = redis.mget(*status_keys) + + uuids.zip(vals).map do |uuid, val| + val ? Resque::Plugins::Status::Hash.new(uuid, decode(val)) : nil + end end - val - end - # clear statuses from redis passing an optional range. See `statuses` for info - # about ranges - def self.clear(range_start = nil, range_end = nil) - status_ids(range_start, range_end).each do |id| - remove(id) + # set a status by UUID. messages can be any number of strings or hashes + # that are merged in order to create a single status. + def set(uuid, *messages) + val = Resque::Plugins::Status::Hash.new(uuid, *messages) + redis.set(status_key(uuid), encode(val)) + if expire_in + redis.expire(status_key(uuid), expire_in) + end + val end - end - def self.clear_completed(range_start = nil, range_end = nil) - status_ids(range_start, range_end).select do |id| - get(id).completed? - end.each do |id| - remove(id) + # clear statuses from redis passing an optional range. See `statuses` for info + # about ranges + def clear(status = nil, range_start = nil, range_end = nil) + ids = status_ids(range_start, range_end) + ids = ids.select do |id| + get(id)['status'] === status.to_s + end if status + ids.each { |id| remove(id) } end - end - def self.clear_failed(range_start = nil, range_end = nil) - status_ids(range_start, range_end).select do |id| - get(id).failed? - end.each do |id| - remove(id) + Resque::Plugins::Status::STATUSES.each do |status| + define_method("clear_#{status}") do + clear("#{status}") + end end - end - def self.remove(uuid) - redis.del(status_key(uuid)) - redis.zrem(set_key, uuid) - end + def remove(uuid) + redis.del(status_key(uuid)) + redis.zrem(set_key, uuid) + end - def self.count - redis.zcard(set_key) - end + def count + redis.zcard(set_key) + end - # Return num Resque::Plugins::Status::Hash objects in reverse chronological order. - # By default returns the entire set. - # @param [Numeric] range_start The optional starting range - # @param [Numeric] range_end The optional ending range - # @example retuning the last 20 statuses - # Resque::Plugins::Status::Hash.statuses(0, 20) - def self.statuses(range_start = nil, range_end = nil) - ids = status_ids(range_start, range_end) - mget(ids).compact || [] - end + # Return num Resque::Plugins::Status::Hash objects in reverse chronological order. + # By default returns the entire set. + # @param [Numeric] range_start The optional starting range + # @param [Numeric] range_end The optional ending range + # @example retuning the last 20 statuses + # Resque::Plugins::Status::Hash.statuses(0, 20) + def statuses(range_start = nil, range_end = nil) + ids = status_ids(range_start, range_end) + mget(ids).compact || [] + end - # Return the num most recent status/job UUIDs in reverse chronological order. - def self.status_ids(range_start = nil, range_end = nil) - if range_end && range_start - # Because we want a reverse chronological order, we need to get a range starting - # by the higest negative number. The ordering is transparent from the API user's - # perspective so we need to convert the passed params - (redis.zrevrange(set_key, (range_start.abs), ((range_end || 1).abs)) || []) - else - # Because we want a reverse chronological order, we need to get a range starting - # by the higest negative number. - redis.zrevrange(set_key, 0, -1) || [] + # Return the num most recent status/job UUIDs in reverse chronological order. + def status_ids(range_start = nil, range_end = nil) + if range_end && range_start + # Because we want a reverse chronological order, we need to get a range starting + # by the higest negative number. The ordering is transparent from the API user's + # perspective so we need to convert the passed params + (redis.zrevrange(set_key, (range_start.abs), ((range_end || 1).abs)) || []) + else + # Because we want a reverse chronological order, we need to get a range starting + # by the higest negative number. + redis.zrevrange(set_key, 0, -1) || [] + end end - end - # Kill the job at UUID on its next iteration this works by adding the UUID to a - # kill list (a.k.a. a list of jobs to be killed. Each iteration the job checks - # if it _should_ be killed by calling tick or at. If so, it raises - # a Resque::Plugins::Status::Killed error and sets the status to 'killed'. - def self.kill(uuid) - redis.sadd(kill_key, uuid) - end + # Kill the job at UUID on its next iteration this works by adding the UUID to a + # kill list (a.k.a. a list of jobs to be killed. Each iteration the job checks + # if it _should_ be killed by calling tick or at. If so, it raises + # a Resque::Plugins::Status::Killed error and sets the status to 'killed'. + def kill(uuid) + redis.sadd(kill_key, uuid) + end - # Remove the job at UUID from the kill list - def self.killed(uuid) - redis.srem(kill_key, uuid) - end + # Remove the job at UUID from the kill list + def killed(uuid) + redis.srem(kill_key, uuid) + end - # Return the UUIDs of the jobs on the kill list - def self.kill_ids - redis.smembers(kill_key) - end + # Return the UUIDs of the jobs on the kill list + def kill_ids + redis.smembers(kill_key) + end - # Kills num jobs within range starting with the most recent first. - # By default kills all jobs. - # Note that the same conditions apply as kill, i.e. only jobs that check - # on each iteration by calling tick or at are eligible to killed. - # @param [Numeric] range_start The optional starting range - # @param [Numeric] range_end The optional ending range - # @example killing the last 20 submitted jobs - # Resque::Plugins::Status::Hash.killall(0, 20) - def self.killall(range_start = nil, range_end = nil) - status_ids(range_start, range_end).collect do |id| - kill(id) + # Kills num jobs within range starting with the most recent first. + # By default kills all jobs. + # Note that the same conditions apply as kill, i.e. only jobs that check + # on each iteration by calling tick or at are eligible to killed. + # @param [Numeric] range_start The optional starting range + # @param [Numeric] range_end The optional ending range + # @example killing the last 20 submitted jobs + # Resque::Plugins::Status::Hash.killall(0, 20) + def killall(range_start = nil, range_end = nil) + status_ids(range_start, range_end).collect do |id| + kill(id) + end end - end - # Check whether a job with UUID is on the kill list - def self.should_kill?(uuid) - redis.sismember(kill_key, uuid) - end + # Check whether a job with UUID is on the kill list + def should_kill?(uuid) + redis.sismember(kill_key, uuid) + end - # The time in seconds that jobs and statuses should expire from Redis (after - # the last time they are touched/updated) - def self.expire_in - @expire_in - end + # The time in seconds that jobs and statuses should expire from Redis (after + # the last time they are touched/updated) + def expire_in + @expire_in + end - # Set the expire_in time in seconds - def self.expire_in=(seconds) - @expire_in = seconds.nil? ? nil : seconds.to_i - end + # Set the expire_in time in seconds + def expire_in=(seconds) + @expire_in = seconds.nil? ? nil : seconds.to_i + end - def self.status_key(uuid) - "status:#{uuid}" - end + def status_key(uuid) + "status:#{uuid}" + end - def self.set_key - "_statuses" - end + def set_key + "_statuses" + end - def self.kill_key - "_kill" - end + def kill_key + "_kill" + end - def self.generate_uuid - SecureRandom.hex.to_s - end + def generate_uuid + SecureRandom.hex.to_s + end - def self.hash_accessor(name, options = {}) - options[:default] ||= nil - coerce = options[:coerce] ? ".#{options[:coerce]}" : "" - module_eval <<-EOT + def hash_accessor(name, options = {}) + options[:default] ||= nil + coerce = options[:coerce] ? ".#{options[:coerce]}" : "" + module_eval <<-EOT def #{name} value = (self['#{name}'] ? self['#{name}']#{coerce} : #{options[:default].inspect}) yield value if block_given? @@ -185,11 +177,11 @@ def #{name}=(value) def #{name}? !!self['#{name}'] end - EOT - end + EOT + end + + # Proxy deprecated methods directly back to Resque itself. - # Proxy deprecated methods directly back to Resque itself. - class << self [:redis, :encode, :decode].each do |method| define_method(method) { |*args| Resque.send(method, *args) } end diff --git a/lib/resque_status.rb b/lib/resque_status.rb new file mode 100644 index 0000000..a10505a --- /dev/null +++ b/lib/resque_status.rb @@ -0,0 +1,2 @@ +module ResqueStatus +end diff --git a/lib/resque_web/plugins/resque_status/engine.rb b/lib/resque_web/plugins/resque_status/engine.rb new file mode 100644 index 0000000..12e3b1c --- /dev/null +++ b/lib/resque_web/plugins/resque_status/engine.rb @@ -0,0 +1,21 @@ +module ResqueWeb + module Plugins + module ResqueStatus + class Engine < ::Rails::Engine + # isolate or not? + isolate_namespace ::ResqueStatus + initializer "resque_status.assets.precompile" do |app| + app.config.assets.precompile += %w(resque_status/application.css resque_status/application.js.coffee) + end + end + + def self.engine_path + '/statuses' + end + + def self.tabs + [{'Status' => '/resque_web/statuses'}] + end + end + end +end diff --git a/resque-status.gemspec b/resque-status.gemspec index cbb623a..34770a4 100644 --- a/resque-status.gemspec +++ b/resque-status.gemspec @@ -18,30 +18,7 @@ Gem::Specification.new do |s| "LICENSE", "README.rdoc" ] - s.files = [ - ".document", - "Gemfile", - "Gemfile.lock", - "LICENSE", - "README.rdoc", - "Rakefile", - "examples/sleep_job.rb", - "init.rb", - "lib/resque-status.rb", - "lib/resque/job_with_status.rb", - "lib/resque/plugins/status.rb", - "lib/resque/plugins/status/hash.rb", - "lib/resque/server/views/status.erb", - "lib/resque/server/views/status_styles.erb", - "lib/resque/server/views/statuses.erb", - "lib/resque/status.rb", - "lib/resque/status_server.rb", - "resque-status.gemspec", - "test/redis-test.conf", - "test/test_helper.rb", - "test/test_resque_plugins_status.rb", - "test/test_resque_plugins_status_hash.rb" - ] + s.files = Dir['{lib,config,app}/**/*'] s.homepage = "http://github.com/quirkey/resque-status" s.rubyforge_project = "quirkey" s.rubygems_version = "2.2.1" From 28dab1dcb969f887b54e96ce74cc3946ce8b19de Mon Sep 17 00:00:00 2001 From: Nikolay Murga Date: Wed, 23 Jul 2014 15:15:18 +0300 Subject: [PATCH 2/3] Fix tab url --- lib/resque_web/plugins/resque_status/engine.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resque_web/plugins/resque_status/engine.rb b/lib/resque_web/plugins/resque_status/engine.rb index 12e3b1c..86fba92 100644 --- a/lib/resque_web/plugins/resque_status/engine.rb +++ b/lib/resque_web/plugins/resque_status/engine.rb @@ -14,7 +14,7 @@ def self.engine_path end def self.tabs - [{'Status' => '/resque_web/statuses'}] + [{'Status' => Engine.app.url_helpers.statuses_path}] end end end From e4950dd304fac4e879aaa4391f0c1198e653b632 Mon Sep 17 00:00:00 2001 From: Nikolay Murga Date: Wed, 23 Jul 2014 16:41:12 +0300 Subject: [PATCH 3/3] Fix colspan --- app/views/resque_status/statuses/index.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/resque_status/statuses/index.erb b/app/views/resque_status/statuses/index.erb index 02b39b8..3b97034 100644 --- a/app/views/resque_status/statuses/index.erb +++ b/app/views/resque_status/statuses/index.erb @@ -68,7 +68,7 @@ <% end %> <% else %> - No Statuses right now... + No Statuses right now... <% end %>