import type { ReactNode } from 'react'; import { useEffect, useRef, useState } from 'react'; import type { InstanceContext, InstanceModule } from '../app-shell.js'; import { canonicalHttpOrigin } from '../fleet/fleet-page.js'; import { displayStatus } from '../ui/locale.js'; export type CapabilityState = 'supported' | 'degraded' | 'unsupported' | 'unknown'; export interface InstanceCapability { readonly state: CapabilityState; readonly explanation?: string; } export type InstanceCapabilityMap = Readonly>>; export interface CapabilityDataSource { load(instanceId: string, signal: AbortSignal): Promise; } export interface InstanceDetailProps { readonly instanceId: string; readonly module: InstanceModule; readonly instance?: InstanceContext; readonly capabilities?: InstanceCapabilityMap; readonly capabilityDataSource?: CapabilityDataSource; readonly moduleContent?: ReactNode; } export const INSTANCE_MODULE_LABELS: Readonly> = { overview: '设备信息', cellular: '蜂窝网络', 'device-network': '设备网络', messages: '短信', calls: '通话', esim: 'eSIM', notifications: '通知', automation: '自动化', ota: 'OTA', }; const PRIMARY_MODULES = ['messages', 'overview'] as const satisfies readonly InstanceModule[]; const DEFAULT_EXPLANATIONS: Readonly, string>> = { degraded: '此模块可用,但功能受限。', unsupported: '此实例不支持该模块。', unknown: '能力状态未知。', }; function canRender(capability: InstanceCapability | undefined): boolean { if (!capability) return true; return capability.state === 'supported' || capability.state === 'degraded'; } const CORE_MODULES = new Set(['overview', 'messages']); function canOpen(module: InstanceModule, capability: InstanceCapability | undefined): boolean { return capability ? canRender(capability) : CORE_MODULES.has(module); } function explanation(capability: InstanceCapability | undefined): string | null { if (!capability) return null; if (capability.state === 'supported') return null; return capability.explanation?.trim() || DEFAULT_EXPLANATIONS[capability.state]; } /** * Owner-fenced instance context and capability navigation for every instance route. * Capability discovery is injected: this framework deliberately assumes no API or operation IDs. */ export function InstanceDetail({ instanceId, module, instance, capabilities, capabilityDataSource, moduleContent, }: InstanceDetailProps) { const ownsRoute = instance?.id === instanceId; const [loadedCapabilities, setLoadedCapabilities] = useState(); const [loading, setLoading] = useState(false); const [loadError, setLoadError] = useState(null); const requestRef = useRef(0); useEffect(() => { const request = ++requestRef.current; setLoadedCapabilities(undefined); setLoadError(null); if (!ownsRoute || capabilities || !capabilityDataSource) { setLoading(false); return; } const controller = new AbortController(); setLoading(true); void capabilityDataSource.load(instanceId, controller.signal).then( (result) => { if (!controller.signal.aborted && requestRef.current === request) { setLoadedCapabilities(result); setLoading(false); } }, (error: unknown) => { void error; if (!controller.signal.aborted && requestRef.current === request) { setLoadError('能力探测失败。'); setLoading(false); } }, ); return () => controller.abort(); }, [capabilities, capabilityDataSource, instanceId, ownsRoute]); if (!ownsRoute) { return (

{INSTANCE_MODULE_LABELS[module]}

此路由缺少实例上下文。

); } const map = capabilities ?? loadedCapabilities ?? {}; const origin = canonicalHttpOrigin(instance.origin); const activeCapability = map[module]; return (

{INSTANCE_MODULE_LABELS[module]}

{loading ?

正在加载能力…

: null} {loadError ?

能力不可用:{loadError}

: null} {!loading && canOpen(module, activeCapability) ? ( <> {activeCapability?.state === 'degraded' ? (

{explanation(activeCapability)}

) : null} {moduleContent ??

查看{INSTANCE_MODULE_LABELS[module]}数据和可用操作。

} ) : null} {!loading && !canOpen(module, activeCapability) ? (

{explanation(activeCapability)}

) : null}
); }