diff --git a/CHANGELOG.md b/CHANGELOG.md
index 677e7b69..afd5a964 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -31,6 +31,7 @@
### 变更
+- 组织页顶部蓝色状态栏增加「下载最新源码」主按钮:点击后先打开系统文件夹选择器,再下载最新 openXYOS 主分支源码。不必先打开「组织OS管理」。成功提示保存路径;管理抽屉仍保留同一操作作为次要入口。
- 对话与工作区共用一份列表:侧栏「对话」进入工作区「对话」标签;点开一条才进入聊天画布。工作区侧栏默认打开「项目」标签。
- 用户可见用词对齐:员工 = 已入编部门;同事 = 同一组织里一起聊的人;专家 / 智能助手 = 尚未入编的帮手。个性化「子智能体」改为「专项助手」。群聊选择「同事或智能助手」。
- 桌面未注册的 local guest 也能打开「模型」和「知识库」(第一台电脑免登录)。
diff --git a/dashboard/src/layouts/sidebarNav.test.ts b/dashboard/src/layouts/sidebarNav.test.ts
index cb66fe75..fade9f9e 100644
--- a/dashboard/src/layouts/sidebarNav.test.ts
+++ b/dashboard/src/layouts/sidebarNav.test.ts
@@ -81,8 +81,14 @@ describe("sidebarNav", () => {
expect(en.nav.organization).toBe("Organization");
expect(zh.organization.enableModule).toBe("启用组织模块");
expect(zh.organization.manageOs).toBe("组织OS管理");
+ expect(zh.organization.downloadSourceBar).toBe("下载最新源码");
+ expect(zh.organization.downloadSource).toBe("下载最新 openXYOS 源码");
expect(en.organization.enableModule).toBe("Enable organization module");
expect(en.organization.manageOs).toBe("Organization OS");
+ expect(en.organization.downloadSourceBar).toBe("Download latest source");
+ expect(en.organization.downloadSource).toBe(
+ "Download latest openXYOS source",
+ );
expect(zh.chat.modelPickerManage).toBe("模型管理");
expect(en.chat.modelPickerManage).toBe("Model management");
});
diff --git a/dashboard/src/locales/en.json b/dashboard/src/locales/en.json
index e6e62758..5d49c14f 100644
--- a/dashboard/src/locales/en.json
+++ b/dashboard/src/locales/en.json
@@ -109,6 +109,7 @@
"fullscreen": "Fullscreen",
"exitFullscreen": "Exit fullscreen",
"downloadSource": "Download latest openXYOS source",
+ "downloadSourceBar": "Download latest source",
"downloadSourceHint": "Pick any folder on any drive with the system dialog. FreeOS then downloads the latest openXYOS main-branch source from GitHub.",
"downloadSourceDest": "Save to folder",
"downloadSourceDone": "Downloaded to {{path}}",
diff --git a/dashboard/src/locales/zh.json b/dashboard/src/locales/zh.json
index 7d22ec24..f98edf4b 100644
--- a/dashboard/src/locales/zh.json
+++ b/dashboard/src/locales/zh.json
@@ -109,6 +109,7 @@
"fullscreen": "全屏",
"exitFullscreen": "退出全屏",
"downloadSource": "下载最新 openXYOS 源码",
+ "downloadSourceBar": "下载最新源码",
"downloadSourceHint": "用系统文件夹选择器任选盘符与目录,FreeOS 会从 GitHub 下载最新 openXYOS 主分支源码。",
"downloadSourceDest": "保存到文件夹",
"downloadSourceDone": "已下载到 {{path}}",
diff --git a/dashboard/src/pages/Organization/Organization.module.less b/dashboard/src/pages/Organization/Organization.module.less
index 658dac7b..c291b91e 100644
--- a/dashboard/src/pages/Organization/Organization.module.less
+++ b/dashboard/src/pages/Organization/Organization.module.less
@@ -71,6 +71,11 @@
background: #fff;
}
+.statusActions :global(.ant-btn-primary) {
+ font-weight: 650;
+ box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.35);
+}
+
.statusActions :global(.ant-btn:hover) {
color: #0033ff !important;
border-color: #fff !important;
diff --git a/dashboard/src/pages/Organization/index.test.tsx b/dashboard/src/pages/Organization/index.test.tsx
index a5a4c02e..904094ca 100644
--- a/dashboard/src/pages/Organization/index.test.tsx
+++ b/dashboard/src/pages/Organization/index.test.tsx
@@ -1,7 +1,8 @@
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
-import { describe, expect, it, vi } from "vitest";
+import { describe, expect, it, vi, beforeEach } from "vitest";
import OrganizationPage from "./index";
import { orgModuleApi, type OrgOverview } from "../../api/modules/orgModule";
+import { message } from "../../utils/antdMessage";
const overview: OrgOverview = {
enabled: true,
@@ -65,7 +66,28 @@ vi.mock("../../hooks/useServerTimezone", () => ({
useServerTimezone: () => "UTC",
}));
+const pickDesktopFolder = vi.fn();
+const canPickDesktopFolder = vi.fn();
+
+vi.mock("../../utils/desktopFolder", () => ({
+ pickDesktopFolder: (...args: unknown[]) => pickDesktopFolder(...args),
+ canPickDesktopFolder: (...args: unknown[]) => canPickDesktopFolder(...args),
+}));
+
+vi.mock("../../utils/antdMessage", () => ({
+ message: { success: vi.fn(), error: vi.fn(), info: vi.fn() },
+}));
+
describe("OrganizationPage", () => {
+ beforeEach(() => {
+ canPickDesktopFolder.mockReturnValue(true);
+ pickDesktopFolder.mockReset();
+ vi.mocked(orgModuleApi.overview).mockResolvedValue(overview);
+ vi.mocked(orgModuleApi.downloadSource).mockReset();
+ vi.mocked(message.success).mockReset();
+ vi.mocked(message.error).mockReset();
+ });
+
it("defaults to the local embed and keeps extras behind the two status buttons", async () => {
render(