Merge pull request #30 from langflow-ai/task-timings

task timings
This commit is contained in:
Sebastián Estévez 2025-09-09 14:34:04 -04:00 committed by GitHub
commit 951ccc7d12
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 40 additions and 0 deletions

View file

@ -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() {
</div>
<CardDescription className="text-xs">
Started {formatRelativeTime(task.created_at)}
{formatDuration(task.duration_seconds) && (
<span className="ml-2 text-muted-foreground">
{formatDuration(task.duration_seconds)}
</span>
)}
</CardDescription>
</CardHeader>
{formatTaskProgress(task) && (
@ -256,6 +277,11 @@ export function TaskNotificationMenu() {
</div>
<div className="text-xs text-muted-foreground">
{formatRelativeTime(task.updated_at)}
{formatDuration(task.duration_seconds) && (
<span className="ml-2">
{formatDuration(task.duration_seconds)}
</span>
)}
</div>
{/* Show final results for completed tasks */}
{task.status === 'completed' && formatTaskProgress(task)?.detailed && (

View file

@ -13,6 +13,7 @@ export interface Task {
failed_files?: number
created_at: string
updated_at: string
duration_seconds?: number
result?: Record<string, unknown>
error?: string
files?: Record<string, Record<string, unknown>>

View file

@ -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

View file

@ -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;