diff --git a/chimera/web-ui/app/api/telemetry/route.ts b/chimera/web-ui/app/api/telemetry/route.ts new file mode 100644 index 00000000..941009fc --- /dev/null +++ b/chimera/web-ui/app/api/telemetry/route.ts @@ -0,0 +1,15 @@ +import { NextResponse } from 'next/server'; + +export async function GET() { + // Stub telemetry record until backend wiring is complete + const data = { + hash: 'demo-hash', + metrics: { + eccErrors: 0, + temperature: 70, + nvlinkErrors: 0, + migEvents: [], + }, + }; + return NextResponse.json(data); +} diff --git a/chimera/web-ui/app/page.tsx b/chimera/web-ui/app/page.tsx index 3f82e933..73cad57a 100644 --- a/chimera/web-ui/app/page.tsx +++ b/chimera/web-ui/app/page.tsx @@ -1,3 +1,13 @@ +import AuthProvider from '../components/AuthProvider'; +import TelemetryClient from '../components/TelemetryClient'; + export default function Home() { - return
Chimera Dashboard
; + return ( + +
+

Chimera Dashboard

+ +
+
+ ); } diff --git a/chimera/web-ui/components/AuthProvider.tsx b/chimera/web-ui/components/AuthProvider.tsx new file mode 100644 index 00000000..735ef4ed --- /dev/null +++ b/chimera/web-ui/components/AuthProvider.tsx @@ -0,0 +1,18 @@ +'use client'; + +import { createContext, useContext } from 'react'; + +export interface User { + name: string; +} + +const AuthContext = createContext({ name: 'demo-user' }); + +export function useUser() { + return useContext(AuthContext); +} + +export default function AuthProvider({ children }: { children: React.ReactNode }) { + // TODO: replace with real OIDC integration + return {children}; +} diff --git a/chimera/web-ui/components/TelemetryClient.tsx b/chimera/web-ui/components/TelemetryClient.tsx new file mode 100644 index 00000000..697f6063 --- /dev/null +++ b/chimera/web-ui/components/TelemetryClient.tsx @@ -0,0 +1,27 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import TelemetryTable, { TelemetryRecord } from './TelemetryTable'; + +export default function TelemetryClient() { + const [records, setRecords] = useState([]); + + useEffect(() => { + async function load() { + const res = await fetch('/api/telemetry'); + if (res.ok) { + const data = await res.json(); + setRecords([data]); + } + } + load(); + const id = setInterval(load, 5000); + return () => clearInterval(id); + }, []); + + return ( +
+ +
+ ); +} diff --git a/chimera/web-ui/components/TelemetryTable.tsx b/chimera/web-ui/components/TelemetryTable.tsx new file mode 100644 index 00000000..841f438f --- /dev/null +++ b/chimera/web-ui/components/TelemetryTable.tsx @@ -0,0 +1,36 @@ +export interface TelemetryRecord { + hash: string; + metrics: { + eccErrors: number; + temperature: number; + nvlinkErrors: number; + migEvents: string[]; + }; +} + +export default function TelemetryTable({ records }: { records: TelemetryRecord[] }) { + return ( + + + + + + + + + + + + {records.map((r, idx) => ( + + + + + + + + ))} + +
HashECC ErrorsTemp (C)NVLink ErrorsMIG Events
{r.hash}{r.metrics.eccErrors}{r.metrics.temperature}{r.metrics.nvlinkErrors}{r.metrics.migEvents.join(', ')}
+ ); +} diff --git a/chimera/web-ui/tailwind.config.js b/chimera/web-ui/tailwind.config.js index 0ccd0260..49862c21 100644 --- a/chimera/web-ui/tailwind.config.js +++ b/chimera/web-ui/tailwind.config.js @@ -1,5 +1,8 @@ module.exports = { - content: ["./app/**/*.{js,ts,jsx,tsx}"] , + content: [ + "./app/**/*.{js,ts,jsx,tsx}", + "./components/**/*.{js,ts,jsx,tsx}", + ], theme: { extend: {}, },