Files
Infra-Management/resources/js/Pages/Admin/Index.jsx
I-Fun c649f055d8 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.
2026-04-07 20:29:32 +07:00

94 lines
5.6 KiB
JavaScript

import AppLayout from '@/Layouts/AppLayout';
import { Head, router } from '@inertiajs/react';
import { Settings, Users, Activity, Shield, Database, Globe, Server, ChevronRight } from 'lucide-react';
import { GlassCard } from '@/Components/ui/GlassCard';
import { Button } from '@/Components/ui/Button';
import { motion } from 'framer-motion';
import { timeAgo } from '@/lib/utils';
const adminSections = [
{ title: 'General Settings', href: '/admin/settings', icon: Settings, desc: 'App name, theme, session timeout' },
{ title: 'LDAP / SSO', href: '/admin/ldap', icon: Globe, desc: 'Configure LDAP/AD authentication' },
{ title: 'Users', href: '/acl/users', icon: Users, desc: 'Manage user accounts' },
{ title: 'Roles & ACL', href: '/acl/roles', icon: Shield, desc: 'Roles and permission management' },
{ title: 'Audit Log', href: '/admin/audit-log', icon: Activity, desc: 'User activity and system events' },
{ title: 'System Health', href: '/admin/system-health',icon: Server, desc: 'Database, queues, storage status' },
];
export default function AdminIndex({ stats, recent_activity }) {
return (
<AppLayout title="Administration">
<Head title="Administration" />
<div className="space-y-5">
<div>
<h2 className="text-xl font-bold text-white">Administration</h2>
<p className="text-sm text-white/40">System settings, users, and maintenance</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
{adminSections.map(s => {
const Icon = s.icon;
return (
<a key={s.href} href={s.href}>
<GlassCard className="p-5 cursor-pointer group" hover glow="cyan">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-white/5 border border-white/10 flex items-center justify-center group-hover:border-cyan-500/30 group-hover:bg-cyan-500/10 transition-all">
<Icon className="w-5 h-5 text-white/50 group-hover:text-cyan-400 transition-colors" />
</div>
<div>
<p className="text-sm font-medium text-white group-hover:text-cyan-300 transition-colors">{s.title}</p>
<p className="text-xs text-white/30">{s.desc}</p>
</div>
</div>
<ChevronRight className="w-4 h-4 text-white/20 group-hover:text-white/50 transition-colors" />
</div>
</GlassCard>
</a>
);
})}
</div>
{/* System stats */}
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
{[
{ label: 'Total Users', value: stats?.users ?? 0 },
{ label: 'Active Sessions', value: stats?.sessions ?? 0 },
{ label: 'Queue Jobs', value: stats?.queued ?? 0 },
{ label: 'DB Size', value: stats?.db_size ?? '—' },
].map(s => (
<GlassCard key={s.label} className="p-4 text-center">
<p className="text-2xl font-bold text-white">{s.value}</p>
<p className="text-xs text-white/40 mt-0.5">{s.label}</p>
</GlassCard>
))}
</div>
{/* Recent activity */}
<GlassCard className="p-5">
<div className="flex items-center justify-between mb-4">
<h3 className="text-sm font-semibold text-white">Recent Activity</h3>
<a href="/admin/audit-log"><Button size="sm" variant="ghost">View All →</Button></a>
</div>
<div className="space-y-2">
{(recent_activity ?? []).map((log, i) => (
<div key={i} className="flex items-start gap-3 py-2 border-b border-white/[0.05] last:border-0">
<div className="w-7 h-7 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-xs shrink-0">
{log.causer?.name?.charAt(0)?.toUpperCase() ?? '?'}
</div>
<div className="flex-1 min-w-0">
<p className="text-sm text-white/80">{log.description}</p>
<p className="text-xs text-white/30">{log.causer?.name ?? 'System'} · {timeAgo(log.created_at)}</p>
</div>
</div>
))}
{(!recent_activity || recent_activity.length === 0) && (
<p className="text-sm text-white/30 text-center py-4">No recent activity</p>
)}
</div>
</GlassCard>
</div>
</AppLayout>
);
}