initial commit

This commit is contained in:
2026-05-07 06:41:36 +01:00
commit 783400884a
23 changed files with 2904 additions and 0 deletions

21
src/app/api/lxc/route.js Normal file
View File

@@ -0,0 +1,21 @@
import { NextResponse } from 'next/server';
import { getNodes, getLXC } from '@/lib/proxmox';
/** @param {import('next').Request} _req */
export async function GET(_req) {
try {
const nodes = await getNodes();
const allLXC = [];
for (const node of nodes) {
try {
const lxcs = await getLXC(node.name);
allLXC.push(...lxcs.map((lxc) => ({ ...lxc, node: node.name })));
} catch { /* skip node */ }
}
return NextResponse.json({ data: allLXC, timestamp: Date.now() });
} catch (error) {
return NextResponse.json({ error: error.message, data: null }, { status: 502 });
}
}

View File

@@ -0,0 +1,12 @@
import { NextResponse } from 'next/server';
import { getNodes } from '@/lib/proxmox';
/** @param {import('next').Request} _req */
export async function GET(_req) {
try {
const data = await getNodes();
return NextResponse.json({ data, timestamp: Date.now() });
} catch (error) {
return NextResponse.json({ error: error.message, data: null }, { status: 502 });
}
}

View File

@@ -0,0 +1,12 @@
import { NextResponse } from 'next/server';
import { getSummary } from '@/lib/proxmox';
/** @param {import('next').Request} _req */
export async function GET(_req) {
try {
const data = await getSummary();
return NextResponse.json({ data, timestamp: Date.now() });
} catch (error) {
return NextResponse.json({ error: error.message, data: null }, { status: 502 });
}
}

21
src/app/api/vms/route.js Normal file
View File

@@ -0,0 +1,21 @@
import { NextResponse } from 'next/server';
import { getNodes, getVMs } from '@/lib/proxmox';
/** @param {import('next').Request} _req */
export async function GET(_req) {
try {
const nodes = await getNodes();
const allVMs = [];
for (const node of nodes) {
try {
const vms = await getVMs(node.name);
allVMs.push(...vms.map((vm) => ({ ...vm, node: node.name })));
} catch { /* skip node */ }
}
return NextResponse.json({ data: allVMs, timestamp: Date.now() });
} catch (error) {
return NextResponse.json({ error: error.message, data: null }, { status: 502 });
}
}

22
src/app/globals.css Normal file
View File

@@ -0,0 +1,22 @@
@import "tailwindcss";
@theme {
--color-bg-primary: #0b0f19;
--color-bg-card: #111827;
--color-bg-card-hover: #1a2332;
--color-border-card: #1e293b;
--color-text-primary: #f1f5f9;
--color-text-secondary: #94a3b8;
--color-accent: #3b82f6;
--color-status-green: #22c55e;
--color-status-red: #ef4444;
--color-status-yellow: #eab308;
--color-status-gray: #64748b;
}
@layer base {
html {
background-color: var(--color-bg-primary);
color: var(--color-text-primary);
}
}

19
src/app/layout.js Normal file
View File

@@ -0,0 +1,19 @@
import './globals.css';
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
/** @type {import('next').Metadata} */
export const metadata = {
title: 'Proxmox Monitor',
description: 'Real-time dashboard for Proxmox VE',
};
/** @param {{ children: import('react').ReactNode }} props */
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
);
}

6
src/app/page.js Normal file
View File

@@ -0,0 +1,6 @@
import Dashboard from '@/components/Dashboard';
/** @returns {import('react').ReactNode} */
export default function HomePage() {
return <Dashboard />;
}