feat: initialize Infra Manager with React, Tailwind CSS, and Inertia.js
- Added main application entry point (app.jsx) and bootstrap file for React setup. - Created Wiki index page (Index.jsx) for documentation and file management. - Implemented utility functions for formatting and status handling in utils.js. - Set up Blade template (app.blade.php) for Inertia.js integration. - Defined API routes for metrics and terminal access in api.php. - Established console commands for scheduled tasks in console.php. - Created web routes for various application features including authentication, hypervisors, containers, cloud accounts, security, backups, and wiki management in web.php. - Developed setup scripts for Windows (setup.ps1) and Linux (setup.sh) environments. - Configured Tailwind CSS for styling with custom themes and animations in tailwind.config.js. - Set up Vite for asset bundling and development server in vite.config.js.
This commit is contained in:
71
resources/js/lib/utils.js
Normal file
71
resources/js/lib/utils.js
Normal file
@@ -0,0 +1,71 @@
|
||||
import { clsx } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
export function cn(...inputs) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
export function formatBytes(bytes, decimals = 2) {
|
||||
if (!bytes || bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
export function formatUptime(seconds) {
|
||||
const d = Math.floor(seconds / 86400);
|
||||
const h = Math.floor((seconds % 86400) / 3600);
|
||||
const m = Math.floor((seconds % 3600) / 60);
|
||||
if (d > 0) return `${d}d ${h}h`;
|
||||
if (h > 0) return `${h}h ${m}m`;
|
||||
return `${m}m`;
|
||||
}
|
||||
|
||||
export function getStatusColor(status) {
|
||||
const map = {
|
||||
online: 'text-green-400',
|
||||
running: 'text-cyan-400',
|
||||
active: 'text-green-400',
|
||||
stopped: 'text-slate-400',
|
||||
offline: 'text-red-400',
|
||||
error: 'text-red-400',
|
||||
warning: 'text-yellow-400',
|
||||
unknown: 'text-gray-400',
|
||||
paused: 'text-yellow-400',
|
||||
exited: 'text-slate-400',
|
||||
};
|
||||
return map[status?.toLowerCase()] ?? 'text-gray-400';
|
||||
}
|
||||
|
||||
export function getStatusDot(status) {
|
||||
const map = {
|
||||
online: 'bg-green-400',
|
||||
running: 'bg-cyan-400',
|
||||
active: 'bg-green-400',
|
||||
stopped: 'bg-slate-500',
|
||||
offline: 'bg-red-400',
|
||||
error: 'bg-red-400',
|
||||
warning: 'bg-yellow-400',
|
||||
unknown: 'bg-gray-500',
|
||||
paused: 'bg-yellow-400',
|
||||
exited: 'bg-slate-500',
|
||||
};
|
||||
return map[status?.toLowerCase()] ?? 'bg-gray-500';
|
||||
}
|
||||
|
||||
export function getSecurityGradeColor(grade) {
|
||||
const map = { A: 'text-green-400', B: 'text-cyan-400', C: 'text-yellow-400', D: 'text-orange-400', F: 'text-red-400' };
|
||||
return map[grade] ?? 'text-gray-400';
|
||||
}
|
||||
|
||||
export function timeAgo(date) {
|
||||
if (!date) return 'Never';
|
||||
const d = new Date(date);
|
||||
const seconds = Math.floor((new Date() - d) / 1000);
|
||||
if (seconds < 60) return `${seconds}s ago`;
|
||||
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;
|
||||
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;
|
||||
return `${Math.floor(seconds / 86400)}d ago`;
|
||||
}
|
||||
Reference in New Issue
Block a user