桌面 GUI 外链修复 + 主题顺序调整(含结构扁平化进行中的工作区基线)

- 集成 tauri-plugin-opener:Cargo/lib.rs/capabilities/npm 四处接线,新增 src/openExternal.ts(桌面走 opener,浏览器回退 window.open,相对路径绝对化)
- 关于页 4 个链接、活动栏官网菜单、代理错误横幅 2 处健康检查链接全部改走 openExternal,桌面端可正常跳转
- 设置→外观 主题顺序调整为 深色/浅色/跟随系统
- release 二进制重编并验证(浏览器实测关于页链接可开文档页)
- 附带工作区中未提交的扁平化重构现状(另一会话进行中)
- homepage 落地页与文档终检通过(8787 / 与 /docs 双 200)
This commit is contained in:
logan committed 2026-10-16 03:03:36 +08:00
1 parent 6452026fd6
commit 2bb4ef7a95
299 files changed
+6059 -3322

No files matched your search

+85
View File
@@ -0,0 +1,85 @@
import { MockView } from "./features/mock/MockView";
import { DocsView } from "./features/docs/DocsView";
import { useWorkspaceLifecycle } from "./features/workspace/useWorkspaceLifecycle";
/**
* OpsxAPI 工作台入口:组装顶栏 / 侧栏 / 标签页 / 编辑器 / 对话框。
*/
import { findNode } from "./core/index";
import { useWorkspace } from "./workspaceStore";
import { ActivityRail } from "./components/ActivityRail";
import { Sidebar } from "./components/Sidebar";
import { TestingView } from "./features/testing/TestingView";
import { TabBar } from "./components/TabBar";
import { TopBar } from "./components/TopBar";
import { GraphqlEditor } from "./components/editors/GraphqlEditor";
import { HttpEditor } from "./components/editors/HttpEditor";
import { MqttEditor } from "./components/editors/MqttEditor";
import { SocketIoEditor } from "./components/editors/SocketIoEditor";
import { SseEditor } from "./components/editors/SseEditor";
import { WebsocketEditor } from "./components/editors/WebsocketEditor";
import { WorkspaceDialogs } from "./features/workspace/WorkspaceDialogs";
import { EmptyState } from "./features/workspace/EmptyState";
export function OpsxWorkspace() {
useWorkspaceLifecycle();
const inited = useWorkspace((s) => s.collections.length > 0 || s.environments.length > 0);
const collections = useWorkspace((s) => s.collections);
const activeTabId = useWorkspace((s) => s.activeTabId);
const toast = useWorkspace((s) => s.toast);
const clearToast = useWorkspace((s) => s.clearToast);
const view = useWorkspace((s) => s.view);
const activeRef = activeTabId ? findNode(collections, activeTabId) : null;
const activeNode = activeRef?.node;
return (
<div className="flex h-screen flex-col overflow-hidden">
<TopBar />
<div className="flex min-h-0 min-w-0 flex-1">
<ActivityRail />
{view === "docs" ? <DocsView /> : view === "mock" ? <MockView /> : view === "testing" ? (
<div className="flex min-h-0 min-w-0 flex-1">
<TestingView />
</div>
) : (
<div className="flex min-h-0 min-w-0 flex-1">
<Sidebar />
<main className="flex min-w-0 flex-1 flex-col">
<TabBar />
{inited && activeNode === undefined && (
<EmptyState />
)}
{activeNode && activeNode.type === "request" && (
<>
{activeNode.kind === "http" && <HttpEditor node={activeNode} />}
{activeNode.kind === "graphql" && <GraphqlEditor node={activeNode} />}
{activeNode.kind === "websocket" && <WebsocketEditor node={activeNode} />}
{activeNode.kind === "sse" && <SseEditor node={activeNode} />}
{activeNode.kind === "socketio" && <SocketIoEditor node={activeNode} />}
{activeNode.kind === "mqtt" && <MqttEditor node={activeNode} />}
</>
)}
{activeNode && activeNode.type === "folder" && (
<EmptyState />
)}
</main>
</div>
)}
</div>
<WorkspaceDialogs />
{toast && (
<div
className="ops-toast"
role="status"
data-tone={toast.tone}
onClick={() => clearToast()}
>
{toast.message}
</div>
)}
</div>
);
}