From 6cfdb827c7a02688f29ca9a443a9bf39714d7639 Mon Sep 17 00:00:00 2001 From: phact Date: Tue, 9 Sep 2025 14:33:15 -0400 Subject: [PATCH] task timings --- .../src/components/task-notification-menu.tsx | 26 +++++++++++++++++++ frontend/src/contexts/task-context.tsx | 1 + src/models/tasks.py | 10 +++++++ src/services/task_service.py | 3 +++ 4 files changed, 40 insertions(+) diff --git a/frontend/src/components/task-notification-menu.tsx b/frontend/src/components/task-notification-menu.tsx index 372717d4..c6f94959 100644 --- a/frontend/src/components/task-notification-menu.tsx +++ b/frontend/src/components/task-notification-menu.tsx @@ -76,6 +76,22 @@ export function TaskNotificationMenu() { return null } + const formatDuration = (seconds?: number) => { + if (!seconds || seconds < 0) return null + + if (seconds < 60) { + return `${Math.round(seconds)}s` + } else if (seconds < 3600) { + const mins = Math.floor(seconds / 60) + const secs = Math.round(seconds % 60) + return secs > 0 ? `${mins}m ${secs}s` : `${mins}m` + } else { + const hours = Math.floor(seconds / 3600) + const mins = Math.floor((seconds % 3600) / 60) + return mins > 0 ? `${hours}h ${mins}m` : `${hours}h` + } + } + const formatRelativeTime = (dateString: string) => { // Handle different timestamp formats let date: Date @@ -153,6 +169,11 @@ export function TaskNotificationMenu() { Started {formatRelativeTime(task.created_at)} + {formatDuration(task.duration_seconds) && ( + + • {formatDuration(task.duration_seconds)} + + )} {formatTaskProgress(task) && ( @@ -256,6 +277,11 @@ export function TaskNotificationMenu() {
{formatRelativeTime(task.updated_at)} + {formatDuration(task.duration_seconds) && ( + + • {formatDuration(task.duration_seconds)} + + )}
{/* Show final results for completed tasks */} {task.status === 'completed' && formatTaskProgress(task)?.detailed && ( diff --git a/frontend/src/contexts/task-context.tsx b/frontend/src/contexts/task-context.tsx index 77d1e57e..c132f39b 100644 --- a/frontend/src/contexts/task-context.tsx +++ b/frontend/src/contexts/task-context.tsx @@ -13,6 +13,7 @@ export interface Task { failed_files?: number created_at: string updated_at: string + duration_seconds?: number result?: Record error?: string files?: Record> diff --git a/src/models/tasks.py b/src/models/tasks.py index db67f8bf..236927ab 100644 --- a/src/models/tasks.py +++ b/src/models/tasks.py @@ -20,6 +20,11 @@ class FileTask: retry_count: int = 0 created_at: float = field(default_factory=time.time) updated_at: float = field(default_factory=time.time) + + @property + def duration_seconds(self) -> float: + """Duration in seconds from creation to last update""" + return self.updated_at - self.created_at @dataclass @@ -33,3 +38,8 @@ class UploadTask: status: TaskStatus = TaskStatus.PENDING created_at: float = field(default_factory=time.time) updated_at: float = field(default_factory=time.time) + + @property + def duration_seconds(self) -> float: + """Duration in seconds from creation to last update""" + return self.updated_at - self.created_at diff --git a/src/services/task_service.py b/src/services/task_service.py index f3d22234..8e69d4ae 100644 --- a/src/services/task_service.py +++ b/src/services/task_service.py @@ -224,6 +224,7 @@ class TaskService: "retry_count": file_task.retry_count, "created_at": file_task.created_at, "updated_at": file_task.updated_at, + "duration_seconds": file_task.duration_seconds, } return { @@ -235,6 +236,7 @@ class TaskService: "failed_files": upload_task.failed_files, "created_at": upload_task.created_at, "updated_at": upload_task.updated_at, + "duration_seconds": upload_task.duration_seconds, "files": file_statuses, } @@ -262,6 +264,7 @@ class TaskService: "failed_files": upload_task.failed_files, "created_at": upload_task.created_at, "updated_at": upload_task.updated_at, + "duration_seconds": upload_task.duration_seconds, } # First, add user-owned tasks; then shared anonymous;