79 lines
3.4 KiB
TypeScript
79 lines
3.4 KiB
TypeScript
// 监控大屏 — 标签页切换 Agent / Zabbix / Prometheus // Logan.Li
|
|
import React, { useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { Monitor, Server, Activity, Maximize2, Minimize2 } from 'lucide-react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { PageShell } from '@/components/layout/PageShell';
|
|
import { promDatasourceApi, zabbixDatasourceApi } from '@/api';
|
|
import { ZabbixDashboard } from './ZabbixDashboard';
|
|
import { PrometheusDashboard } from './PrometheusDashboard';
|
|
import i18n from '@/i18n';
|
|
import type { TabId } from './grafana-dashboard/types';
|
|
import { AgentTab } from './grafana-dashboard/AgentTab';
|
|
import { ExternalDatasourceTab } from './grafana-dashboard/ExternalDatasourceTab';
|
|
import { normalizeDatasourceList } from './grafana-dashboard/datasource-toolbar';
|
|
|
|
// ═══════════ Tab 配置 ═══════════
|
|
const getTabs = (): { id: TabId; label: string; icon: React.ReactNode }[] => [
|
|
{ id: 'agent', label: i18n.t('monitor.dashboard.tab.agent'), icon: <Server className="w-3.5 h-3.5" /> },
|
|
{ id: 'zabbix', label: 'Zabbix', icon: <Activity className="w-3.5 h-3.5" /> },
|
|
{ id: 'prometheus', label: 'Prometheus', icon: <Activity className="w-3.5 h-3.5" /> },
|
|
];
|
|
|
|
// ═══════════ Zabbix Tab(薄包装) ═══════════
|
|
const ZabbixTab: React.FC = () => (
|
|
<ExternalDatasourceTab
|
|
fetcher={async () => normalizeDatasourceList(await zabbixDatasourceApi.list())}
|
|
loadingLabel={i18n.t('monitor.dashboard.zabbix.loading')}
|
|
emptyTitle={i18n.t('monitor.dashboard.zabbix.emptyTitle')}
|
|
>
|
|
{(ds) => <ZabbixDashboard key={String(ds.id)} dsUrl={ds.url} dsUsername={ds.username} dsPassword={ds.password} />}
|
|
</ExternalDatasourceTab>
|
|
);
|
|
|
|
// ═══════════ Prometheus Tab(薄包装) ═══════════
|
|
const PrometheusTab: React.FC = () => (
|
|
<ExternalDatasourceTab
|
|
fetcher={async () => normalizeDatasourceList(await promDatasourceApi.list())}
|
|
loadingLabel={i18n.t('monitor.dashboard.prometheus.loading')}
|
|
emptyTitle={i18n.t('monitor.dashboard.prometheus.emptyTitle')}
|
|
>
|
|
{(ds) => <PrometheusDashboard key={String(ds.id)} dsUrl={ds.url} />}
|
|
</ExternalDatasourceTab>
|
|
);
|
|
|
|
// ═══════════ 主组件 ═══════════
|
|
const GrafanaDashboard: React.FC = () => {
|
|
useTranslation();
|
|
const [tab, setTab] = useState<TabId>('agent');
|
|
const [fullscreen, setFullscreen] = useState(false);
|
|
|
|
const tabs = getTabs();
|
|
const pageTabs = tabs.map((item) => ({ id: item.id, label: item.label }));
|
|
|
|
return (
|
|
<PageShell
|
|
variant="workspace"
|
|
title={i18n.t('monitor.dashboard.title')}
|
|
subtitle={i18n.t('monitor.dashboard.subtitle')}
|
|
icon={<Monitor className="h-5 w-5" />}
|
|
tabs={pageTabs}
|
|
activeTab={tab}
|
|
onTabChange={(id) => setTab(id as TabId)}
|
|
className={fullscreen ? 'fixed inset-0 z-50 bg-background p-4 overflow-auto' : undefined}
|
|
contentClassName="min-h-[50vh]"
|
|
actions={
|
|
<Button variant="ghost" size="sm" className="h-7 w-7 p-0" onClick={() => setFullscreen(!fullscreen)}>
|
|
{fullscreen ? <Minimize2 className="w-3.5 h-3.5" /> : <Maximize2 className="w-3.5 h-3.5" />}
|
|
</Button>
|
|
}
|
|
>
|
|
{tab === 'agent' && <AgentTab />}
|
|
{tab === 'zabbix' && <ZabbixTab />}
|
|
{tab === 'prometheus' && <PrometheusTab />}
|
|
</PageShell>
|
|
);
|
|
};
|
|
|
|
export default GrafanaDashboard;
|