From ccaa5165a006d4748ffb404a9a5cfba8312a8b0e Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Sat, 6 Jun 2026 14:51:13 -0500 Subject: [PATCH] refactor(desktop): merge cron jobLabel/jobTitle into one shared helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sidebar and Cron page each carried a near-identical name→prompt→id title fn. Collapse to a single jobTitle in cron/job-state.ts (the page variant, which also falls back to script then 'Cron job'). --- .../app/chat/sidebar/cron-jobs-section.tsx | 18 +++----------- apps/desktop/src/app/cron/index.tsx | 24 +------------------ apps/desktop/src/app/cron/job-state.ts | 9 +++++++ 3 files changed, 13 insertions(+), 38 deletions(-) diff --git a/apps/desktop/src/app/chat/sidebar/cron-jobs-section.tsx b/apps/desktop/src/app/chat/sidebar/cron-jobs-section.tsx index a168b79eed2..7b0e7b95fe7 100644 --- a/apps/desktop/src/app/chat/sidebar/cron-jobs-section.tsx +++ b/apps/desktop/src/app/chat/sidebar/cron-jobs-section.tsx @@ -11,7 +11,7 @@ import { cn } from '@/lib/utils' import { $selectedStoredSessionId } from '@/store/session' import type { CronJob } from '@/types/hermes' -import { jobState, STATE_DOT } from '../../cron/job-state' +import { jobState, jobTitle, STATE_DOT } from '../../cron/job-state' import { SidebarPanelLabel } from '../../shell/sidebar-label' const INACTIVE_STATES = new Set(['completed', 'disabled', 'error', 'paused']) @@ -24,18 +24,6 @@ const PEEK_RUN_LIMIT = 5 // open peek so a freshly-fired run shows up within a few seconds. const PEEK_POLL_INTERVAL_MS = 8000 -function jobLabel(job: CronJob): string { - const name = (job.name ?? '').trim() - - if (name) {return name} - - const prompt = (job.prompt ?? '').trim() - - if (prompt) {return prompt.length > 60 ? `${prompt.slice(0, 60)}…` : prompt} - - return job.id -} - const relativeFmt = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto', style: 'short' }) // Localized "in 5 min" / "2 hr ago" without hand-rolled strings — picks the @@ -126,7 +114,7 @@ export function SidebarCronJobsSection({ if (an !== null && bn === null) {return -1} - return jobLabel(a).localeCompare(jobLabel(b)) + return jobTitle(a).localeCompare(jobTitle(b)) }) }, [jobs]) @@ -191,7 +179,7 @@ function CronJobSidebarRow({ const c = t.cron const state = jobState(job) const next = nextRunMs(job) - const label = jobLabel(job) + const label = jobTitle(job) const meta = INACTIVE_STATES.has(state) ? (c.states[state] ?? state) diff --git a/apps/desktop/src/app/cron/index.tsx b/apps/desktop/src/app/cron/index.tsx index c7da8b91897..58967f9d64e 100644 --- a/apps/desktop/src/app/cron/index.tsx +++ b/apps/desktop/src/app/cron/index.tsx @@ -39,7 +39,7 @@ import { OverlayView } from '../overlays/overlay-view' import { PageSearchShell } from '../page-search-shell' import type { SetStatusbarItemGroup } from '../shell/statusbar-controls' -import { jobState, STATE_DOT } from './job-state' +import { jobState, jobTitle, STATE_DOT } from './job-state' const DEFAULT_DELIVER = 'local' @@ -84,28 +84,6 @@ function jobPrompt(job: CronJob): string { return asText(job.prompt) } -function jobTitle(job: CronJob): string { - const name = jobName(job) - - if (name) { - return name - } - - const prompt = jobPrompt(job) - - if (prompt) { - return truncate(prompt, 60) - } - - const script = asText(job.script) - - if (script) { - return truncate(script, 60) - } - - return job.id || 'Cron job' -} - function jobScheduleDisplay(job: CronJob): string { return asText(job.schedule_display) || asText(job.schedule?.display) || asText(job.schedule?.expr) || '—' } diff --git a/apps/desktop/src/app/cron/job-state.ts b/apps/desktop/src/app/cron/job-state.ts index 10b90df6e7b..b7dd139cc4e 100644 --- a/apps/desktop/src/app/cron/job-state.ts +++ b/apps/desktop/src/app/cron/job-state.ts @@ -18,3 +18,12 @@ export function jobState(job: CronJob): string { return state || (job.enabled === false ? 'disabled' : 'scheduled') } + +// Human label for a job: name → first 60 of prompt → first 60 of script → id. +// One source for the sidebar row and the Cron page so the two never drift. +export function jobTitle(job: CronJob): string { + const pick = (v: unknown) => (typeof v === 'string' ? v.trim() : '') + const clip = (v: string) => (v.length > 60 ? `${v.slice(0, 60)}…` : v) + + return pick(job.name) || clip(pick(job.prompt)) || clip(pick(job.script)) || job.id || 'Cron job' +}