Skip to content

fix jobqueue widget and enhance it with internationalization support#512

Open
Felipedino wants to merge 1 commit intodevelopfrom
fix/jobqueue-widget
Open

fix jobqueue widget and enhance it with internationalization support#512
Felipedino wants to merge 1 commit intodevelopfrom
fix/jobqueue-widget

Conversation

@Felipedino
Copy link
Copy Markdown
Collaborator

This pull request enhances the internationalization and user experience of the job queue components by replacing hardcoded UI strings with translation keys and improving styling and interaction patterns. The changes ensure that all user-facing text in the job queue and job details dialogs are translatable and that the UI is more consistent with the application's theme.

Internationalization improvements:

UI/UX and code improvements:

  • Updated the job queue widget to use ListItemButton for better accessibility and interaction, improved sorting and limiting of displayed jobs, and refined the handling of empty, loading, and error states. [1] [2]
  • Enhanced visual consistency by adjusting background colors, elevation, and icon/button colors to match the application's theme. [1] [2] [3] [4]

Code structure:

  • Removed the statusText object and replaced it with the getStatusText function to centralize status translation logic.

These changes make the job queue features fully localizable and provide a more polished and accessible user interface.

Copilot AI review requested due to automatic review settings March 30, 2026 04:04
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the job queue UI to be fully localizable via react-i18next and refines the widget’s presentation/interaction, while also adjusting the job polling hook to better handle incremental job updates.

Changes:

  • Added jobQueue translation keys to common.json (EN/ES) and replaced hardcoded strings in job queue components with i18n keys.
  • Refactored JobQueueWidget UI (ListItemButton usage, styling tweaks, clearer empty/loading/error states, show-completed toggle copy).
  • Updated useJobManager to sort jobs by last_update and merge incremental updates from the poller.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
DashAI/front/src/utils/i18n/locales/es/common.json Adds Spanish translation keys for job queue UI text/status labels.
DashAI/front/src/utils/i18n/locales/en/common.json Adds English translation keys for job queue UI text/status labels.
DashAI/front/src/hooks/useJobPolling.js Adds incremental-merge behavior and sorting for job manager updates.
DashAI/front/src/components/jobs/JobQueueWidget.jsx Replaces UI strings with i18n keys; updates list interaction and styling.
DashAI/front/src/components/jobs/JobDetailsDialog.jsx Replaces UI strings with i18n keys; adds translated status label mapping.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +20 to +34
const getStatusText = (status, t) => {
switch (status) {
case "not_started":
return t("common:jobQueue.status.queued");
case "started":
return t("common:jobQueue.status.running");
case "finished":
return t("common:jobQueue.status.completed");
case "error":
return t("common:jobQueue.status.failed");
case "deleted":
return t("common:jobQueue.status.deleted");
default:
return status || t("common:unknown");
}
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getStatusText() is duplicated here and in JobQueueWidget.jsx. To avoid future divergence (e.g., adding a new status or changing wording in one place only), consider extracting a shared helper (e.g., utils/jobStatusText) that both components import.

Suggested change
const getStatusText = (status, t) => {
switch (status) {
case "not_started":
return t("common:jobQueue.status.queued");
case "started":
return t("common:jobQueue.status.running");
case "finished":
return t("common:jobQueue.status.completed");
case "error":
return t("common:jobQueue.status.failed");
case "deleted":
return t("common:jobQueue.status.deleted");
default:
return status || t("common:unknown");
}
const JOB_STATUS_TRANSLATION_KEYS = {
not_started: "common:jobQueue.status.queued",
started: "common:jobQueue.status.running",
finished: "common:jobQueue.status.completed",
error: "common:jobQueue.status.failed",
deleted: "common:jobQueue.status.deleted",
};
const getStatusText = (status, t) => {
const key = status && JOB_STATUS_TRANSLATION_KEYS[status];
if (key) {
return t(key);
}
return status || t("common:unknown");

Copilot uses AI. Check for mistakes.
Comment on lines +167 to +168
"activeCount": "{{count}} activos",
"failedCount": "{{count}} fallidos",
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

activeCount/failedCount are used with count, but the Spanish strings are always plural (e.g., 1 activos, 1 fallidos). Add proper i18next plural forms (e.g., activeCount_one/activeCount_other, failedCount_one/failedCount_other) or rephrase to avoid incorrect singular grammar.

Suggested change
"activeCount": "{{count}} activos",
"failedCount": "{{count}} fallidos",
"activeCount_one": "{{count}} activo",
"activeCount_other": "{{count}} activos",
"failedCount_one": "{{count}} fallido",
"failedCount_other": "{{count}} fallidos",

Copilot uses AI. Check for mistakes.
Comment on lines 106 to 110
const unsubscribe = subscribeJobs((updatedJobs) => {
if (Array.isArray(updatedJobs)) {
setJobs(updatedJobs);
// `updatedJobs` is incremental (changes since cursor), so merge it.
setJobs((previousJobs) => mergeJobsById(previousJobs, updatedJobs));
setLoading(false);
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subscribeJobs receives incremental changes (see job poller using /v1/job/changes). Merging updates means jobs deleted server-side (e.g., via deleteJob/deleteAllJobs, which remove rows from task_copy) will never be removed from jobs, so the UI can keep showing deleted items forever. Consider making refresh() re-fetch the full list (getJobs) and replace state (or have the poller/subscription provide a full snapshot / explicit deletions / queue_empty flag so the manager can reconcile removals).

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +21
return Array.from(byId.values()).sort(
(a, b) => new Date(b.last_update) - new Date(a.last_update),
);
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorting by new Date(job.last_update) is risky because the backend timestamps are 'YYYY-MM-DD HH:MM:SS.ffffff' (not ISO8601). Date parsing is inconsistent across browsers (notably Safari) and can yield Invalid Date, breaking ordering. Reuse the widget’s normalization (replace(' ', 'T') + 'Z') or add a shared timestamp parser before sorting.

Copilot uses AI. Check for mistakes.
Comment on lines 203 to +207
const getJobsToShow = () => {
if (showFinished) {
return jobs;
} else {
return [...activeJobs]
return [...jobs]
.sort((a, b) => new Date(b.last_update) - new Date(a.last_update))
.slice(0, 10);
.slice(0, 25);
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getJobsToShow() sorts using new Date(last_update), but last_update comes from SQLite-style timestamps (space-separated, no timezone). This can parse inconsistently across browsers and lead to incorrect ordering. Consider normalizing last_update the same way getRelativeTime() does (or centralize into a shared parse helper) before sorting in both branches.

Copilot uses AI. Check for mistakes.
Comment on lines 358 to 362
{loading && jobs.length === 0 && (
<Box display="flex" justifyContent="center" p={2}>
<Typography variant="body2" color="text.secondary">
Loading jobs...
{t("common:loading")}
</Typography>
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description says all user-facing strings in the job queue are now translatable, but the relative-time strings shown in the list (e.g., “just now”, “Xs ago”, “in Xm”, “time unknown”) are still hardcoded in getRelativeTime(). Please move these to i18n keys and use t(...) with interpolation so they’re localizable as well.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants