roundhouse_ui 0.2.0 → 0.4.0
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.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30b9ee99930148d47a69b86e7a4c079231f8a2504a9a24aaa17a625e39e96429
|
|
4
|
+
data.tar.gz: 333e7892afa4690288d35c671249f3fad6c3a19e304f9b4952346fe0f873a9fd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9391d5af40b1fa0db7de47fab56009cf6d11bb80f2c16d4d65bc4b7b2b376eb7ac7cff595dfe0ebdaa0df401436f811cfc1f9a3d52028aef491c7d5821b0e322
|
|
7
|
+
data.tar.gz: 8099ad548223bbb7d91f13a51b86e62010eb269f446d380c95fa4a416a1f4f95979631e9cbdd5115973bfa98d363ab04f5ef9d1801462a51ce215a5a28f57abe
|
data/README.md
CHANGED
|
@@ -79,9 +79,17 @@ RoundhouseUi.configure do |c|
|
|
|
79
79
|
|
|
80
80
|
# Where queue snapshots are stored (default: Redis). Swap for a file/S3 store.
|
|
81
81
|
# c.snapshot_store = MyS3SnapshotStore.new
|
|
82
|
+
|
|
83
|
+
# Fold sidekiq-failures' `failed` set into the Errors view (see below).
|
|
84
|
+
# No-op unless the sidekiq-failures gem is loaded. Default: off.
|
|
85
|
+
c.show_sidekiq_failures = true
|
|
82
86
|
end
|
|
83
87
|
```
|
|
84
88
|
|
|
89
|
+
Every option is independent and has a safe default — set only what you need.
|
|
90
|
+
`read_only`, `allow_job_editing`, and `show_sidekiq_failures` default to `false`;
|
|
91
|
+
`redact_args` to `[]`; `observability` to a no-op adapter; `snapshot_store` to Redis.
|
|
92
|
+
|
|
85
93
|
## Pausing queues
|
|
86
94
|
|
|
87
95
|
Pause/resume is pure OSS. To make a pause actually stop a queue from being worked,
|
|
@@ -99,6 +107,27 @@ all of Sidekiq's weighting/ordering. Until it's installed, the Queues page recor
|
|
|
99
107
|
but **warns that they aren't enforced** (worker and web are separate processes, so
|
|
100
108
|
Roundhouse detects whether a fetcher has reported in).
|
|
101
109
|
|
|
110
|
+
> ⚠️ **Sidekiq Pro/Enterprise users:** super_fetch / reliable fetch sets its own
|
|
111
|
+
> `fetch_class`, and Sidekiq allows only one. Installing `RoundhouseUi::Fetch` would
|
|
112
|
+
> **replace reliable fetch and lose its crash-recovery guarantees** — don't. On those
|
|
113
|
+
> tiers, leave the fetch strategy out; pause/resume stays inert and the UI says so.
|
|
114
|
+
|
|
115
|
+
## Surfacing sidekiq-failures
|
|
116
|
+
|
|
117
|
+
If you use [`sidekiq-failures`](https://github.com/mhfs/sidekiq-failures), failures it
|
|
118
|
+
records live in their own Redis set — which Roundhouse doesn't read by default. Jobs with
|
|
119
|
+
`retry: false` are the common case: they fail, get recorded there, but never enter the
|
|
120
|
+
retry or dead sets, so they're invisible in Roundhouse. Opt in to fold them into the
|
|
121
|
+
grouped **Errors** view:
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
# config/initializers/roundhouse.rb
|
|
125
|
+
RoundhouseUi.configure { |c| c.show_sidekiq_failures = true }
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
It's a no-op unless `sidekiq-failures` is loaded. Failures appear in **Errors** grouped by
|
|
129
|
+
job class + error (not yet as an individual-job list with per-row actions).
|
|
130
|
+
|
|
102
131
|
## Cancelling jobs
|
|
103
132
|
|
|
104
133
|
Cancellation is cooperative — Ruby can't safely kill a running thread. Install the
|
|
@@ -18,7 +18,7 @@ module RoundhouseUi
|
|
|
18
18
|
scanned = 0
|
|
19
19
|
truncated = false
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
sources.each do |source, set|
|
|
22
22
|
set.each do |entry|
|
|
23
23
|
scanned += 1
|
|
24
24
|
if scanned > SCAN_LIMIT
|
|
@@ -35,6 +35,17 @@ module RoundhouseUi
|
|
|
35
35
|
[ list, scanned, truncated ]
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
# Sidekiq's native sets, plus the sidekiq-failures `failed` set when opted in
|
|
39
|
+
# and that gem is loaded. Its FailureSet is a Sidekiq::JobSet, so it iterates
|
|
40
|
+
# exactly like the others — no special-casing in the aggregation above.
|
|
41
|
+
def sources
|
|
42
|
+
sets = { "retry" => Sidekiq::RetrySet.new, "dead" => Sidekiq::DeadSet.new }
|
|
43
|
+
if RoundhouseUi.show_sidekiq_failures && defined?(Sidekiq::Failures::FailureSet)
|
|
44
|
+
sets["failed"] = Sidekiq::Failures::FailureSet.new
|
|
45
|
+
end
|
|
46
|
+
sets
|
|
47
|
+
end
|
|
48
|
+
|
|
38
49
|
def record(groups, source, entry)
|
|
39
50
|
error = entry.item["error_class"] || "UnknownError"
|
|
40
51
|
group = (groups["#{entry.klass}|#{error}"] ||= {
|
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
.rh-badge.crit { background:rgba(230,106,96,.16); color:var(--crit); }
|
|
47
47
|
|
|
48
48
|
.rh-main { padding:22px 30px 70px; max-width:1180px; }
|
|
49
|
+
:root[data-width="full"] .rh-main { max-width:none; }
|
|
50
|
+
.rh-iconbtn.is-on { color:var(--text); border-color:var(--accent); }
|
|
49
51
|
.rh-top { display:flex; align-items:center; gap:14px; margin-bottom:22px; }
|
|
50
52
|
.rh-top h1 { font-size:21px; font-weight:650; letter-spacing:-.02em; margin:0; }
|
|
51
53
|
.rh-crumb { color:var(--faint); font-size:13px; }
|
|
@@ -148,7 +150,7 @@
|
|
|
148
150
|
</style>
|
|
149
151
|
<%# Apply the saved theme before first paint so it persists across navigations with no flash. %>
|
|
150
152
|
<script nonce="<%= content_nonce %>">
|
|
151
|
-
(function () { try { var t = localStorage.getItem("rh-theme"); if (t) document.documentElement.setAttribute("data-theme", t); } catch (e) {} })();
|
|
153
|
+
(function () { try { var t = localStorage.getItem("rh-theme"); if (t) document.documentElement.setAttribute("data-theme", t); var w = localStorage.getItem("rh-width"); if (w) document.documentElement.setAttribute("data-width", w); } catch (e) {} })();
|
|
152
154
|
</script>
|
|
153
155
|
<%# Turbo Drive: link navigation without full-page reloads (kills the flicker). %>
|
|
154
156
|
<script src="<%= turbo_js_path %>"></script>
|
|
@@ -212,6 +214,7 @@
|
|
|
212
214
|
}
|
|
213
215
|
function startOnce() { if (started) return; started = true; poll(); setInterval(poll, 2500); }
|
|
214
216
|
function syncTheme() { var b = document.getElementById("rh-theme"); if (b) b.textContent = document.documentElement.getAttribute("data-theme") === "light" ? "☀" : "☾"; }
|
|
217
|
+
function syncWidth() { var b = document.getElementById("rh-width"); if (b) b.classList.toggle("is-on", document.documentElement.getAttribute("data-width") === "full"); }
|
|
215
218
|
|
|
216
219
|
// The sidebar is turbo-permanent (so its badges don't flicker), so we move
|
|
217
220
|
// the active-nav highlight ourselves on each navigation.
|
|
@@ -233,6 +236,14 @@
|
|
|
233
236
|
try { localStorage.setItem("rh-theme", next); } catch (_) {}
|
|
234
237
|
syncTheme();
|
|
235
238
|
});
|
|
239
|
+
// width toggle (compact 1180px ⟷ full) — same persistence pattern as theme
|
|
240
|
+
document.addEventListener("click", function (e) {
|
|
241
|
+
var b = e.target.closest && e.target.closest("#rh-width"); if (!b) return;
|
|
242
|
+
var next = document.documentElement.getAttribute("data-width") === "full" ? "compact" : "full";
|
|
243
|
+
document.documentElement.setAttribute("data-width", next);
|
|
244
|
+
try { localStorage.setItem("rh-width", next); } catch (_) {}
|
|
245
|
+
syncWidth();
|
|
246
|
+
});
|
|
236
247
|
// command palette (⌘K)
|
|
237
248
|
var CMDS = [
|
|
238
249
|
{ label: "Dashboard", path: "<%= root_path %>", icon: "▦" },
|
|
@@ -249,7 +260,8 @@
|
|
|
249
260
|
{ label: "Snapshots", path: "<%= snapshots_path %>", icon: "⛁" },
|
|
250
261
|
{ label: "Audit log", path: "<%= audit_log_path %>", icon: "☷" },
|
|
251
262
|
<% if RoundhouseUi.allow_job_editing %>{ label: "Enqueue job", path: "<%= new_job_path %>", icon: "+" },<% end %>
|
|
252
|
-
{ label: "Toggle theme", action: "theme", icon: "◐" }
|
|
263
|
+
{ label: "Toggle theme", action: "theme", icon: "◐" },
|
|
264
|
+
{ label: "Toggle full width", action: "width", icon: "⟷" }
|
|
253
265
|
];
|
|
254
266
|
var palSel = 0, palFiltered = [];
|
|
255
267
|
function palEl() { return document.getElementById("rh-palette"); }
|
|
@@ -280,6 +292,7 @@
|
|
|
280
292
|
function palRun(c) {
|
|
281
293
|
palClose();
|
|
282
294
|
if (c.action === "theme") { var b = document.getElementById("rh-theme"); if (b) b.click(); return; }
|
|
295
|
+
if (c.action === "width") { var wb = document.getElementById("rh-width"); if (wb) wb.click(); return; }
|
|
283
296
|
if (c.path) { window.Turbo ? Turbo.visit(c.path) : (location.href = c.path); }
|
|
284
297
|
}
|
|
285
298
|
function palOpen() { var p = palEl(), i = palInputEl(); if (!p || !i) return; p.hidden = false; i.value = ""; palSel = 0; palRender(); i.focus(); }
|
|
@@ -299,8 +312,8 @@
|
|
|
299
312
|
else if (e.key === "Enter") { e.preventDefault(); if (palFiltered[palSel]) palRun(palFiltered[palSel]); }
|
|
300
313
|
});
|
|
301
314
|
|
|
302
|
-
document.addEventListener("turbo:load", function () { startOnce(); syncTheme(); setActiveNav(); draw(); });
|
|
303
|
-
document.addEventListener("DOMContentLoaded", function () { startOnce(); syncTheme(); setActiveNav(); });
|
|
315
|
+
document.addEventListener("turbo:load", function () { startOnce(); syncTheme(); syncWidth(); setActiveNav(); draw(); });
|
|
316
|
+
document.addEventListener("DOMContentLoaded", function () { startOnce(); syncTheme(); syncWidth(); setActiveNav(); });
|
|
304
317
|
document.addEventListener("visibilitychange", function () { if (!document.hidden) poll(); });
|
|
305
318
|
})();
|
|
306
319
|
</script>
|
|
@@ -345,6 +358,7 @@
|
|
|
345
358
|
<span class="rh-live"><span class="rh-dot"></span> live · <span class="num" data-stat="rate">—</span>/min</span>
|
|
346
359
|
<% if RoundhouseUi.read_only %><span class="rh-ro">read-only</span><% end %>
|
|
347
360
|
<button class="rh-kbd" id="rh-palette-open" type="button" title="Command palette (⌘K)">⌘K</button>
|
|
361
|
+
<button class="rh-iconbtn" id="rh-width" type="button" title="Toggle full width" aria-label="Toggle full width">⟷</button>
|
|
348
362
|
<button class="rh-iconbtn" id="rh-theme" type="button" title="Toggle theme" aria-label="Toggle theme">☾</button>
|
|
349
363
|
</header>
|
|
350
364
|
|
data/lib/roundhouse_ui.rb
CHANGED
|
@@ -51,6 +51,12 @@ module RoundhouseUi
|
|
|
51
51
|
# e.g. RoundhouseUi.redact_args = %w[password token secret]. Default: none.
|
|
52
52
|
attr_accessor :redact_args
|
|
53
53
|
|
|
54
|
+
# Opt-in: fold failures recorded by the `sidekiq-failures` gem (its `failed`
|
|
55
|
+
# sorted set) into the grouped Errors view. Off by default, and a no-op
|
|
56
|
+
# unless sidekiq-failures is loaded. Jobs with `retry: false` never enter
|
|
57
|
+
# Sidekiq's retry/dead sets, so this is the only way to surface them here.
|
|
58
|
+
attr_accessor :show_sidekiq_failures
|
|
59
|
+
|
|
54
60
|
# Configure in an initializer:
|
|
55
61
|
#
|
|
56
62
|
# RoundhouseUi.configure do |c|
|
|
@@ -70,4 +76,5 @@ module RoundhouseUi
|
|
|
70
76
|
self.read_only = false
|
|
71
77
|
self.allow_job_editing = false
|
|
72
78
|
self.redact_args = []
|
|
79
|
+
self.show_sidekiq_failures = false
|
|
73
80
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: roundhouse_ui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- R.J. Robinson
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|