Download desktop/src/hooks/useScheduledTaskDesktopNotifications.ts from chenbhao/codev: direct link, hf CLI and curl.
- Browser
- Download file 3.79 kB
-
https://huggingface.co/chenbhao/codev/resolve/e40073cc959cd4729bf4009662bca374c5c4e266/desktop/src/hooks/useScheduledTaskDesktopNotifications.ts
- Command line
-
hf download hf://chenbhao/codev@e40073cc959cd4729bf4009662bca374c5c4e266/desktop/src/hooks/useScheduledTaskDesktopNotifications.ts
-
curl -L -o useScheduledTaskDesktopNotifications.ts https://huggingface.co/chenbhao/codev/resolve/e40073cc959cd4729bf4009662bca374c5c4e266/desktop/src/hooks/useScheduledTaskDesktopNotifications.ts
3.79 kB
| import { useEffect } from 'react' | |
| import { tasksApi } from '../api/tasks' | |
| import { notifyDesktop } from '../lib/desktopNotifications' | |
| import type { CronTask, TaskRun } from '../types/task' | |
| const POLL_INTERVAL_MS = 30_000 | |
| const NOTIFIED_RUNS_STORAGE_KEY = 'cc-haha.notifiedDesktopTaskRuns.v1' | |
| const MAX_STORED_RUN_IDS = 200 | |
| function isTerminalRun(run: TaskRun): boolean { | |
| return run.status === 'completed' || run.status === 'failed' || run.status === 'timeout' | |
| } | |
| function hasDesktopNotification(task: CronTask | undefined): boolean { | |
| return !!task?.notification?.enabled && task.notification.channels.includes('desktop') | |
| } | |
| function readNotifiedRunIds(): Set<string> { | |
| try { | |
| const raw = localStorage.getItem(NOTIFIED_RUNS_STORAGE_KEY) | |
| const parsed = raw ? JSON.parse(raw) : [] | |
| return new Set(Array.isArray(parsed) ? parsed.filter((id): id is string => typeof id === 'string') : []) | |
| } catch { | |
| return new Set() | |
| } | |
| } | |
| function writeNotifiedRunIds(runIds: Set<string>): void { | |
| try { | |
| const trimmed = [...runIds].slice(-MAX_STORED_RUN_IDS) | |
| localStorage.setItem(NOTIFIED_RUNS_STORAGE_KEY, JSON.stringify(trimmed)) | |
| } catch { | |
| // Notification dedupe is best-effort; storage failures should not break the app. | |
| } | |
| } | |
| function formatTaskRunNotification(run: TaskRun): { title: string; body: string } { | |
| const status = run.status === 'completed' | |
| ? '完成' | |
| : run.status === 'failed' | |
| ? '失败' | |
| : '超时' | |
| const detail = run.error || run.output || run.prompt | |
| const body = detail | |
| ? `${status}: ${detail.slice(0, 160)}` | |
| : `状态: ${status}` | |
| return { | |
| title: `定时任务 ${run.taskName || run.taskId}`, | |
| body, | |
| } | |
| } | |
| export function collectDesktopNotifiableRuns( | |
| tasks: CronTask[], | |
| runs: TaskRun[], | |
| notifiedRunIds: Set<string>, | |
| ): TaskRun[] { | |
| const taskById = new Map(tasks.map((task) => [task.id, task])) | |
| return runs | |
| .filter((run) => isTerminalRun(run)) | |
| .filter((run) => hasDesktopNotification(taskById.get(run.taskId))) | |
| .filter((run) => !notifiedRunIds.has(run.id)) | |
| .sort((a, b) => Date.parse(a.completedAt ?? a.startedAt) - Date.parse(b.completedAt ?? b.startedAt)) | |
| } | |
| export function useScheduledTaskDesktopNotifications(): void { | |
| useEffect(() => { | |
| let stopped = false | |
| let initialized = false | |
| const poll = async () => { | |
| try { | |
| const [{ tasks }, { runs }] = await Promise.all([ | |
| tasksApi.list(), | |
| tasksApi.getRecentRuns(50), | |
| ]) | |
| if (stopped) return | |
| const notifiedRunIds = readNotifiedRunIds() | |
| const pendingRuns = collectDesktopNotifiableRuns(tasks, runs, notifiedRunIds) | |
| if (!initialized) { | |
| for (const run of pendingRuns) notifiedRunIds.add(run.id) | |
| writeNotifiedRunIds(notifiedRunIds) | |
| initialized = true | |
| return | |
| } | |
| for (const run of pendingRuns) { | |
| const notification = formatTaskRunNotification(run) | |
| const sent = await notifyDesktop({ | |
| dedupeKey: `scheduled-task:${run.id}`, | |
| title: notification.title, | |
| body: notification.body, | |
| target: run.sessionId | |
| ? { type: 'session', sessionId: run.sessionId, title: run.taskName || run.taskId } | |
| : { type: 'scheduled' }, | |
| }) | |
| if (sent) notifiedRunIds.add(run.id) | |
| } | |
| writeNotifiedRunIds(notifiedRunIds) | |
| } catch (err) { | |
| if (typeof console !== 'undefined') { | |
| console.warn('[scheduledTaskNotifications] failed to poll task runs:', err) | |
| } | |
| } | |
| } | |
| void poll() | |
| const interval = window.setInterval(() => { | |
| void poll() | |
| }, POLL_INTERVAL_MS) | |
| return () => { | |
| stopped = true | |
| window.clearInterval(interval) | |
| } | |
| }, []) | |
| } | |