refactor(web): 随路径式入口清理失效的管理链接(设计:用户端不提供管理入口)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- TopBar / Nav 的 hash 形式管理入口(#/admin、#/admin/system)**删除**(design/07 §0.2:用户端不提供任何
  管理入口、bundle 不含该路径串);面板只经 ADMIN_PATH 路径直入
- AdminApp 三处 window.location.hash = "" 改调 router 导出的 navigateUserShell()
- 复核:tsc 0 错 + vite build 成功;用户端源码 grep "#/admin" 0 命中(仅在 channels/useAdapterNav.ts
  尚有模块内闭环的 hash 字面量,属另一决策,仅报告未改)
- 局限:无 playwright/puppeteer 且不许加依赖 ⇒ 「布局未塌」为结构+静态样式依赖推断(无子元素数量相关样式)
This commit is contained in:
AskaEth committed 2026-10-04 14:01:43 +08:00
1 parent a398dc9b92
commit 852c327360
3 files changed
+5 -29

No files matched your search

+4 -4
View File
@@ -5,7 +5,7 @@ import { useAppStore } from "../store/useAppStore";
import type { WsStatus } from "../lib/types";
import { UiModeSwitch } from "../design/UiModeSwitch";
import { ADMIN_GROUPS, ADMIN_SECTIONS } from "./sections";
import { navigateAdmin, type AdminSectionId } from "./router";
import { navigateAdmin, navigateUserShell, type AdminSectionId } from "./router";
import { Button, Tag, type TagTone } from "../components/primitives";
import { Icon } from "../components/Icon";
import { DashboardModule } from "./modules/Dashboard";
@@ -239,7 +239,7 @@ function AdminTopBar({ section, onMenu }: { section: AdminSectionId; onMenu?: ()
>
<Icon name={theme === "dark" ? "sun" : "moon"} size={18} />
</button>
<Button size="sm" variant="ghost" className="shrink-0" onClick={() => { window.location.hash = ""; }}>
<Button size="sm" variant="ghost" className="shrink-0" onClick={() => { navigateUserShell(); }}>
返回用户端
</Button>
</header>
@@ -256,7 +256,7 @@ function LoginGate(): React.ReactNode {
<p className="max-w-md text-sm text-[var(--mu-text-lo)]">
管理面板需持有 JWT。请先在用户端 <span className="text-[var(--mu-text-hi)]">登录页</span> 完成登录后,再返回本页。
</p>
<Button variant="primary" onClick={() => { window.location.hash = ""; }}>前往用户端登录</Button>
<Button variant="primary" onClick={() => { navigateUserShell(); }}>前往用户端登录</Button>
</div>
);
}
@@ -273,7 +273,7 @@ function Forbidden403(): React.ReactNode {
当前角色 <Tag tone="neutral">{role ?? "?"}</Tag>(viewer 只读)。管理面板需 <Tag tone="accent">owner</Tag> 或 <Tag tone="ok">admin</Tag> 角色;管理端写操作仅 owner。
</p>
<div className="flex gap-2">
<Button variant="primary" onClick={() => { window.location.hash = ""; }}>返回用户端</Button>
<Button variant="primary" onClick={() => { navigateUserShell(); }}>返回用户端</Button>
</div>
</div>
);
+1 -17
View File
@@ -16,7 +16,7 @@ import { Tag } from "./primitives";
* at runtime by the agent / user, and rendered per message). This is a small
* navigation rail: brand + connection status + the conversation list
* (`SessionRail`, which also owns per-session role picking, design/22 §4.6) +
* theme + admin/settings entry.
* 主题切换 + UI 档位开关(双档,裁决 16.4.4)。
*
* Two surface variants share the same NavContent:
* - Sidebar (desktop): fixed rail, `hidden md:flex`.
@@ -76,22 +76,6 @@ function NavContent({ onNavigate }: { onNavigate: () => void }): React.ReactNode
{hasToken ? <SessionRail onNavigate={onNavigate} /> : null}
<div className="mt-auto flex flex-col gap-1">
<NavItem
icon="settings"
label="设置"
onClick={() => {
window.location.hash = "#/admin/system";
onNavigate();
}}
/>
<NavItem
icon="shield"
label="管理面板"
onClick={() => {
window.location.hash = "#/admin";
onNavigate();
}}
/>
<NavItem
icon={theme === "dark" ? "sun" : "moon"}
label={theme === "dark" ? "浅色" : "深色"}
-8
View File
@@ -82,14 +82,6 @@ export function TopBar({ onMenu }: { onMenu: () => void }): React.ReactNode {
{meta.label}
</Tag>
<button
onClick={() => { window.location.hash = "#/admin"; }}
aria-label="管理面板"
title="管理面板 /admin"
className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-[var(--mu-radius)] bg-[var(--mu-surface-4)] text-sm transition-all duration-200 ease-[var(--mu-spring)] hover:bg-[var(--mu-surface-5)] active:scale-95"
>
<Icon name="shield" size={18} />
</button>
{/* 双档 UI 档位(裁决 16.4.4):胶囊形态,尺寸对齐本栏其余 h-8 按钮。
窄屏(<sm)本栏已被头像/状态位占满,再塞 88px 会把角色名挤没甚至横向溢出,
故窄屏收起——移动端改由侧栏抽屉里的分段开关切档(Nav.tsx)。 */}