- Implemented CloudlyViewSettings component for managing cloud provider settings including Hetzner, Cloudflare, AWS, DigitalOcean, Azure, and Google Cloud. - Added functionality to load, save, and test connections for each provider. - Enhanced UI with loading states and success/error notifications. feat: Create tasks view with execution history - Developed CloudlyViewTasks component to display and manage tasks and their executions. - Integrated auto-refresh functionality for task executions. - Added filtering and searching capabilities for tasks. feat: Implement execution details and task panel components - Created CloudlyExecutionDetails component to show detailed information about task executions including logs and metrics. - Developed CloudlyTaskPanel component to display individual tasks with execution status and actions to run or cancel tasks. feat: Utility functions for formatting and categorization - Added utility functions for formatting dates, durations, and cron expressions. - Implemented functions to retrieve category icons and hues for task categorization.
69 lines
2.6 KiB
TypeScript
69 lines
2.6 KiB
TypeScript
export function formatDate(timestamp: number): string {
|
|
return new Date(timestamp).toLocaleString();
|
|
}
|
|
|
|
export function formatDuration(ms: number): string {
|
|
if (ms < 1000) return `${ms}ms`;
|
|
if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
|
|
if (ms < 3600000) return `${(ms / 60000).toFixed(1)}m`;
|
|
return `${(ms / 3600000).toFixed(1)}h`;
|
|
}
|
|
|
|
export function formatRelativeTime(ts?: number): string {
|
|
if (!ts) return '-';
|
|
const diff = Date.now() - ts;
|
|
const abs = Math.abs(diff);
|
|
if (abs < 60_000) return `${Math.round(abs / 1000)}s ago`;
|
|
if (abs < 3_600_000) return `${Math.round(abs / 60_000)}m ago`;
|
|
if (abs < 86_400_000) return `${Math.round(abs / 3_600_000)}h ago`;
|
|
return `${Math.round(abs / 86_400_000)}d ago`;
|
|
}
|
|
|
|
export function getCategoryIcon(category: string): string {
|
|
switch (category) {
|
|
case 'maintenance':
|
|
return 'lucide:Wrench';
|
|
case 'deployment':
|
|
return 'lucide:Rocket';
|
|
case 'backup':
|
|
return 'lucide:Archive';
|
|
case 'monitoring':
|
|
return 'lucide:Activity';
|
|
case 'cleanup':
|
|
return 'lucide:Trash2';
|
|
case 'system':
|
|
return 'lucide:Settings';
|
|
case 'security':
|
|
return 'lucide:Shield';
|
|
default:
|
|
return 'lucide:Play';
|
|
}
|
|
}
|
|
|
|
export function getCategoryHue(category: string): number {
|
|
switch (category) {
|
|
case 'maintenance': return 28; // orange
|
|
case 'deployment': return 208; // blue
|
|
case 'backup': return 122; // green
|
|
case 'monitoring': return 280; // purple
|
|
case 'cleanup': return 20; // brownish
|
|
case 'system': return 200; // steel
|
|
case 'security': return 0; // red
|
|
default: return 210; // default blue
|
|
}
|
|
}
|
|
|
|
export function formatCronFriendly(cron?: string): string {
|
|
if (!cron) return '';
|
|
const parts = cron.trim().split(/\s+/);
|
|
if (parts.length !== 5) return cron; // fallback
|
|
const [min, hour, dom, mon, dow] = parts;
|
|
if (min === '*/1' && hour === '*' && dom === '*' && mon === '*' && dow === '*') return 'every minute';
|
|
if (min.startsWith('*/') && hour === '*' && dom === '*' && mon === '*' && dow === '*') return `every ${min.replace('*/','')} min`;
|
|
if (min === '0' && hour.startsWith('*/') && dom === '*' && mon === '*' && dow === '*') return `every ${hour.replace('*/','')} hours`;
|
|
if (min === '0' && hour === '*' && dom === '*' && mon === '*' && dow === '*') return 'hourly';
|
|
if (min === '0' && hour === '0' && dom === '*' && mon === '*' && dow === '*') return 'daily';
|
|
if (min === '0' && hour === '0' && dom === '1' && mon === '*' && dow === '*') return 'monthly';
|
|
return cron;
|
|
}
|