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:
I-Fun
2026-04-07 20:29:32 +07:00
commit c649f055d8
126 changed files with 8122 additions and 0 deletions

10
routes/api.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
use App\Http\Controllers\Api\MetricsController;
use App\Http\Controllers\Api\WebSocketController;
use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->group(function () {
Route::get('/metrics/{target}', [MetricsController::class, 'live']);
Route::get('/terminal/{vm}', [WebSocketController::class, 'vmConsole']);
});

16
routes/console.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schedule;
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote');
Schedule::command('infra:sync-hypervisors')->everyFiveMinutes();
Schedule::command('infra:sync-containers')->everyThreeMinutes();
Schedule::command('infra:sync-cloud')->everyTenMinutes();
Schedule::command('infra:collect-metrics')->everyMinute();
Schedule::command('infra:check-certificates')->daily();
Schedule::command('infra:check-backups')->hourly();

205
routes/web.php Normal file
View File

@@ -0,0 +1,205 @@
<?php
use App\Http\Controllers\Auth\AuthController;
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\Hypervisor\HypervisorController;
use App\Http\Controllers\Hypervisor\VirtualMachineController;
use App\Http\Controllers\Hypervisor\TemplateController;
use App\Http\Controllers\Container\ContainerController;
use App\Http\Controllers\Container\StackController;
use App\Http\Controllers\Cloud\CloudAccountController;
use App\Http\Controllers\Cloud\CloudResourceController;
use App\Http\Controllers\Security\SecurityDashboardController;
use App\Http\Controllers\Security\ScanController;
use App\Http\Controllers\Backup\BackupController;
use App\Http\Controllers\Backup\RestoreController;
use App\Http\Controllers\Monitoring\MonitoringController;
use App\Http\Controllers\Identity\PasswordController;
use App\Http\Controllers\Identity\CertificateController;
use App\Http\Controllers\Wiki\WikiController;
use App\Http\Controllers\Wiki\DocumentController;
use App\Http\Controllers\Acl\RoleController;
use App\Http\Controllers\Acl\UserController;
use App\Http\Controllers\Admin\AdminController;
use App\Http\Controllers\Admin\LdapController;
use App\Http\Controllers\Admin\SettingsController;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
// ─── Auth Routes ────────────────────────────────────────────────────
Route::middleware('guest')->group(function () {
Route::get('/login', [AuthController::class, 'showLogin'])->name('login');
Route::post('/login', [AuthController::class, 'login']);
});
Route::post('/logout', [AuthController::class, 'logout'])->name('logout')->middleware('auth');
// ─── Authenticated Routes ────────────────────────────────────────────
Route::middleware(['auth'])->group(function () {
// Dashboard
Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
// ── Hypervisor / vCenter ──────────────────────────────────────
Route::prefix('hypervisors')->name('hypervisors.')->group(function () {
Route::get('/', [HypervisorController::class, 'index'])->name('index');
Route::get('/create', [HypervisorController::class, 'create'])->name('create');
Route::post('/', [HypervisorController::class, 'store'])->name('store');
Route::get('/{hypervisor}', [HypervisorController::class, 'show'])->name('show');
Route::get('/{hypervisor}/edit', [HypervisorController::class, 'edit'])->name('edit');
Route::put('/{hypervisor}', [HypervisorController::class, 'update'])->name('update');
Route::delete('/{hypervisor}', [HypervisorController::class, 'destroy'])->name('destroy');
Route::post('/{hypervisor}/sync', [HypervisorController::class, 'sync'])->name('sync');
Route::post('/{hypervisor}/test-connection', [HypervisorController::class, 'testConnection'])->name('test-connection');
});
Route::prefix('virtual-machines')->name('vms.')->group(function () {
Route::get('/', [VirtualMachineController::class, 'index'])->name('index');
Route::get('/{vm}', [VirtualMachineController::class, 'show'])->name('show');
Route::post('/{vm}/power', [VirtualMachineController::class, 'power'])->name('power');
Route::post('/{vm}/snapshot', [VirtualMachineController::class, 'snapshot'])->name('snapshot');
Route::post('/{vm}/clone', [VirtualMachineController::class, 'clone'])->name('clone');
Route::post('/{vm}/migrate', [VirtualMachineController::class, 'migrate'])->name('migrate');
});
Route::prefix('templates')->name('templates.')->group(function () {
Route::get('/', [TemplateController::class, 'index'])->name('index');
Route::get('/create', [TemplateController::class, 'create'])->name('create');
Route::post('/', [TemplateController::class, 'store'])->name('store');
Route::get('/{template}', [TemplateController::class, 'show'])->name('show');
Route::get('/{template}/edit', [TemplateController::class, 'edit'])->name('edit');
Route::put('/{template}', [TemplateController::class, 'update'])->name('update');
Route::delete('/{template}', [TemplateController::class, 'destroy'])->name('destroy');
Route::post('/{template}/deploy', [TemplateController::class, 'deploy'])->name('deploy');
});
// ── Containers / Docker ───────────────────────────────────────
Route::prefix('containers')->name('containers.')->group(function () {
Route::get('/', [ContainerController::class, 'index'])->name('index');
Route::get('/{container}', [ContainerController::class, 'show'])->name('show');
Route::post('/{container}/action', [ContainerController::class, 'action'])->name('action');
Route::get('/{container}/logs', [ContainerController::class, 'logs'])->name('logs');
Route::get('/{container}/stats', [ContainerController::class, 'stats'])->name('stats');
Route::delete('/{container}', [ContainerController::class, 'destroy'])->name('destroy');
});
Route::prefix('stacks')->name('stacks.')->group(function () {
Route::get('/', [StackController::class, 'index'])->name('index');
Route::get('/create', [StackController::class, 'create'])->name('create');
Route::post('/', [StackController::class, 'store'])->name('store');
Route::get('/{stack}', [StackController::class, 'show'])->name('show');
Route::get('/{stack}/edit', [StackController::class, 'edit'])->name('edit');
Route::put('/{stack}', [StackController::class, 'update'])->name('update');
Route::delete('/{stack}', [StackController::class, 'destroy'])->name('destroy');
Route::post('/{stack}/deploy', [StackController::class, 'deploy'])->name('deploy');
});
// ── Cloud Accounts ────────────────────────────────────────────
Route::prefix('cloud')->name('cloud.')->group(function () {
Route::get('/', [CloudAccountController::class, 'index'])->name('index');
Route::get('/accounts/create', [CloudAccountController::class, 'create'])->name('accounts.create');
Route::post('/accounts', [CloudAccountController::class, 'store'])->name('accounts.store');
Route::get('/accounts/{account}', [CloudAccountController::class, 'show'])->name('accounts.show');
Route::get('/accounts/{account}/edit', [CloudAccountController::class, 'edit'])->name('accounts.edit');
Route::put('/accounts/{account}', [CloudAccountController::class, 'update'])->name('accounts.update');
Route::delete('/accounts/{account}', [CloudAccountController::class, 'destroy'])->name('accounts.destroy');
Route::get('/resources', [CloudResourceController::class, 'index'])->name('resources.index');
Route::get('/resources/{resource}', [CloudResourceController::class, 'show'])->name('resources.show');
Route::post('/accounts/{account}/sync', [CloudAccountController::class, 'sync'])->name('accounts.sync');
});
// ── Security Dashboard ────────────────────────────────────────
Route::prefix('security')->name('security.')->group(function () {
Route::get('/', [SecurityDashboardController::class, 'index'])->name('index');
Route::get('/scans', [ScanController::class, 'index'])->name('scans.index');
Route::post('/scans', [ScanController::class, 'store'])->name('scans.store');
Route::get('/scans/{scan}', [ScanController::class, 'show'])->name('scans.show');
Route::get('/vulnerabilities', [SecurityDashboardController::class, 'vulnerabilities'])->name('vulnerabilities');
Route::get('/compliance', [SecurityDashboardController::class, 'compliance'])->name('compliance');
});
// ── Backup & DR ───────────────────────────────────────────────
Route::prefix('backups')->name('backups.')->group(function () {
Route::get('/', [BackupController::class, 'index'])->name('index');
Route::post('/', [BackupController::class, 'store'])->name('store');
Route::get('/{backup}', [BackupController::class, 'show'])->name('show');
Route::delete('/{backup}', [BackupController::class, 'destroy'])->name('destroy');
Route::post('/{backup}/restore', [RestoreController::class, 'restore'])->name('restore');
Route::get('/schedules', [BackupController::class, 'schedules'])->name('schedules');
Route::post('/schedules', [BackupController::class, 'storeSchedule'])->name('schedules.store');
});
// ── Monitoring ────────────────────────────────────────────────
Route::prefix('monitoring')->name('monitoring.')->group(function () {
Route::get('/', [MonitoringController::class, 'index'])->name('index');
Route::get('/metrics/{target}', [MonitoringController::class, 'metrics'])->name('metrics');
Route::get('/alerts', [MonitoringController::class, 'alerts'])->name('alerts');
Route::post('/alerts/{alert}/acknowledge', [MonitoringController::class, 'acknowledge'])->name('alerts.acknowledge');
Route::get('/dashboards', [MonitoringController::class, 'dashboards'])->name('dashboards');
});
// ── Identity / Secrets ────────────────────────────────────────
Route::prefix('identity')->name('identity.')->group(function () {
Route::get('/', fn() => Inertia::render('Identity/Index'))->name('index');
Route::prefix('passwords')->name('passwords.')->group(function () {
Route::get('/', [PasswordController::class, 'index'])->name('index');
Route::post('/', [PasswordController::class, 'store'])->name('store');
Route::get('/{password}/reveal', [PasswordController::class, 'reveal'])->name('reveal');
Route::put('/{password}', [PasswordController::class, 'update'])->name('update');
Route::delete('/{password}', [PasswordController::class, 'destroy'])->name('destroy');
});
Route::prefix('certificates')->name('certificates.')->group(function () {
Route::get('/', [CertificateController::class, 'index'])->name('index');
Route::post('/', [CertificateController::class, 'store'])->name('store');
Route::get('/{cert}', [CertificateController::class, 'show'])->name('show');
Route::delete('/{cert}', [CertificateController::class, 'destroy'])->name('destroy');
Route::post('/generate', [CertificateController::class, 'generate'])->name('generate');
});
});
// ── Wiki / Documents ──────────────────────────────────────────
Route::prefix('wiki')->name('wiki.')->group(function () {
Route::get('/', [WikiController::class, 'index'])->name('index');
Route::get('/spaces', [WikiController::class, 'spaces'])->name('spaces');
Route::get('/spaces/{space}', [WikiController::class, 'space'])->name('space');
Route::get('/pages/create', [DocumentController::class, 'create'])->name('pages.create');
Route::post('/pages', [DocumentController::class, 'store'])->name('pages.store');
Route::get('/pages/{page}', [DocumentController::class, 'show'])->name('pages.show');
Route::get('/pages/{page}/edit', [DocumentController::class, 'edit'])->name('pages.edit');
Route::put('/pages/{page}', [DocumentController::class, 'update'])->name('pages.update');
Route::delete('/pages/{page}', [DocumentController::class, 'destroy'])->name('pages.destroy');
Route::get('/files', [WikiController::class, 'files'])->name('files');
Route::post('/files', [WikiController::class, 'uploadFile'])->name('files.upload');
Route::delete('/files/{file}', [WikiController::class, 'deleteFile'])->name('files.delete');
});
// ── ACL / Roles & Users ───────────────────────────────────────
Route::middleware(['role:admin|super-admin'])->group(function () {
Route::prefix('acl')->name('acl.')->group(function () {
Route::get('/', fn() => Inertia::render('Acl/Index'))->name('index');
Route::resource('roles', RoleController::class);
Route::resource('users', UserController::class);
Route::post('/users/{user}/roles', [UserController::class, 'assignRole'])->name('users.roles');
});
// ── Administration ────────────────────────────────────────
Route::prefix('admin')->name('admin.')->group(function () {
Route::get('/', [AdminController::class, 'index'])->name('index');
Route::get('/settings', [SettingsController::class, 'index'])->name('settings');
Route::put('/settings', [SettingsController::class, 'update'])->name('settings.update');
Route::get('/audit-log', [AdminController::class, 'auditLog'])->name('audit-log');
Route::get('/system-health', [AdminController::class, 'systemHealth'])->name('system-health');
Route::prefix('ldap')->name('ldap.')->group(function () {
Route::get('/', [LdapController::class, 'index'])->name('index');
Route::put('/', [LdapController::class, 'update'])->name('update');
Route::post('/test', [LdapController::class, 'test'])->name('test');
Route::post('/sync', [LdapController::class, 'sync'])->name('sync');
});
});
});
});