feat(web): rebuild the console around the fused control plane

Render the Hub feature set in the existing Animal Island styling: fleet
messages, notification centre, log centre, organisation panel, per-instance
device module panels and the settings backup, connection and maintenance
surfaces.
This commit is contained in:
chick
2026-09-05 18:53:04 +08:00
parent f9186bd851
commit a75badeb58
77 changed files with 20578 additions and 435 deletions
+33 -7
View File
@@ -30,20 +30,43 @@ export interface InstanceDetailProps {
export const INSTANCE_MODULE_LABELS: Readonly<Record<InstanceModule, string>> = {
overview: '实例仪表盘',
sim: 'SIM 卡',
cellular: '蜂窝网络',
'device-network': '设备网络',
messages: '短信管理',
calls: '通话',
esim: 'eSIM',
vowifi: 'WiFi 通话',
notifications: '通知',
automation: '自动化',
ota: 'OTA',
configuration: '设备设置',
'device-backup': '设备备份',
};
const PRIMARY_MODULES = ['overview', 'messages'] as const satisfies readonly InstanceModule[];
const PRIMARY_LABELS: Readonly<Record<(typeof PRIMARY_MODULES)[number], string>> = {
const MODULE_NAV: readonly InstanceModule[] = [
'overview',
'sim',
'cellular',
'device-network',
'messages',
'calls',
'esim',
'vowifi',
'notifications',
'automation',
'ota',
'configuration',
'device-backup',
] as const satisfies readonly InstanceModule[];
const SHORT_LABELS: Readonly<Partial<Record<InstanceModule, string>>> = {
overview: '仪表盘',
cellular: '蜂窝',
'device-network': '设备网络',
messages: '短信',
notifications: '通知',
configuration: '设置',
'device-backup': '备份',
};
const AUTH_LABELS = { authenticated: '已认证', 'auth-required': '需要认证' } as const;
const FRESHNESS_LABELS = {
@@ -63,9 +86,12 @@ function canRender(capability: InstanceCapability | undefined): boolean {
return capability.state === 'supported' || capability.state === 'degraded';
}
const CORE_MODULES = new Set<InstanceModule>(['overview', 'messages']);
function canOpen(module: InstanceModule, capability: InstanceCapability | undefined): boolean {
return capability ? canRender(capability) : CORE_MODULES.has(module);
/**
* Every tab is backed by a live device probe, so an unknown capability no longer hides a module;
* the module itself reports the sections a device cannot serve.
*/
function canOpen(_module: InstanceModule, capability: InstanceCapability | undefined): boolean {
return capability ? canRender(capability) : true;
}
function explanation(capability: InstanceCapability | undefined): string | null {
@@ -191,14 +217,14 @@ export function InstanceDetail({
</div>
<nav aria-label="实例模块">
<ul>
{PRIMARY_MODULES.map((item) => {
{MODULE_NAV.map((item) => {
return (
<li key={item}>
<a
href={`/instances/${encodeURIComponent(instanceId)}/${item}`}
aria-current={module === item ? 'page' : undefined}
>
{PRIMARY_LABELS[item]}
{SHORT_LABELS[item] ?? INSTANCE_MODULE_LABELS[item]}
</a>
</li>
);