From 2ac904125f0a8ff6dfe50ca8901423dd36898791 Mon Sep 17 00:00:00 2001 From: Giovani Guizzo Date: Thu, 31 Jul 2025 17:57:45 -0300 Subject: [PATCH 1/7] refactor: simplify logging messages in job transitions --- packages/core/src/transitions/complete-transition.ts | 2 +- packages/core/src/transitions/rerun-transition.ts | 2 +- packages/core/src/transitions/run-transition.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/src/transitions/complete-transition.ts b/packages/core/src/transitions/complete-transition.ts index a067636..37960c7 100644 --- a/packages/core/src/transitions/complete-transition.ts +++ b/packages/core/src/transitions/complete-transition.ts @@ -24,7 +24,7 @@ export class CompleteTransition extends JobTransition { } apply(job: JobData): JobData { - logger("Core").info(`Job ${job.class} has completed with args: ${JSON.stringify(job.args)}`); + logger("Core").info(`Job #${job.id} - ${job.class} has completed`); job.completed_at = new Date(); job.state = "completed"; job.result = this.result ?? null; diff --git a/packages/core/src/transitions/rerun-transition.ts b/packages/core/src/transitions/rerun-transition.ts index 2616711..433bf08 100644 --- a/packages/core/src/transitions/rerun-transition.ts +++ b/packages/core/src/transitions/rerun-transition.ts @@ -11,7 +11,7 @@ import { JobTransition } from "./transition"; */ export class RerunTransition extends JobTransition { apply(job: JobData): JobData { - logger("Core").debug(`Re-running job ${job.class} with args: ${JSON.stringify(job.args)}`); + logger("Core").debug(`Re-running job #${job.id} - ${job.class}`); // Reset job state to waiting job.state = "waiting"; diff --git a/packages/core/src/transitions/run-transition.ts b/packages/core/src/transitions/run-transition.ts index 6d60f62..c60d9ba 100644 --- a/packages/core/src/transitions/run-transition.ts +++ b/packages/core/src/transitions/run-transition.ts @@ -14,7 +14,7 @@ import { JobTransition } from "./transition"; */ export class RunTransition extends JobTransition { apply(job: JobData): JobData { - logger("Core").info(`Running job #${job.id} - ${job.class} with args: ${JSON.stringify(job.args)}`); + logger("Core").info(`Running job #${job.id} - ${job.class}`); job.state = "running"; job.attempted_at = new Date(); job.attempt = job.attempt + 1; From 4aa2b3fbf4783b2de1467cda14503ff9cf19c254 Mon Sep 17 00:00:00 2001 From: Giovani Guizzo Date: Thu, 31 Jul 2025 17:59:22 -0300 Subject: [PATCH 2/7] feat: enhance logging for job transitions with job IDs --- packages/core/src/transitions/cancel-transition.ts | 2 ++ packages/core/src/transitions/rerun-transition.ts | 2 +- packages/core/src/transitions/retry-transition.ts | 2 +- packages/core/src/transitions/snooze-transition.ts | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/core/src/transitions/cancel-transition.ts b/packages/core/src/transitions/cancel-transition.ts index 72a8723..76555f5 100644 --- a/packages/core/src/transitions/cancel-transition.ts +++ b/packages/core/src/transitions/cancel-transition.ts @@ -1,3 +1,4 @@ +import { logger } from "../logger"; import { JobData } from "../schema"; import { JobTransition } from "./transition"; @@ -15,6 +16,7 @@ import { JobTransition } from "./transition"; */ export class CancelTransition extends JobTransition { apply(job: JobData): JobData { + logger("Core").info(`Cancelling job #${job.id} - ${job.class}`); job.state = "canceled"; job.canceled_at = new Date(); return job; diff --git a/packages/core/src/transitions/rerun-transition.ts b/packages/core/src/transitions/rerun-transition.ts index 433bf08..93fc4c6 100644 --- a/packages/core/src/transitions/rerun-transition.ts +++ b/packages/core/src/transitions/rerun-transition.ts @@ -11,7 +11,7 @@ import { JobTransition } from "./transition"; */ export class RerunTransition extends JobTransition { apply(job: JobData): JobData { - logger("Core").debug(`Re-running job #${job.id} - ${job.class}`); + logger("Core").info(`Re-running job #${job.id} - ${job.class}`); // Reset job state to waiting job.state = "waiting"; diff --git a/packages/core/src/transitions/retry-transition.ts b/packages/core/src/transitions/retry-transition.ts index af53f00..7e12809 100644 --- a/packages/core/src/transitions/retry-transition.ts +++ b/packages/core/src/transitions/retry-transition.ts @@ -43,7 +43,7 @@ export class RetryTransition extends JobTransition { const reason = toErrorData(this.reason); const delay = this.delay ?? this.calculateBackoff(job.attempt); - logger("Core").info(`Retrying failed job ${job.class} in ${delay}ms`); + logger("Core").info(`Retrying failed job #${job.id} - ${job.class} in ${delay}ms`); const errData = { ...reason, diff --git a/packages/core/src/transitions/snooze-transition.ts b/packages/core/src/transitions/snooze-transition.ts index 7d2de5a..8bcd5c5 100644 --- a/packages/core/src/transitions/snooze-transition.ts +++ b/packages/core/src/transitions/snooze-transition.ts @@ -26,7 +26,7 @@ export class SnoozeTransition extends JobTransition { } apply(job: JobData): JobData { - logger("Core").info(`Job ${job.class} snoozed by ${this.delay}ms`); + logger("Core").info(`Job #${job.id} - ${job.class} snoozed by ${this.delay}ms`); // Attempts are only decremented if the job is running and has already been attempted // This means that the job will not consider the current run as an attempt From 876a8b9fcd4f43790c35d21161de3525a9d97e5e Mon Sep 17 00:00:00 2001 From: Giovani Guizzo Date: Thu, 31 Jul 2025 18:37:41 -0300 Subject: [PATCH 3/7] feat: improve detail toggling by using unique IDs for constructor, run, and result arguments --- packages/dashboard/src/public/js/job.js | 31 +++++++------------ .../dashboard/src/views/partials/job-view.ejs | 6 ++-- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/packages/dashboard/src/public/js/job.js b/packages/dashboard/src/public/js/job.js index 67f751c..15214b6 100644 --- a/packages/dashboard/src/public/js/job.js +++ b/packages/dashboard/src/public/js/job.js @@ -1,43 +1,36 @@ +// Global variable to store details state +let globalDetailsStates = {}; + function applySeeMore() { document.querySelectorAll(".sq-code").forEach((container) => { const content = container.querySelector(".code-content"); const btn = container.querySelector(".toggle-btn"); const maxHeight = 240; - let expanded = false; if (content.scrollHeight <= maxHeight) { btn.classList.add("hidden"); } - btn.addEventListener("click", () => { - expanded = !expanded; - + function toggleDetails(expanded) { if (expanded) { content.classList.remove("max-h-[15rem]", "overflow-hidden"); btn.textContent = "See less"; + globalDetailsStates[container.id] = true; // Save state as expanded } else { content.classList.add("max-h-[15rem]", "overflow-hidden"); btn.textContent = "See more"; + globalDetailsStates[container.id] = false; // Save state as not expanded } + } + + toggleDetails(globalDetailsStates[container.id] ?? false); + + btn.addEventListener("click", () => { + toggleDetails(!globalDetailsStates[container.id] ?? true); }); }); } document.addEventListener("DOMContentLoaded", applySeeMore); document.addEventListener("htmx:afterSwap", applySeeMore); - -document.addEventListener("htmx:beforeSwap", (evt) => { - const detailsStates = Array.from(document.querySelectorAll("#job-details details")).map((d) => d.open); - - evt.detail.target.dataset.detailsStates = JSON.stringify(detailsStates); -}); - -document.addEventListener("htmx:afterSwap", (evt) => { - const detailsStates = JSON.parse(evt.detail.target.dataset.detailsStates || "[]"); - - const details = evt.target.querySelectorAll("details"); - detailsStates.forEach((isOpen, idx) => { - if (isOpen) details[idx].open = true; - }); -}); diff --git a/packages/dashboard/src/views/partials/job-view.ejs b/packages/dashboard/src/views/partials/job-view.ejs index 06f428b..55e6279 100644 --- a/packages/dashboard/src/views/partials/job-view.ejs +++ b/packages/dashboard/src/views/partials/job-view.ejs @@ -114,7 +114,7 @@

Constructor Arguments

<% if (Array.isArray(job.constructor_args) && job.constructor_args.length > 0) { %> -
+
<%= JSON.stringify(job.constructor_args, null, 2) %>
@@ -130,7 +130,7 @@

Run Arguments

<% if (Array.isArray(job.args) && job.args.length > 0) { %> -
+
<%= JSON.stringify(job.args, null, 2) %>
@@ -147,7 +147,7 @@ <% if (job.result) { %>

Result

-
+
<%= JSON.stringify(job.result, null, 2) %>
From e7a05fe275af9d418ad60143f0ccb0c9ea9da085 Mon Sep 17 00:00:00 2001 From: Giovani Guizzo Date: Thu, 31 Jul 2025 19:19:57 -0300 Subject: [PATCH 4/7] feat: implement scroll position restoration for HTMX swaps --- packages/core/src/backends/duplicated-job-error.ts | 4 +--- packages/dashboard/src/public/js/scroll.js | 12 ++++++++++++ packages/dashboard/src/views/layout.ejs | 9 ++++----- 3 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 packages/dashboard/src/public/js/scroll.js diff --git a/packages/core/src/backends/duplicated-job-error.ts b/packages/core/src/backends/duplicated-job-error.ts index 577d4d9..494eabe 100644 --- a/packages/core/src/backends/duplicated-job-error.ts +++ b/packages/core/src/backends/duplicated-job-error.ts @@ -10,8 +10,6 @@ import { JobData } from "../schema"; */ export class DuplicatedJobError extends Error { constructor(job: JobData) { - super( - `Job ${job.class} is duplicated, constructor args: ${JSON.stringify(job.constructor_args)} args: ${JSON.stringify(job.args)}`, - ); + super(`Job #${job.id} - ${job.class} is duplicated`); } } diff --git a/packages/dashboard/src/public/js/scroll.js b/packages/dashboard/src/public/js/scroll.js new file mode 100644 index 0000000..2846cb0 --- /dev/null +++ b/packages/dashboard/src/public/js/scroll.js @@ -0,0 +1,12 @@ +let savedScrollY = 0; + +// Save and restore scroll position around HTMX swaps +document.addEventListener("DOMContentLoaded", () => { + document.addEventListener("htmx:beforeSwap", () => { + savedScrollY = document.getElementById("main-section").scrollTop; + }); + + document.addEventListener("htmx:afterSwap", () => { + document.getElementById("main-section").scroll(0, savedScrollY); + }); +}); diff --git a/packages/dashboard/src/views/layout.ejs b/packages/dashboard/src/views/layout.ejs index 88c8011..6116ab4 100644 --- a/packages/dashboard/src/views/layout.ejs +++ b/packages/dashboard/src/views/layout.ejs @@ -9,6 +9,7 @@ +
@@ -30,18 +31,16 @@ -
- <%- body %> -
+
<%- body %>
From 1c87eebc30f728c639aa1b2466874d6243e39ac1 Mon Sep 17 00:00:00 2001 From: Giovani Guizzo Date: Thu, 31 Jul 2025 19:30:53 -0300 Subject: [PATCH 5/7] fix: correct scroll position restoration method for HTMX swaps --- packages/dashboard/src/public/js/scroll.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dashboard/src/public/js/scroll.js b/packages/dashboard/src/public/js/scroll.js index 2846cb0..4a2a067 100644 --- a/packages/dashboard/src/public/js/scroll.js +++ b/packages/dashboard/src/public/js/scroll.js @@ -7,6 +7,6 @@ document.addEventListener("DOMContentLoaded", () => { }); document.addEventListener("htmx:afterSwap", () => { - document.getElementById("main-section").scroll(0, savedScrollY); + document.getElementById("main-section").scrollTo({ top: savedScrollY }); }); }); From 77930b62bc940809695d3e02f73c0bf3bc2ab13a Mon Sep 17 00:00:00 2001 From: Giovani Guizzo Date: Thu, 31 Jul 2025 19:51:03 -0300 Subject: [PATCH 6/7] feat: enhance URL management for HTMX requests and improve button behavior in job and queue tables --- packages/dashboard/src/public/js/jobs.js | 10 ---------- packages/dashboard/src/views/pages/jobs.ejs | 2 +- packages/dashboard/src/views/partials/jobs-table.ejs | 4 ++-- packages/dashboard/src/views/partials/queues-table.ejs | 2 +- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/packages/dashboard/src/public/js/jobs.js b/packages/dashboard/src/public/js/jobs.js index 4067476..4430111 100644 --- a/packages/dashboard/src/public/js/jobs.js +++ b/packages/dashboard/src/public/js/jobs.js @@ -28,13 +28,3 @@ document.addEventListener("htmx:configRequest", (evt) => { evt.detail.parameters.end = endDate.toISOString(); } }); - -document.addEventListener("htmx:afterRequest", (evt) => { - const form = document.getElementById("filter-form"); - if (!form) return; - - const params = new URLSearchParams(new FormData(form)).toString(); - - const url = `/jobs?${params}`; - window.history.pushState({}, "", url); -}); diff --git a/packages/dashboard/src/views/pages/jobs.ejs b/packages/dashboard/src/views/pages/jobs.ejs index 23b6589..5ae4376 100644 --- a/packages/dashboard/src/views/pages/jobs.ejs +++ b/packages/dashboard/src/views/pages/jobs.ejs @@ -1,6 +1,6 @@
+ hx-trigger="change from:* delay:300ms, every 3s, jobChanged" hx-push-url="true">
diff --git a/packages/dashboard/src/views/partials/jobs-table.ejs b/packages/dashboard/src/views/partials/jobs-table.ejs index 67732f9..3c670f6 100644 --- a/packages/dashboard/src/views/partials/jobs-table.ejs +++ b/packages/dashboard/src/views/partials/jobs-table.ejs @@ -36,10 +36,10 @@ <%= job.claimed_by || '-' %> <% if (job.available_at > new Date()) { %> - + <% } %> <% if (!['canceled', 'failed', 'completed'].includes(job.state)){ %> - + <% } %> diff --git a/packages/dashboard/src/views/partials/queues-table.ejs b/packages/dashboard/src/views/partials/queues-table.ejs index 561fc53..4964833 100644 --- a/packages/dashboard/src/views/partials/queues-table.ejs +++ b/packages/dashboard/src/views/partials/queues-table.ejs @@ -36,7 +36,7 @@ <%= queue.jobs.filter(job => job.state === "failed").length %>