Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
### 变更

- 桌面端(`OCTOP_DESKTOP` / `FREEOS_DESKTOP`)首次打开不再经过验证启动密码、选择数据库、创建管理员三步:自动绑定本地 SQLite 并使用已有 guest / local-session。首屏只保留配置 LLM API Key,可「跳过,进入工作台」,之后仍可在设置里配模型。自托管服务端向导不变。
- 侧栏「设置」分组改名为「能力」/ Capabilities。原「控制」与「管理」子模块并入顶层「系统设置」/ System Settings(页内分节;工作台 / 远程桌面仍走全屏路由)。旧 `/admin/*`、`/acp`、`/agent-config` 地址会重定向。
- 用户可见吉祥物从章鱼换成 XYAI 白色机器人姿势包(欢迎 / 空态 / 探头 / 思考 / 打字 / 任务);桌面启动页与 openXYOS 首页使用同一角色,不再加载章鱼 WebM。
- 桌面更新通道只跟踪 `github.com/XYAIStudio/FreeOS/releases`。不再读取 PyPI `octop`、腾讯云 COS 或其它 Octop 镜像;当前已是最新 FreeOS `v0.0.1` 时不会误报更新。
- 默认主题与残留 Octop `rose` 存储一次性迁移为 XYAI 蓝 `#0033FF`(之后仍可手动选玫瑰粉)。

### 修复

- 桌面 / 本地会话不再被 `setup_required` 短路:`GET /setup/status` 之后仍可调用 `POST /auth/local-session`,不会误跳进服务端密码向导。
- 组织页「启动边车」会拉起捆绑的 Node + openXYOS(Windows 用 `node.exe` / `cmd /c`,不再直接 Popen `.bat`),并在右侧预览区嵌入控制台(支持全屏)。openXYOS 在 FreeOS 桌面环境下关闭 `X-Frame-Options`,避免 iframe 空白。安装 / 桌面启动时宿主与 Wails 都会确保边车常开(需 `dist/index.html` 已打包)。
- Windows 打开时不再因 WebView2 `Navigate`/`SetURL` 在 Chromium 未就绪时触发 Go panic。主窗口等 WebView 点火后再跳转;`SetURL` 失败会重试并显示 FreeOS 提示,而不是原始堆栈。设置窗口延后创建,避免两个 WebView2 同时初始化同一用户目录。用户数据目录必须可写,并设置 `WEBVIEW2_USER_DATA_FOLDER`。
- 已安装的 FreeOS 不再继承残留的 `~/.octop` 作为桌面家目录。无 `FREEOS_STAMP` 的 `~/.octop/portable` 会被丢弃;健康检查要求 `product=freeos`,避免连上旧 Octop 进程后出现红标登录墙。桌面端 `?desktop=1` 会记住本地会话并持续重试,不再落到登录页。
- Windows NSIS 安装完成后双击桌面 / 开始菜单快捷方式(或 `FreeOS.exe`)能打开窗口:快捷方式工作目录固定为 `$INSTDIR`,WebView2 用户数据写到 `%LOCALAPPDATA%\FreeOS\WebView2`(不再落到 Program Files),结束页用未提权 token 启动以免把 `~/.freeos` 标成 High integrity,并忽略非 `FreeOS.exe` 的残留 `desktop.pid`。
Expand Down
8 changes: 4 additions & 4 deletions dashboard/src/layouts/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ import { typeSize } from "../utils/mobileTypeScale";
import { DESKTOP_DRAG_REGION_CLASS } from "../utils/desktopChrome";

const NAV_GROUPS_STORAGE_KEY = "octop:sidebar-nav-groups";
/** Minimal settings pane: skip the "设置" group header (duplicates the pane title). */
const MINIMAL_SETTINGS_HIDDEN_HEADERS = new Set(["nav.settings"]);
/** Minimal settings pane: skip the Capabilities group header (duplicates the pane title). */
const MINIMAL_SETTINGS_HIDDEN_HEADERS = new Set(["nav.capabilities"]);

function loadCollapsedGroups(): Set<string> {
try {
Expand Down Expand Up @@ -190,7 +190,7 @@ function NavItemButton({
}}
>
{t(item.labelKey)}
{item.key === "admin-advanced" && role === "admin" && hasUpdate ? (
{item.key === "system-settings" && role === "admin" && hasUpdate ? (
<span className={styles.navUpdateBadge}>
{t("nav.newVersionBadge", "有新版本")}
</span>
Expand Down Expand Up @@ -254,7 +254,7 @@ function NavList({
isMobile?: boolean;
isGroupCollapsed: (groupKey: string) => boolean;
toggleGroup: (groupKey: string) => void;
/** all = classic; primary = top flat entries; grouped = settings/control/admin */
/** all = classic; primary = top flat entries; grouped = capabilities */
sectionFilter?: "all" | "primary" | "grouped";
hideGroupHeaderKeys?: ReadonlySet<string>;
}) {
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/layouts/SidebarCollapsedIconNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function SidebarCollapsedIconNav({
{items.map((item) => {
const active = selectedKey === item.key;
const showUpdateBadge =
item.key === "admin-advanced" && role === "admin" && hasUpdate;
item.key === "system-settings" && role === "admin" && hasUpdate;
return (
<Tooltip
key={item.key}
Expand Down
36 changes: 36 additions & 0 deletions dashboard/src/layouts/sidebarNav.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ describe("sidebarNav", () => {
}
expect(isGroupedNavKey("chat")).toBe(false);
expect(isGroupedNavKey("experts")).toBe(false);
expect(isGroupedNavKey("system-settings")).toBe(false);
expect(isGroupedNavKey("workbench")).toBe(false);
});

it("places grouped keys only under sections with groupKey", () => {
Expand All @@ -42,4 +44,38 @@ describe("sidebarNav", () => {
expect(isGroupedNavKey(key)).toBe(false);
}
});

it("renames settings to capabilities and folds control/admin into system-settings", () => {
const sections = buildNavSections(adminUser, { mobileEnabled: true });
expect(sections.map((s) => s.groupKey)).toEqual([
undefined,
"nav.capabilities",
]);
const primary = sections[0].items.map((i) => i.key);
expect(primary).toContain("system-settings");
expect(primary).not.toContain("workbench");
expect(primary).not.toContain("admin-users");
const grouped = sections[1].items.map((i) => i.key);
expect(grouped).toEqual([
"personalization",
"channels",
"connectors",
"skill-packages",
"knowledge-bases",
]);
});

it("hides system-settings when the user has no control or admin modules", () => {
const guest = {
id: 2,
username: "guest",
role: "user",
permissions: [],
} as OctopUser;
const sections = buildNavSections(guest);
const keys = sections.flatMap((s) => s.items.map((i) => i.key));
expect(keys).not.toContain("system-settings");
expect(keys).not.toContain("workbench");
expect(keys).toContain("personalization");
});
});
124 changes: 16 additions & 108 deletions dashboard/src/layouts/sidebarNav.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
import type { ReactNode } from "react";
import {
Monitor,
MessageSquareText,
Timer,
SlidersHorizontal,
Waypoints,
Link2,
Database,
Cpu,
Users as UsersIcon,
Activity,
Share2,
Sparkles,
Puzzle,
Package,
HardDrive,
GraduationCap,
Shield,
PanelsTopLeft,
Building2,
} from "lucide-react";
import type { OctopUser } from "../api/modules/auth";
import { navAllowed, userCan } from "../utils/permissions";
import { canSeeSystemSettings } from "../pages/SystemSettings/tabs";
import { navAllowed } from "../utils/permissions";

export const EXPANDED_WIDTH = 220;
export const COLLAPSED_WIDTH = 56;
Expand All @@ -44,7 +37,7 @@ export interface NavSection {
}

/**
* Catalog of nav item keys that live under settings / control / admin groups.
* Catalog of nav item keys that live under the Capabilities group.
* Permission-independent — used for pane/route helpers; visibility still
* comes from {@link buildNavSections}.
*/
Expand All @@ -54,16 +47,6 @@ export const SIDEBAR_GROUPED_NAV_KEYS = [
"connectors",
"skill-packages",
"knowledge-bases",
"workbench",
"remote-desktop",
"acp",
"admin-users",
"models",
"admin-storage",
"admin-plugins",
"admin-security",
"admin-advanced",
"agent-config",
] as const;

const GROUPED_NAV_KEY_SET = new Set<string>(SIDEBAR_GROUPED_NAV_KEYS);
Expand Down Expand Up @@ -109,6 +92,18 @@ export function buildNavSections(
icon: <Activity size={iconSize} strokeWidth={iconStroke} />,
labelKey: "nav.tokenUsage",
},
...(canSeeSystemSettings(user, { mobileEnabled: opts?.mobileEnabled })
? [
{
key: "system-settings",
path: "/system-settings",
icon: (
<SlidersHorizontal size={iconSize} strokeWidth={iconStroke} />
),
labelKey: "nav.systemSettings",
} satisfies NavItem,
]
: []),
],
},
];
Expand Down Expand Up @@ -154,94 +149,7 @@ export function buildNavSections(
});
}
if (settingsItems.length > 0) {
sections.push({ groupKey: "nav.settings", items: settingsItems });
}

const controlItems: NavItem[] = [];
if (navAllowed(user, "workbench")) {
controlItems.push({
key: "workbench",
path: "/workbench",
icon: <PanelsTopLeft size={iconSize} strokeWidth={iconStroke} />,
labelKey: "nav.workbench",
});
}
// Server desktop + phone share one nav entry; phone tab also needs host capability.
if (
userCan(user, "desktop") ||
(opts?.mobileEnabled && userCan(user, "mobile"))
) {
controlItems.push({
key: "remote-desktop",
path: "/remote-desktop",
icon: <Monitor size={iconSize} strokeWidth={iconStroke} />,
labelKey: "nav.remoteDesktop",
});
}
// ACP: no module key this round — admin role only.
if (navAllowed(user, "acp")) {
controlItems.push({
key: "acp",
path: "/acp",
icon: <Share2 size={iconSize} strokeWidth={iconStroke} />,
labelKey: "nav.acp",
});
}
if (controlItems.length > 0) {
sections.push({ groupKey: "nav.control", items: controlItems });
}

const adminItems: NavItem[] = [];
if (navAllowed(user, "admin-users")) {
adminItems.push({
key: "admin-users",
path: "/admin/users",
icon: <UsersIcon size={iconSize} strokeWidth={iconStroke} />,
labelKey: "nav.adminUsers",
});
}
if (navAllowed(user, "models")) {
adminItems.push({
key: "models",
path: "/admin/models",
icon: <Cpu size={iconSize} strokeWidth={iconStroke} />,
labelKey: "nav.models",
});
}
if (navAllowed(user, "admin-storage")) {
adminItems.push({
key: "admin-storage",
path: "/admin/backend",
icon: <HardDrive size={iconSize} strokeWidth={iconStroke} />,
labelKey: "nav.adminStorage",
});
}
if (navAllowed(user, "admin-plugins")) {
adminItems.push({
key: "admin-plugins",
path: "/admin/plugins",
icon: <Puzzle size={iconSize} strokeWidth={iconStroke} />,
labelKey: "nav.adminPlugins",
});
}
if (navAllowed(user, "admin-security")) {
adminItems.push({
key: "admin-security",
path: "/admin/security",
icon: <Shield size={iconSize} strokeWidth={iconStroke} />,
labelKey: "nav.security",
});
}
if (navAllowed(user, "admin-advanced")) {
adminItems.push({
key: "admin-advanced",
path: "/admin/advanced",
icon: <SlidersHorizontal size={iconSize} strokeWidth={iconStroke} />,
labelKey: "nav.adminAdvanced",
});
}
if (adminItems.length > 0) {
sections.push({ groupKey: "nav.admin", items: adminItems });
sections.push({ groupKey: "nav.capabilities", items: settingsItems });
}
return sections;
}
12 changes: 11 additions & 1 deletion dashboard/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,15 @@
"saveFailed": "Could not update organization module",
"actionFailed": "Action failed",
"enabled": "Organization module enabled",
"disabled": "Organization module disabled"
"disabled": "Organization module disabled",
"previewTitle": "openXYOS preview",
"previewOffline": "Sidecar is offline. Start it to preview the organization console here.",
"previewLoading": "Starting openXYOS…",
"fullscreen": "Fullscreen",
"exitFullscreen": "Exit fullscreen"
},
"systemSettings": {
"subtitle": "Workbench, remote desktop, and host administration in one place."
},
"desktopChrome": {
"group": "Window controls",
Expand Down Expand Up @@ -263,6 +271,8 @@
"skills": "Skills",
"agentConfig": "Configuration",
"settings": "Settings",
"capabilities": "Capabilities",
"systemSettings": "System Settings",
"voice": "Voice",
"observability": "Observability",
"https": "HTTPS",
Expand Down
12 changes: 11 additions & 1 deletion dashboard/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,15 @@
"saveFailed": "无法更新组织模块",
"actionFailed": "操作失败",
"enabled": "组织模块已启用",
"disabled": "组织模块已关闭"
"disabled": "组织模块已关闭",
"previewTitle": "openXYOS 预览",
"previewOffline": "边车未运行。启动后可在此预览组织控制台。",
"previewLoading": "正在启动 openXYOS…",
"fullscreen": "全屏",
"exitFullscreen": "退出全屏"
},
"systemSettings": {
"subtitle": "工作台、远程桌面与主机管理集中在这里。"
},
"desktopChrome": {
"group": "窗口控制",
Expand Down Expand Up @@ -263,6 +271,8 @@
"skills": "技能",
"agentConfig": "运行配置",
"settings": "设置",
"capabilities": "能力",
"systemSettings": "系统设置",
"voice": "语音",
"observability": "可观测",
"https": "HTTPS",
Expand Down
Loading
Loading