de3dc87920
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
* docs: add desktop project plan * feat(desktop): implement phase 1 tauri client * refactor(client): unify web and desktop release workflow * feat(desktop): implement phase 2 native capabilities * 完善桌面端交互体验与发布检查 * 完善桌面端界面、发布检查与邮箱域名同步 * fix(deploy): 修复数据库初始化复用旧镜像 * fix(deploy): 增加部署更新实时进度 * fix(auth): 支持无邮箱后缀时手动输入 * feat(desktop): 稳定桌面端界面与文件操作反馈 - 重构 DesktopPreferences 为分栏式设置面板,整合连接、外观、通知、更新与诊断信息分区,并补充过渡动效与暗色主题样式 - DesktopLayout 侧边栏导航分组支持展开折叠,调整管理/项目区块顺序并统一图标与标题 - 新增 fileTaskFeedback 工具,统一 pickFiles/saveFile/openFile 的成功/取消提示,替换审计导出、权限日志、附件、文档、线程、项目配置等处的直接调用 - desktopUpdateManager 暴露更新状态快照与状态变更监听,区分检查中、安装中、已推迟、失败等状态 - DesktopServerSettings 增加连接诊断信息(检查时间、健康地址、耗时、HTTP 状态) - unified-page.css 与 ProjectMilestones 引入 CSS 变量以适配暗色主题 - WebLayout 将服务器设置入口改为打开系统偏好面板,管理菜单中邮件服务归入系统设置分组 - ProfileSettings 移除已迁入偏好面板的桌面端专属区块 - 补充 Layout.desktop 布局与偏好面板契约测试 * feat(desktop): 支持桌面端三十天免登录 * 完善桌面端发布稳定化门禁 * 完善桌面端端到端回归收口 * 补齐桌面端附件文件流回归 * 完善桌面端回归与安全边界复审 * 完善桌面体验与系统通知收口 * feat(desktop): 收口桌面工作台视觉与活动反馈 * 优化桌面端界面布局 * style: 优化个人中心和偏好设置弹窗样式,重构工作入口为精致分屏布局并移除首字徽标 * 功能(桌面端):增加在线辅助本地缓存 * 优化桌面端标签导航与后台交互 * ci: 新增 Windows 桌面端内测构建 * fix: 修复桌面检查脚本的 Windows 路径判断 * test: 兼容 Windows 换行的桌面布局断言 * test: 兼容 Windows 换行的路由断言 * ci: 修复 Windows 内测构建配置传参 * ci: 避免 Windows 安装器构建交互等待 * 修复桌面端界面显示与稳定性问题 * feat(网页端): 完善登录后工作台与项目管理体验 * docs(desktop): 精简桌面端约束入口 * feat(admin): 完善审计访问上下文与后台布局 * fix(git): 跟踪原生图标资源 * fix(web): 修正工作台端侧标识 * feat(监控): 完善系统监控、登录状态与访问审计能力 * 修复(权限管理):统一 PM 系统导航与权限校验 * feat(工作台): 优化入口布局与连接安全状态 * feat(桌面与监控): 完善工作台导航和登录活动定位 - 优化桌面标签、上下文标题、前进后退、导航栏隐藏和原生菜单体验 - 补充登录会话 IP 采集、地理位置回退、管理端展示及数据库迁移 - 更新桌面发布检查、运维文档和前后端测试覆盖 * 功能(文档与桌面):完善文件预览下载与客户端构建基线 - 保存文档版本原始文件名,规范下载响应并持久化上传目录\n- 增加 PDF.js 预览、桌面保存打开流程及统一错误反馈\n- 统一 Node.js 22.13 构建基线并收紧临时文件权限门禁\n- 补充迁移、单元测试、发布检查与运维文档 * 功能(文档预览):集成 ONLYOFFICE 安全只读预览与工作台体验 新增 ONLYOFFICE 配置签名、内部内容接口、容器编排与反向代理。 打通网页端和桌面端独立预览工作区,完善文档入口、布局及帮助体验。 补充桌面安全发布门禁、开发脚本、使用文档和前后端测试。 * feat(collaboration): 完善在线文档协作与通知闭环 - 新增协作文件夹、文件、不可变修订、成员、会话、回调回执、编辑申请与分享链接数据模型。 - 补齐新建、导入、复制、下载、回收站、恢复、成员授权、所有权转让及文件级权限接口。 - 接入 ONLYOFFICE 共同编辑、历史版本预览与恢复、修订另存副本、导出下载审计和幂等回调保存。 - 增加编辑权限申请、审批通知、项目提醒聚合、通知 Feed、已读处理及历史待办数据回填。 - 支持公开分享的查看或编辑模式、有效期、密码哈希、失败锁定、短时访问凭证与固定分享地址。 - 增加协作者导出、申请编辑、工作表结构保护和所有权管理策略,并纳入项目接口权限矩阵。 - 新增协作文件库、编辑工作区、公开分享页、下载与另存为对话框,以及导航、路由和权限入口。 - 统一网页端与桌面端通知布局,增加沉浸式工作区和浏览器、Tauri 双端全屏能力。 - 扩展运行时文件下载适配、Tauri 环境识别和原生全屏命令,继续保持业务代码运行时边界。 - 加固 ONLYOFFICE 消息桥的同源下载、签名地址隔离和保存为能力校验,并更新桌面发布检查。 - 增加连续数据库迁移、50MB 上传限制、OnlyOffice 中文文案与开发启动路由校验。 - 补充协作、通知、权限、路由、运行时、布局和 OnlyOffice 相关测试及模块说明文档。 * refactor(frontend): 按需加载页面并清理未使用代码 - 将业务页面路由统一改为动态导入,拆分首屏入口与各功能模块构建产物。 - 将网页端和桌面端布局改为异步组件,避免两套平台布局同时进入初始包。 - 新增 Element Plus 按需安装入口,并通过全局配置组件统一注入中文语言包。 - 提取 API 运行时钩子,在应用启动时注入项目清理、令牌续期和认证失效退出能力。 - 将权限监控面板及地图资源改为延迟加载,补充地图加载状态、失败提示和切换竞态保护。 - 删除已被现有工作流替代的项目成员、接口权限、中心绑定、培训表单及旧项目首页等页面。 - 清理废弃的快捷操作、项目选择、用户选择、FAQ 表单、风险占位组件和旧地图辅助模块。 - 移除未使用的 API 方法、类型、字典、状态机、展示工具、样式和项目详情编辑逻辑。 - 开启 TypeScript 未使用变量与参数检查,并同步收紧相关测试和组件暴露类型。 - 移除未使用的 updater、date-fns 和 Sass 前端依赖,更新锁文件并删除旧 CSS 清洗插件。 - 更新路由、Axios、ETMF、通知、权限监控和桌面布局测试以覆盖重构后的边界。 * fix(审计): 移除共享库审计与预览噪声 * 功能(提醒):统一项目提醒中心与桌面通知链路 增加通用提醒状态、数据库迁移和定时同步,覆盖风险时效、文件回执、项目里程碑、访视窗口与协作申请。 新增网页端和桌面端提醒中心、真实投递诊断与固定隐私通知正文,并补齐登录来源聚合、测试和说明文档。 * feat(deploy): 默认安装 ONLYOFFICE 标准组件 * build(release): 加固 v0.1.0 桌面发布链路 (#3)
114 lines
4.1 KiB
JavaScript
114 lines
4.1 KiB
JavaScript
import { execFileSync } from "node:child_process";
|
|
import { readFile } from "node:fs/promises";
|
|
import { resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const frontendDir = fileURLToPath(new URL("../", import.meta.url));
|
|
const rootDir = resolve(frontendDir, "..");
|
|
const packageInfo = JSON.parse(await readFile(resolve(frontendDir, "package.json"), "utf8"));
|
|
const failures = [];
|
|
|
|
const allowedChannels = new Set(["dev", "main", "release", "local"]);
|
|
const fullShaPattern = /^[0-9a-f]{40}$/i;
|
|
const semverTag = `v${packageInfo.version}`;
|
|
|
|
const env = process.env;
|
|
const channel = env.VITE_BUILD_CHANNEL || "local";
|
|
const commit = env.VITE_BUILD_COMMIT || "local";
|
|
const isCi = env.CI === "true" || env.GITHUB_ACTIONS === "true";
|
|
const isTagBuild = env.GITHUB_REF_TYPE === "tag";
|
|
const isReleaseBuild = env.RELEASE_BUILD === "true" || isTagBuild || channel === "release";
|
|
const requiresMacosSigning = env.REQUIRE_DESKTOP_SIGNING === "true";
|
|
const requiresWindowsSigning = env.REQUIRE_WINDOWS_SIGNING === "true";
|
|
|
|
const fail = (message) => failures.push(message);
|
|
const assert = (condition, message) => {
|
|
if (!condition) fail(message);
|
|
};
|
|
|
|
const requireEnv = (name) => {
|
|
assert(Boolean(env[name]), `${name} must be configured for signed desktop release builds.`);
|
|
};
|
|
|
|
const gitHead = () => {
|
|
try {
|
|
return execFileSync("git", ["rev-parse", "HEAD"], {
|
|
cwd: rootDir,
|
|
encoding: "utf8",
|
|
stdio: ["ignore", "pipe", "ignore"],
|
|
}).trim();
|
|
} catch {
|
|
return undefined;
|
|
}
|
|
};
|
|
|
|
assert(allowedChannels.has(channel), `VITE_BUILD_CHANNEL must be one of ${[...allowedChannels].join(", ")}.`);
|
|
|
|
if (isCi || isReleaseBuild) {
|
|
assert(channel !== "local", "CI and release builds must inject VITE_BUILD_CHANNEL.");
|
|
assert(fullShaPattern.test(commit), "CI and release builds must inject a full 40-character VITE_BUILD_COMMIT.");
|
|
}
|
|
|
|
if (env.GITHUB_SHA) {
|
|
assert(
|
|
commit === env.GITHUB_SHA || commit === "local",
|
|
"VITE_BUILD_COMMIT must match GITHUB_SHA when GitHub Actions provides a source commit.",
|
|
);
|
|
}
|
|
|
|
if (isReleaseBuild && fullShaPattern.test(commit)) {
|
|
const headSha = gitHead();
|
|
assert(Boolean(headSha), "Release builds must be able to resolve the current Git commit.");
|
|
if (headSha) {
|
|
assert(commit === headSha, "VITE_BUILD_COMMIT must match the current Git HEAD for release builds.");
|
|
}
|
|
}
|
|
|
|
if (isTagBuild) {
|
|
assert(env.GITHUB_REF_NAME === semverTag, `Release tag must be ${semverTag}; found ${env.GITHUB_REF_NAME || "<missing>"}.`);
|
|
assert(channel === "release", "Release tag builds must set VITE_BUILD_CHANNEL=release.");
|
|
}
|
|
|
|
assert(
|
|
!(requiresMacosSigning && requiresWindowsSigning),
|
|
"macOS and Windows signing requirements must be checked in their native jobs.",
|
|
);
|
|
|
|
if (requiresMacosSigning) {
|
|
assert(process.platform === "darwin", "Signed macOS desktop release builds must run on macOS.");
|
|
if (isCi) {
|
|
assert(isTagBuild, "Signed desktop release candidate builds in CI must run from a release tag.");
|
|
}
|
|
requireEnv("TAURI_SIGNING_PRIVATE_KEY");
|
|
requireEnv("TAURI_SIGNING_PRIVATE_KEY_PASSWORD");
|
|
requireEnv("APPLE_ID");
|
|
requireEnv("APPLE_PASSWORD");
|
|
requireEnv("APPLE_TEAM_ID");
|
|
assert(
|
|
Boolean(env.APPLE_CERTIFICATE || env.APPLE_SIGNING_IDENTITY),
|
|
"APPLE_CERTIFICATE or APPLE_SIGNING_IDENTITY must be configured for macOS signing.",
|
|
);
|
|
if (env.APPLE_CERTIFICATE) {
|
|
requireEnv("APPLE_CERTIFICATE_PASSWORD");
|
|
}
|
|
}
|
|
|
|
if (requiresWindowsSigning) {
|
|
assert(process.platform === "win32", "Signed Windows desktop release builds must run on Windows.");
|
|
if (isCi) {
|
|
assert(isTagBuild, "Signed Windows desktop release candidate builds in CI must run from a release tag.");
|
|
}
|
|
requireEnv("TAURI_SIGNING_PRIVATE_KEY");
|
|
requireEnv("TAURI_SIGNING_PRIVATE_KEY_PASSWORD");
|
|
requireEnv("WINDOWS_CERTIFICATE");
|
|
requireEnv("WINDOWS_CERTIFICATE_PASSWORD");
|
|
requireEnv("WINDOWS_TIMESTAMP_URL");
|
|
}
|
|
|
|
if (failures.length > 0) {
|
|
console.error(`Release build environment check failed:\n${failures.map((item) => ` - ${item}`).join("\n")}`);
|
|
process.exitCode = 1;
|
|
} else {
|
|
console.log("Release build environment check passed.");
|
|
}
|