feat: Redirect root to /insight, update Insight service card details, and enable live data fetching for observability adapters.

This commit is contained in:
Haitao Pan 2026-02-02 02:58:09 +08:00
parent 7112aae0ad
commit 2b121a3d21
8 changed files with 37 additions and 92 deletions

2
next-env.d.ts vendored
View File

@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/dev/types/routes.d.ts";
import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

View File

@ -58,7 +58,7 @@ export function InsightSidebarContent({
<SidebarHeader className={`flex items-start justify-between mb-7 ${collapsed ? 'flex-col items-center gap-4' : ''}`}>
{!collapsed && (
<div className="space-y-2">
<h1 className="text-lg font-semibold text-slate-100">Insight Workbench</h1>
<h1 className="text-lg font-semibold text-slate-100">Observability Workbench</h1>
<p className="text-sm text-slate-400">
Navigate topology, run cross-domain queries and keep SLOs on track.
</p>
@ -94,8 +94,8 @@ export function InsightSidebarContent({
<button
onClick={() => onSelectSection(section.id)}
className={`w-full rounded-xl transition ${collapsed
? 'flex flex-col items-center gap-2 px-2 py-3'
: 'flex items-center gap-3 px-3 py-2 text-left'
? 'flex flex-col items-center gap-2 px-2 py-3'
: 'flex items-center gap-3 px-3 py-2 text-left'
} ${active
? 'bg-slate-800 text-slate-100 shadow-inner shadow-slate-800/60'
: 'text-slate-300 hover:bg-slate-800/60'
@ -128,8 +128,8 @@ export function InsightSidebarContent({
<button
key={option.id}
className={`flex flex-col rounded-xl border px-3 py-2 text-left transition ${activeMode
? 'border-emerald-500/70 bg-emerald-500/10 text-emerald-200'
: 'border-slate-800 bg-slate-900/70 text-slate-200 hover:border-slate-700'
? 'border-emerald-500/70 bg-emerald-500/10 text-emerald-200'
: 'border-slate-800 bg-slate-900/70 text-slate-200 hover:border-slate-700'
}`}
onClick={() => onTopologyChange(option.id)}
type="button"
@ -161,8 +161,8 @@ export function InsightSidebarContent({
<button
key={option.id}
className={`flex items-center justify-between rounded-xl border px-3 py-2 text-left text-sm transition ${activeLanguage
? 'border-emerald-500/70 bg-emerald-500/10 text-emerald-200'
: 'border-slate-800 bg-slate-900/70 text-slate-200 hover:border-slate-700'
? 'border-emerald-500/70 bg-emerald-500/10 text-emerald-200'
: 'border-slate-800 bg-slate-900/70 text-slate-200 hover:border-slate-700'
}`}
onClick={() => onToggleLanguage(option.id)}
type="button"

View File

@ -20,9 +20,8 @@ const mockLogs: LogEntry[] = Array.from({ length: 25 }).map((_, idx) => ({
}))
export async function fetchLogs(query: string) {
void query
await new Promise(resolve => setTimeout(resolve, 200))
return mockLogs
const adapter = createLogsAdapter()
return adapter.queryLogs(query)
}
export function createLogsAdapter(baseUrl?: string, token?: string) {
@ -30,15 +29,10 @@ export function createLogsAdapter(baseUrl?: string, token?: string) {
return {
async queryLogs(query: string, params?: Record<string, string>) {
void params
try {
return await client.request<LogEntry[]>(`/logs/query`, {
method: 'POST',
body: JSON.stringify({ query })
})
} catch (err) {
console.warn('Logs adapter fallback to mock', err)
return fetchLogs(query)
}
return await client.request<LogEntry[]>(`/logs/query`, {
method: 'POST',
body: JSON.stringify({ query })
})
}
}
}

View File

@ -4,7 +4,7 @@ export interface ClientOptions {
}
export function createOpenObserveClient(options: ClientOptions = {}) {
const { baseUrl = '/api', token } = options
const { baseUrl = 'https://infra.svc.plus/api', token } = options
async function request<T>(path: string, init?: RequestInit): Promise<T> {
const headers = new Headers(init?.headers)

View File

@ -28,10 +28,8 @@ const mockSeries: PrometheusResponse[] = [
]
export async function fetchPromQL(query: string) {
void query
// Replace with API call when backend is ready.
await new Promise(resolve => setTimeout(resolve, 300))
return mockSeries
const adapter = createPrometheusAdapter()
return adapter.queryRange(query)
}
export function createPrometheusAdapter(baseUrl?: string, token?: string) {
@ -39,15 +37,13 @@ export function createPrometheusAdapter(baseUrl?: string, token?: string) {
return {
async queryRange(query: string, params?: Record<string, string>) {
void params
try {
return await client.request<PrometheusResponse[]>(`/prometheus/query`, {
method: 'POST',
body: JSON.stringify({ query })
})
} catch (err) {
console.warn('Prometheus adapter fallback to mock', err)
return fetchPromQL(query)
}
return await client.request<PrometheusResponse[]>(`/prometheus/api/v1/query`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({ query }).toString()
})
}
}
}

View File

@ -44,9 +44,8 @@ const mockTrace: TraceSpan[] = [
]
export async function fetchTraces(query: string) {
void query
await new Promise(resolve => setTimeout(resolve, 250))
return mockTrace
const adapter = createTracesAdapter()
return adapter.queryTraces(query)
}
export function createTracesAdapter(baseUrl?: string, token?: string) {
@ -54,15 +53,10 @@ export function createTracesAdapter(baseUrl?: string, token?: string) {
return {
async queryTraces(query: string, params?: Record<string, string>) {
void params
try {
return await client.request<TraceSpan[]>(`/traces/query`, {
method: 'POST',
body: JSON.stringify({ query })
})
} catch (err) {
console.warn('Traces adapter fallback to mock', err)
return fetchTraces(query)
}
return await client.request<TraceSpan[]>(`/traces/query`, {
method: 'POST',
body: JSON.stringify({ query })
})
}
}
}

View File

@ -118,40 +118,11 @@ const shortcuts = [
},
];
import { redirect } from "next/navigation";
export default function HomePage() {
const { mode, isOpen, setIsOpen, setMinimized, close } = useMoltbotStore();
const isSidebar = mode !== 'overlay' && isOpen;
return (
<div className="min-h-screen bg-background text-text transition-colors duration-150 flex flex-col">
<UnifiedNavigation />
<div className={cn(
"flex flex-1 relative overflow-hidden",
mode === 'left-sidebar' && "flex-row-reverse"
)}>
<div className="flex-1 overflow-y-auto relative">
<div className="relative mx-auto max-w-7xl px-6 pb-20">
<div
className="absolute inset-0 bg-gradient-app-from opacity-20 pointer-events-none"
aria-hidden
/>
<main className="relative space-y-12 pt-10">
<HeroSection />
<NextStepsSection />
<StatsSection />
<ShortcutsSection />
</main>
<div className="relative">
<Footer />
</div>
</div>
</div>
</div>
</div>
);
redirect("/insight");
return null;
}
export function HeroSection() {

View File

@ -246,23 +246,13 @@ export default function ServicesPage() {
},
{
key: "insight",
name: isChinese ? "Insight 工作台" : "Insight Workbench",
name: isChinese ? "监控与观测" : "Monitoring & Observability",
description: isChinese
? "进入观测、告警与智能协作控制面。"
: "Observability, alerts, and AI-assisted operations.",
? "基础设施、数据库与应用系统的全栈可观测性工作台。"
: "Full-stack observability workbench for infrastructure, databases, and apps.",
href: "/insight",
icon: Gauge,
},
{
key: "infra-monitor",
name: isChinese ? "基础设施监控" : "Infrastructure Monitoring",
description: isChinese
? "基于 Pigsty 4.0 (Apache-2.0) 构建的开源可观测性与监控平台。"
: "Open-source observability based on Pigsty 4.0 (Apache-2.0).",
href: "https://infra.svc.plus/",
icon: Database,
external: true,
},
{
key: "ai-gateway",
name: isChinese ? "AI 网关" : "AI Gateway",