diff --git a/portal/frontend/src/pages/AdminCustomerDetailPage.tsx b/portal/frontend/src/pages/AdminCustomerDetailPage.tsx index da9b9b0..90853a9 100644 --- a/portal/frontend/src/pages/AdminCustomerDetailPage.tsx +++ b/portal/frontend/src/pages/AdminCustomerDetailPage.tsx @@ -1,15 +1,20 @@ -import { Card, Descriptions, Tabs, Table, Tag, Typography, Button, Space, Spin, Result } from 'antd'; +import { Card, Descriptions, Tabs, Table, Tag, Typography, Button, Space, Spin, Result, Tooltip } from 'antd'; import type { ColumnsType } from 'antd/es/table'; -import { ArrowLeftOutlined } from '@ant-design/icons'; +import { ArrowLeftOutlined, LineChartOutlined } from '@ant-design/icons'; import { useQuery } from '@tanstack/react-query'; import { useNavigate, useParams } from 'react-router-dom'; import { fetchFleetCustomerDetail, type FleetSite, type FleetDevice, type FleetRecentMeasurement, type FleetIngestEvent, } from '../api/fleet'; +import { fetchGrafanaConfig } from '../api/grafana'; const { Text } = Typography; +// UID of the customer-drilldown dashboard provisioned in grafana/dashboards-admin/. +// Coordinated change: rename here and in the JSON together. +const CUSTOMER_DRILLDOWN_UID = 'customer-drilldown'; + export function AdminCustomerDetailPage() { const { id = '' } = useParams<{ id: string }>(); const navigate = useNavigate(); @@ -18,6 +23,17 @@ export function AdminCustomerDetailPage() { queryFn: () => fetchFleetCustomerDetail(id), refetchInterval: 30_000, }); + const { data: grafana } = useQuery({ + queryKey: ['grafana-config'], + queryFn: fetchGrafanaConfig, + staleTime: 5 * 60_000, + }); + + const drilldownUrl = (() => { + if (!data || !grafana?.baseUrl) return null; + const base = grafana.baseUrl.replace(/\/$/, ''); + return `${base}/d/${encodeURIComponent(CUSTOMER_DRILLDOWN_UID)}?orgId=1&kiosk=tv&theme=light&var-customer=${encodeURIComponent(data.id)}`; + })(); if (isLoading) return
; if (error || !data) { @@ -56,10 +72,28 @@ export function AdminCustomerDetailPage() { return ( - - - {data.code} · {data.name} - {data.isActive ? Active : Disabled} + + + + {data.code} · {data.name} + {data.isActive ? Active : Disabled} + + + +