scrapeRL / frontend /src /utils /helpers.ts
NeerajCodz's picture
feat: implement React dashboard with components and hooks
0cfd364
export function formatTimestamp(timestamp: string): string {
const date = new Date(timestamp);
return date.toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
}
export function formatDate(timestamp: string): string {
const date = new Date(timestamp);
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
});
}
export function formatDuration(ms: number): string {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
if (hours > 0) {
return `${hours}h ${minutes % 60}m`;
}
if (minutes > 0) {
return `${minutes}m ${seconds % 60}s`;
}
return `${seconds}s`;
}
export function formatNumber(num: number, decimals = 2): string {
if (Math.abs(num) >= 1e6) {
return `${(num / 1e6).toFixed(decimals)}M`;
}
if (Math.abs(num) >= 1e3) {
return `${(num / 1e3).toFixed(decimals)}K`;
}
return num.toFixed(decimals);
}
export function formatReward(reward: number): string {
const sign = reward >= 0 ? '+' : '';
return `${sign}${reward.toFixed(3)}`;
}
export function truncateText(text: string, maxLength: number): string {
if (text.length <= maxLength) return text;
return `${text.slice(0, maxLength - 3)}...`;
}
export function classNames(...classes: (string | boolean | undefined | null)[]): string {
return classes.filter(Boolean).join(' ');
}
export function getStatusColor(status: string): string {
const colors: Record<string, string> = {
idle: 'yellow',
thinking: 'blue',
acting: 'green',
waiting: 'orange',
error: 'red',
running: 'green',
completed: 'green',
failed: 'red',
pending: 'gray',
timeout: 'orange',
};
return colors[status] ?? 'gray';
}
export function getRoleIcon(role: string): string {
const icons: Record<string, string> = {
navigator: '🧭',
extractor: 'πŸ“Š',
validator: 'βœ…',
coordinator: '🎯',
};
return icons[role] ?? 'πŸ€–';
}
export function getActionIcon(actionType: string): string {
const icons: Record<string, string> = {
navigate: 'πŸ”—',
click: 'πŸ‘†',
extract: 'πŸ“€',
scroll: 'πŸ“œ',
input: '⌨️',
wait: '⏳',
screenshot: 'πŸ“Έ',
execute_tool: 'πŸ”§',
delegate: 'πŸ‘₯',
terminate: 'πŸ›‘',
};
return icons[actionType] ?? '⚑';
}
export function debounce<T extends (...args: unknown[]) => unknown>(
func: T,
wait: number
): (...args: Parameters<T>) => void {
let timeout: ReturnType<typeof setTimeout> | null = null;
return (...args: Parameters<T>) => {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => func(...args), wait);
};
}
export function throttle<T extends (...args: unknown[]) => unknown>(
func: T,
limit: number
): (...args: Parameters<T>) => void {
let inThrottle = false;
return (...args: Parameters<T>) => {
if (!inThrottle) {
func(...args);
inThrottle = true;
setTimeout(() => (inThrottle = false), limit);
}
};
}
export function generateId(): string {
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 9)}`;
}
export function parseJSON<T>(json: string, fallback: T): T {
try {
return JSON.parse(json) as T;
} catch {
return fallback;
}
}
export function calculateProgress(current: number, total: number): number {
if (total === 0) return 0;
return Math.min(Math.round((current / total) * 100), 100);
}
export function groupBy<T>(array: T[], key: keyof T): Record<string, T[]> {
return array.reduce((groups, item) => {
const groupKey = String(item[key]);
return {
...groups,
[groupKey]: [...(groups[groupKey] || []), item],
};
}, {} as Record<string, T[]>);
}
export function sortByTimestamp<T extends { timestamp: string }>(
items: T[],
order: 'asc' | 'desc' = 'desc'
): T[] {
return [...items].sort((a, b) => {
const timeA = new Date(a.timestamp).getTime();
const timeB = new Date(b.timestamp).getTime();
return order === 'asc' ? timeA - timeB : timeB - timeA;
});
}