dev-manager-tauri/src/App.tsx
lanrtop bf697b5e28 feat(ui): 功能区重构阶段二——洞察页 + 全局/项目层级归位(N3/N4/N5)
N3 洞察页三 tab(飞轮/健康中心/全局治理):
   - FlywheelPanel(版本队列/阻塞/停转归档/Git质量/梦核)整体迁出 BlueprintModal
     ——跨项目内容不再寄生单项目弹窗,BlueprintModal 减重 414 行
   - CONVENTIONS 规则来源 + 应用梦核建议迁至全局治理 tab(影响所有项目的操作归全局层)
   - BlueprintModal 侧板只留单项目内容(模块详情/余票/可派发/项目治理)
N4 Gitea 层级归位:实例管理(全局配置)拆为 GiteaInstancesSection 挂设置页;
   项目绑定+webhook 留治理面板,无实例时提示去设置页添加;共用 queryKey 缓存
N5 仓库注册表并入 项目→管理→仓库 tab(RegistryTab 复用),Sidebar 底部入口
   与弹窗死壳移除;总览页更名对齐"跨项目行动项"定位

至此 ui-restructure N1-N5 全部完成:三条公理(名实一致/层级对齐/频率分层)落地。
零后端变更,typecheck 全绿。
2026-07-02 14:51:43 +09:00

82 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect } from "react";
import { OverviewPage } from "./components/overview/OverviewPage";
import { Dashboard } from "./components/dashboard/Dashboard";
import { ProjectModal } from "./components/dashboard/ProjectModal";
import { ResourcesPage } from "./components/resources/ResourcesPage";
import { ToolsPage } from "./components/tools/ToolsPage";
import { SettingsPage } from "./components/settings/SettingsPage";
import { InsightPage } from "./components/insight/InsightPage";
import { Sidebar, type Page } from "./components/layout/Sidebar";
import { Toast } from "./components/ui/Toast";
import { getStartupAlerts, type StartupAlert } from "./lib/commands";
import { useUIStore } from "./store/ui";
import { check as checkUpdate } from "@tauri-apps/plugin-updater";
export default function App() {
const [page, setPage] = useState<Page>("overview");
const [alerts, setAlerts] = useState<StartupAlert[]>([]);
const [alertsDismissed, setAlertsDismissed] = useState(false);
const showToast = useUIStore((s) => s.showToast);
// 启动时静默检查更新
useEffect(() => {
checkUpdate()
.then((update) => {
if (update?.available) {
showToast(`🆕 发现新版本 v${update.version},前往「设置」页更新`);
}
})
.catch(() => {}); // 静默失败,不打扰用户
}, []);
// 启动健康扫描结果(延迟 2s 等后端扫描完成)
useEffect(() => {
const timer = setTimeout(() => {
getStartupAlerts()
.then((list) => { if (list.length > 0) setAlerts(list); })
.catch(() => {});
}, 2000);
return () => clearTimeout(timer);
}, []);
return (
<div className="h-screen flex overflow-hidden">
<Sidebar
page={page}
onPageChange={setPage}
/>
<main className="flex-1 overflow-auto bg-gray-50 flex flex-col min-h-0">
{alerts.length > 0 && !alertsDismissed && (
<div className="shrink-0 bg-amber-50 border-b border-amber-200 px-6 py-2.5 flex items-start gap-3">
<span className="text-amber-500 shrink-0 mt-0.5"></span>
<div className="flex-1 min-w-0">
<span className="text-xs font-semibold text-amber-800"></span>
<span className="text-xs text-amber-700 ml-1">
{alerts.slice(0, 3).map((a) => `${a.project_name}${a.detail}`).join("、")}
{alerts.length > 3 && `,等 ${alerts.length - 3} 个项目`}
</span>
</div>
<button
onClick={() => setAlertsDismissed(true)}
className="shrink-0 text-amber-400 hover:text-amber-600 text-sm leading-none"
aria-label="关闭"
>×</button>
</div>
)}
<div className="flex-1 overflow-auto min-h-0">
{page === "overview" && <OverviewPage />}
{page === "dashboard" && <Dashboard />}
{page === "resources" && <ResourcesPage />}
{page === "insight" && <InsightPage />}
{page === "tools" && <ToolsPage />}
{page === "settings" && <SettingsPage />}
</div>
</main>
<ProjectModal />
<Toast />
</div>
);
}