1
0
Fork 0
mirror of https://github.com/mperham/sidekiq.git synced 2022-11-09 13:52:34 -05:00

Persist live poll status in browser localStorage (#4976)

* Persist live poll status in browser localStorage

* Prefix localStorage variables with 'sidekiq'

* Minor fix for default handling in localStorage timeInterval parsing
This commit is contained in:
Stephen Humphries 2021-08-30 15:31:41 -04:00 committed by GitHub
parent 8e36432662
commit 84dd20d397
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 80 additions and 58 deletions

View file

@ -70,17 +70,6 @@ module Sidekiq
@head_html.join if defined?(@head_html)
end
def poll_path
if current_path != "" && params["poll"]
path = root_path + current_path
query_string = to_query_string(params.slice(*params.keys - %w[page poll]))
path += "?#{query_string}" unless query_string.empty?
path
else
""
end
end
def text_direction
get_locale["TextDirection"] || "ltr"
end
@ -203,7 +192,7 @@ module Sidekiq
[score.to_f, jid]
end
SAFE_QPARAMS = %w[page poll direction]
SAFE_QPARAMS = %w[page direction]
# Merge options with current params, filter safe params, and stringify to query string
def qparams(options)

View file

@ -428,12 +428,6 @@ describe Sidekiq::Web do
assert_match(/#{msg['args'][2]}/, last_response.body)
end
it 'calls updatePage() once when polling' do
get '/busy?poll=true'
assert_equal 200, last_response.status
assert_equal 1, last_response.body.scan('data-poll-path="/busy').count
end
it 'escape job args and error messages' do
# on /retries page
params = add_xss_retry
@ -647,12 +641,6 @@ describe Sidekiq::Web do
assert_equal 200, last_response.status
assert_match(/#{params.first['args'][2]}/, last_response.body)
end
it 'handles bad query input' do
get '/queues/foo?page=B<H'
assert_equal 200, last_response.status
assert_match(/B%3CH/, last_response.body)
end
end
def add_scheduled

View file

@ -109,4 +109,19 @@ class TestWebHelpers < Minitest::Test
s = o.display_args(nil)
assert_equal "Invalid job payload, args is nil", s
end
def test_to_query_string_escapes_bad_query_input
obj = Helpers.new
assert_equal "page=B%3CH", obj.to_query_string("page" => "B<H")
end
def test_qparams_string_escapes_bad_query_input
obj = Helpers.new
obj.instance_eval do
def params
{ "direction" => "H>B" }
end
end
assert_equal "direction=H%3EB&page=B%3CH", obj.qparams("page" => "B<H")
end
end

View file

@ -16,13 +16,9 @@
Sidekiq = {};
$(function() {
var pollpath = $('body').data('poll-path');
if (pollpath != "") {
var ti = parseInt(localStorage.timeInterval) || 2000;
setTimeout(function(){updatePage(pollpath)}, ti);
}
var livePollTimer = null;
$(function() {
$(document).on('click', '.check_all', function() {
$('input[type=checkbox]', $(this).closest('table')).prop('checked', this.checked);
});
@ -36,6 +32,26 @@ $(function() {
});
updateFuzzyTimes($('body').data('locale'));
if ($(".live-poll").length > 0) { // set up live poll only when button is present
$(document).on("click", ".live-poll", function() {
if (localStorage.sidekiqLivePoll == "enabled") {
localStorage.sidekiqLivePoll = "disabled";
clearTimeout(livePollTimer);
livePollTimer = null;
} else {
localStorage.sidekiqLivePoll = "enabled";
livePollCallback();
}
updateLivePollButton();
});
updateLivePollButton();
if (localStorage.sidekiqLivePoll == "enabled") {
scheduleLivePoll();
}
}
});
function updateFuzzyTimes(locale) {
@ -50,11 +66,35 @@ function updateFuzzyTimes(locale) {
t.cancel();
}
function updatePage(url) {
function updateLivePollButton() {
if (localStorage.sidekiqLivePoll == "enabled") {
$('.live-poll-stop').show();
$('.live-poll-start').hide();
} else {
$('.live-poll-start').show();
$('.live-poll-stop').hide();
}
}
function livePollCallback() {
clearTimeout(livePollTimer);
$.ajax({
url: url,
url: document.url,
dataType: 'html'
}).done(function(data) {
}).done(
replacePage
).complete(
scheduleLivePoll
)
}
function scheduleLivePoll() {
let ti = parseInt(localStorage.sidekiqTimeInterval) || 5000;
livePollTimer = setTimeout(livePollCallback, ti);
}
function replacePage(data) {
$data = $(data)
var $page = $data.filter('#page')
@ -64,13 +104,6 @@ function updatePage(url) {
$('.status').replaceWith($header_status)
updateFuzzyTimes($('body').data('locale'));
var ti = parseInt(localStorage.timeInterval) || 2000;
setTimeout(function(){updatePage(url)}, ti)
}).fail(function() {
var ti = parseInt(localStorage.timeInterval) || 2000;
setTimeout(function(){updatePage(url)}, ti)
})
}
$(function() {

View file

@ -17,7 +17,7 @@ var nodes=vis.selectAll("path").data(series.stack.filter(function(d){return d.y!
var poller;
var realtimeGraph = function(updatePath) {
var timeInterval = parseInt(localStorage.timeInterval || '5000');
var timeInterval = parseInt(localStorage.sidekiqTimeInterval) || 5000;
var graphElement = document.getElementById("realtime");
var graph = new Rickshaw.Graph( {
@ -246,14 +246,14 @@ var setSliderLabel = function(val) {
$(function(){
renderGraphs();
if (typeof localStorage.timeInterval !== 'undefined'){
$('div.interval-slider input').val(localStorage.timeInterval);
setSliderLabel(localStorage.timeInterval);
if (typeof localStorage.sidekiqTimeInterval !== 'undefined'){
$('div.interval-slider input').val(localStorage.sidekiqTimeInterval);
setSliderLabel(localStorage.sidekiqTimeInterval);
}
$(document).on('change', 'div.interval-slider input', function(){
clearInterval(poller);
localStorage.timeInterval = $(this).val();
localStorage.sidekiqTimeInterval = $(this).val();
setSliderLabel($(this).val());
resetGraphs();
renderGraphs();

View file

@ -98,10 +98,10 @@ header.row .pagination {
.poll-wrapper {
margin: 9px;
}
#live-poll.active {
.live-poll.active {
background-color: #009300;
}
#live-poll.active:hover {
.live-poll.active:hover {
background-color: #777;
}
.summary_bar ul {

View file

@ -1,7 +1,4 @@
<% if current_path != '' %>
<% if params[:poll] %>
<a id="live-poll" class="btn btn-primary active" href="<%= root_path + current_path %>"><%= t('StopPolling') %></a>
<% else %>
<a id="live-poll" class="btn btn-primary" href="<%= root_path + current_path %>?<%= qparams(poll: true) %>"><%= t('LivePoll') %></a>
<% end %>
<a class="live-poll-start live-poll btn btn-primary"><%= t('LivePoll') %></a>
<a class="live-poll-stop live-poll btn btn-primary active"><%= t('StopPolling') %></a>
<% end %>

View file

@ -22,7 +22,7 @@
<meta name="google" content="notranslate" />
<%= display_custom_head %>
</head>
<body class="admin" data-poll-path="<%= poll_path %>" data-locale="<%= locale %>">
<body class="admin" data-locale="<%= locale %>">
<%= erb :_nav %>
<div id="page">
<div class="container">