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:
@@ -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>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user