Files
codex-app-server/cloud/console-react/src/App.tsx
T
host e90c885290 console: GitHub 风格(Primer)
保持一页式控制台排版与全部功能、API 不变,只换视觉:
深色顶栏 #24292f、Primer 浅色配色(边框 #d0d7de、链接蓝
#0969da、绿主按钮 #2da44e)、6px 圆角方框、系统字体与
等宽 ID/trace;任务列表改 issues 式(状态圆点 + 标题 +
灰色元信息);对话改评论时间线(白框 + 头部 + 正文,
竖线连接),灰/蓝气泡已移除;自动选项目与继续消息历史
不受影响。console 标记单测本地 53 项通过。
2026-10-29 10:13:30 +08:00

127 lines
4.9 KiB
TypeScript

import { ConsoleContext, useConsole } from "./context";
import { useConsoleStore } from "./hooks/useConsoleStore";
import { useAutoRefresh, useIntervalMs } from "./hooks/useAutoRefresh";
import DataCards from "./sections/DataCards";
import DispatchSection from "./sections/DispatchSection";
import TaskListSection from "./sections/TaskListSection";
import ConversationSection from "./sections/ConversationSection";
import TaskDetailPanel from "./sections/TaskDetailPanel";
import ApiKeySection from "./sections/ApiKeySection";
import AdminSection from "./sections/AdminSection";
import ProjectsSection from "./sections/ProjectsSection";
import MembersPanel from "./sections/MembersPanel";
import EnvSection from "./sections/EnvSection";
import EnvContextPanel from "./sections/EnvContextPanel";
import WorkersSection from "./sections/WorkersSection";
import HealthPanel from "./sections/HealthPanel";
import SkillsSection from "./sections/SkillsSection";
import SkillsToolsPanel from "./sections/SkillsToolsPanel";
import AutomationsSection from "./sections/AutomationsSection";
import TriageSection from "./sections/TriageSection";
// Layout only: ONE scrollable console page in GitHub Primer style —
// a dark header bar (name + real connection status + health + quota
// + refresh stamp + anchor nav as header links), a data-cards row,
// then every module as a bordered section in order. No icon-rail
// column, no left list column, no right panel column, no view
// switching. Detail/context panels sit under their own sections
// below (detail under 对话, members under 项目, and so on).
const NAV: Array<[string, string]> = [
["#sec-dispatch", "派发"], ["#sec-tasks", "任务"], ["#sec-conv", "对话"],
["#sec-projects", "项目"], ["#sec-env", "环境"], ["#sec-workers", "Workers"],
["#sec-skills", "技能"], ["#sec-automations", "自动化"], ["#sec-triage", "分诊"],
["#sec-admin", "管理区"], ["#sec-key", "API Key"],
];
function TopBar() {
return (
<header className="dash-topbar">
<div className="dash-topbar-row">
<span className="dash-brand">Codex 命令台</span>
<TopStatus />
<span className="muted dash-hide-sm"><TopHealth /></span>
<span className="muted dash-hide-sm"><TopQuota /></span>
<span className="muted dash-stamp"><TopStamp /></span>
</div>
<nav className="dash-nav" aria-label="页面导航">
{NAV.map(([href, label]) => <a key={href} href={href}>{label}</a>)}
</nav>
</header>
);
}
// Tiny readers so the top bar re-renders from the store.
function TopStatus() {
const ctx = useConsole();
return <span className={ctx.keySaved ? "dash-status ok" : "dash-status off"}>{ctx.keySaved ? "● 已连接" : "○ 未连接"}</span>;
}
function TopHealth() {
return <>{useConsole().healthText}</>;
}
function TopQuota() {
return <>{useConsole().quotaText}</>;
}
function TopStamp() {
return <>自动刷新 · 每 10 秒 · 已刷新 {useConsole().refreshStamp}</>;
}
export default function App() {
const store = useConsoleStore();
useAutoRefresh((selectFocused) => store.refreshAll(selectFocused), 10000);
useIntervalMs(() => store.refreshSlow(), 60000);
const scrollToDispatch = () => {
document.getElementById("sec-dispatch")?.scrollIntoView({ behavior: "smooth" });
};
return (
<ConsoleContext.Provider value={store}>
<TopBar />
<main className="dash-page">
<DataCards />
<section id="sec-dispatch" className="dash-section">
<DispatchSection />
</section>
<section id="sec-tasks" className="dash-section card">
<h2>任务列表</h2>
<TaskListSection onNew={scrollToDispatch} />
</section>
<section id="sec-conv" className="dash-section">
<div className="card">
<h2>对话</h2>
<ConversationSection />
</div>
<TaskDetailPanel />
</section>
<section id="sec-projects" className="dash-section">
<ProjectsSection />
<MembersPanel />
</section>
<section id="sec-env" className="dash-section">
<EnvSection />
<EnvContextPanel />
</section>
<section id="sec-workers" className="dash-section">
<WorkersSection />
<HealthPanel />
</section>
<section id="sec-skills" className="dash-section">
<SkillsSection />
<SkillsToolsPanel />
</section>
<section id="sec-automations" className="dash-section">
<AutomationsSection />
</section>
<section id="sec-triage" className="dash-section">
<TriageSection />
</section>
<section id="sec-admin" className="dash-section">
<AdminSection />
</section>
<section id="sec-key" className="dash-section">
<ApiKeySection />
</section>
</main>
</ConsoleContext.Provider>
);
}