Files
PiAgentUI/src/utils/formatUtils.ts
T
Evandro b3489e1ede
Build & Push Frontend Docker Image / build-and-push (push) Canceled after 0s
Build Validation / validate (push) Canceled after 6s
Build & Push Backend Docker Image / build-and-push (push) Failing after 10m10s
Build & Push Gateway Docker Image / build-and-push (push) Failing after 10m9s
🎉 Initial commit: PiAgentUI — AI Agent Desktop & Web UI
A professional workspace for AI coding agents with:
- Real-time streaming chat with SSE
- Session management (fork, clone, tree navigation)
- MCP tools browser & metadata panel
- Skills browser (global, project, package sources)
- Voice input & STT provider configuration
- Integrated terminal & file explorer
- Model selector with capability metadata
- Keyboard-first UI with command palette
- 8 languages (en, pt-BR, es, ja, zh-CN, ar, bn, hi)
- Tauri 2 desktop app
- React 19 + TypeScript + Vite 8 + Tailwind CSS 4
- Pi Agent extension runtime

Originally forked from OpenCodeUI, now an independent project.
License: GPL-3.0-only
2026-06-01 00:50:06 -03:00

80 lines
3.1 KiB
TypeScript

/**
* Shared formatting utilities.
* Consolidated from duplicated functions across message parts, hooks, and renderers.
*/
import type { CompletedAtFormat } from '../store/themeStore'
/** Format a tool name for display: "my-tool_name" → "My Tool Name" */
export function formatToolName(name: string): string {
return name.replace(/[-_]/g, ' ').replace(/\b\w/g, c => c.toUpperCase())
}
/** Format a duration in ms to human-readable string */
export function formatDuration(ms: number): string {
const normalizedMs = Math.max(0, Math.round(ms))
if (normalizedMs < 1000) return `${normalizedMs}ms`
const s = normalizedMs / 1000
if (s < 60) return `${s.toFixed(1)}s`
const totalSeconds = Math.round(s)
const d = Math.floor(totalSeconds / (60 * 60 * 24))
const h = Math.floor((totalSeconds % (60 * 60 * 24)) / (60 * 60))
const m = Math.floor((totalSeconds % (60 * 60)) / 60)
const remS = totalSeconds % 60
if (d > 0) return [`${d}d`, h > 0 ? `${h}h` : '', m > 0 ? `${m}m` : ''].filter(Boolean).join(' ')
if (h > 0) return [`${h}h`, m > 0 ? `${m}m` : '', remS > 0 ? `${remS}s` : ''].filter(Boolean).join(' ')
return [`${m}m`, remS > 0 ? `${remS}s` : ''].filter(Boolean).join(' ')
}
/** Format a cost in dollars */
export function formatCost(cost: number): string {
if (cost === 0) return '$0'
if (cost < 0.001) return '<$0.001'
if (cost < 0.01) return '$' + cost.toFixed(3)
if (cost < 1) return '$' + cost.toFixed(2)
return '$' + cost.toFixed(2)
}
/** Format a timestamp (ms) to local HH:MM time string */
export function formatTime(ms: number): string {
const date = new Date(ms)
const h = date.getHours().toString().padStart(2, '0')
const m = date.getMinutes().toString().padStart(2, '0')
return `${h}:${m}`
}
/** Format a timestamp (ms) to local YYYY-MM-DD HH:MM string */
export function formatDateTime(ms: number): string {
const date = new Date(ms)
const y = date.getFullYear().toString().padStart(4, '0')
const mon = (date.getMonth() + 1).toString().padStart(2, '0')
const d = date.getDate().toString().padStart(2, '0')
return `${y}-${mon}-${d} ${formatTime(ms)}`
}
/** Format a timestamp (ms) to local YYYY-MM-DD HH:MM:SS string for detail tooltips */
export function formatDetailedDateTime(ms: number): string {
const date = new Date(ms)
const y = date.getFullYear().toString().padStart(4, '0')
const mon = (date.getMonth() + 1).toString().padStart(2, '0')
const d = date.getDate().toString().padStart(2, '0')
const h = date.getHours().toString().padStart(2, '0')
const m = date.getMinutes().toString().padStart(2, '0')
const s = date.getSeconds().toString().padStart(2, '0')
return `${y}-${mon}-${d} ${h}:${m}:${s}`
}
/** Format completed time according to the selected display mode */
export function formatCompletedAt(ms: number, format: CompletedAtFormat): string {
return format === 'dateTime' ? formatDateTime(ms) : formatTime(ms)
}
/** Format a large number with k/M suffix */
export function formatNumber(num: number): string {
if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M'
if (num >= 1000) return (num / 1000).toFixed(1) + 'k'
return num.toString()
}