From ae6ae99eebb90e39aa1c226e8bf9828ae6fef163 Mon Sep 17 00:00:00 2001 From: tianma-if Date: Wed, 30 Sep 2026 17:49:20 +0800 Subject: [PATCH] feat: integrate structured GitHub issue forms and prefilled feedback URLs --- .github/ISSUE_TEMPLATE/bug.yml | 79 +++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 1 + .github/ISSUE_TEMPLATE/deployment.yml | 67 ++++++++++++++++ .github/ISSUE_TEMPLATE/feature.yml | 52 ++++++++++++ apps/desktop/src/main/desktop-diagnostics.mjs | 32 ++++---- .../src/main/desktop-diagnostics.test.mjs | 10 ++- .../Features/Workspace/SettingsView.swift | 5 +- .../src/screens/WorkspaceSettingsView.tsx | 1 + packages/shared/src/github-feedback.test.mjs | 3 + packages/shared/src/github-feedback.ts | 17 +++- tests/github-feedback.test.ts | 3 + 11 files changed, 250 insertions(+), 20 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/deployment.yml create mode 100644 .github/ISSUE_TEMPLATE/feature.yml diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 00000000..a09745cb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,79 @@ +name: 问题反馈 +description: 功能表现和预期不一致,或出现报错。 +title: "[Bug] " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + 请填写下面的必填项。GitHub Issue 公开可见,不要附上密码、Token、实例地址或笔记正文。 + + 系统信息在「设置 → 系统信息」,点「复制信息」后粘贴。Linux 请另外写上发行版、桌面环境,以及 Wayland 或 X11。桌面端如果停在崩溃恢复页,请写上恢复页出现前正在做什么。 + - type: dropdown + id: client + attributes: + label: 出现问题的客户端 + description: Which client is affected? + multiple: true + options: + - Web + - macOS + - Windows + - Linux + - Android + - iOS + - Browser extension + validations: + required: true + - type: textarea + id: what-happened + attributes: + label: 发生了什么 + description: 实际看到的结果、报错原文。What did you see, including the exact error text? + placeholder: 例如:点击分享后按钮一直转圈,控制台出现 TypeError。 + validations: + required: true + - type: textarea + id: steps + attributes: + label: 怎样复现 + description: 按顺序写出操作。Steps to reproduce, in order. + placeholder: | + 1. + 2. + 3. + validations: + required: true + - type: textarea + id: expected + attributes: + label: 期望的结果 + description: 你认为这一步应该发生什么。What did you expect? + validations: + required: false + - type: textarea + id: system-info + attributes: + label: 系统信息 + description: 粘贴「设置 → 系统信息」里复制的内容。应用内反馈会自动填入。Paste the copied system information. + placeholder: | + - 客户端版本: v1.93.0 + - 系统: macOS + - 实例构建: v1.93.0 + validations: + required: true + - type: textarea + id: diagnostics + attributes: + label: 诊断信息 + description: 应用在崩溃或同步失败时会自动填入。手动提交时留空。Filled automatically for crash and sync reports. + validations: + required: false + - type: upload + id: screenshots + attributes: + label: 截图或录屏 + description: 有界面异常时附上。Add a screenshot or screen recording when the issue is visible. + validations: + required: false + accept: ".png,.jpg,.jpeg,.gif,.webp,.mp4,.mov,.webm" diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..3ba13e0c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/deployment.yml b/.github/ISSUE_TEMPLATE/deployment.yml new file mode 100644 index 00000000..b185aa45 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/deployment.yml @@ -0,0 +1,67 @@ +name: 部署与连接 +description: 自托管实例无法安装、更新或连接。 +title: "[Deploy] " +labels: ["question"] +body: + - type: markdown + attributes: + value: | + 先看仓库文档里的 Cloudflare 或 Docker 部署说明。仍然失败时再提交。 + + GitHub Issue 公开可见。不要附上密码、Token、实例地址或笔记正文。需要对照地址时,维护者会在评论里单独询问。 + - type: dropdown + id: deploy-method + attributes: + label: 部署方式 + description: How is this instance deployed? + multiple: false + options: + - Cloudflare 一键部署 + - Cloudflare 手动部署 + - Docker + - 官方 Demo + - 不确定 + validations: + required: true + - type: dropdown + id: client + attributes: + label: 出问题的客户端 + description: Which client cannot connect? 纯服务端问题时选你用来访问的那个端。 + multiple: true + options: + - Web + - macOS + - Windows + - Linux + - Android + - iOS + - Browser extension + validations: + required: true + - type: textarea + id: what-happened + attributes: + label: 发生了什么 + description: 实际看到的结果、报错原文。What did you see, including the exact error text? + placeholder: 例如:桌面端登录一直显示 network_unreachable,浏览器打开同一地址可以登录。 + validations: + required: true + - type: textarea + id: steps + attributes: + label: 已经试过什么 + description: 包括文档中的哪一步、命令输出,以及是否用浏览器对照过。What have you already tried? + validations: + required: true + - type: textarea + id: system-info + attributes: + label: 系统信息 + description: 能打开应用时,粘贴「设置 → 系统信息」里复制的内容。应用还打不开时,写上实例版本、数据库后端和部署平台。 + placeholder: | + - 实例构建: v1.93.0 + - 数据库后端: D1 + - 部署平台: Cloudflare + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 00000000..0756982c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,52 @@ +name: 功能建议 +description: 希望增加或调整一个能力。 +title: "[Feature] " +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + 请写清现在办不到什么,以及你希望怎么做。GitHub Issue 公开可见,不要附上密码、Token、实例地址或笔记正文。 + + 系统信息用来确认当前版本是否已经支持。在「设置 → 系统信息」点「复制信息」后粘贴。 + - type: dropdown + id: client + attributes: + label: 用在哪个端 + description: Which client should have this? + multiple: true + options: + - Web + - macOS + - Windows + - Linux + - Android + - iOS + - Browser extension + validations: + required: true + - type: textarea + id: what-happened + attributes: + label: 想要的能力 + description: 做成之后,你可以完成哪件现在做不到的事。What should become possible? + placeholder: 例如:在手机上把一篇笔记从 Markdown 切回富文本继续改。 + validations: + required: true + - type: textarea + id: steps + attributes: + label: 现在怎么做 + description: 你目前的做法,以及具体卡在哪一步。How do you handle this today, and where does it break down? + validations: + required: true + - type: textarea + id: system-info + attributes: + label: 系统信息 + description: 粘贴「设置 → 系统信息」里复制的内容。应用内反馈会自动填入。Paste the copied system information. + placeholder: | + - 客户端版本: v1.93.0 + - 系统: Android + validations: + required: true diff --git a/apps/desktop/src/main/desktop-diagnostics.mjs b/apps/desktop/src/main/desktop-diagnostics.mjs index 067b6130..9a4a943c 100644 --- a/apps/desktop/src/main/desktop-diagnostics.mjs +++ b/apps/desktop/src/main/desktop-diagnostics.mjs @@ -1,4 +1,9 @@ const GITHUB_NEW_ISSUE_URL = "https://github.com/tianma-if/edgeever/issues/new"; +const DESKTOP_CLIENT_BY_PLATFORM = { + darwin: "macOS", + win32: "Windows", + linux: "Linux", +}; // Keep the prefilled GitHub URL below common browser/server URL limits while // retaining the first useful frames from renderer stacks. const MAX_DIAGNOSTIC_TEXT_LENGTH = 1_200; @@ -45,21 +50,20 @@ export const buildDesktopDiagnosticIssueUrl = ({ diagnostic, systemInfo }) => { gpuFeatures: sanitizeDesktopDiagnosticText(systemInfo.gpuFeatures), }; const title = `[Crash] Desktop renderer failure (${safeSystemInfo.platform} ${safeSystemInfo.architecture})`; + const systemInfoText = Object.entries(safeSystemInfo) + .filter(([, value]) => value) + .map(([key, value]) => `- ${key}: ${value}`) + .join("\n"); + const client = DESKTOP_CLIENT_BY_PLATFORM[safeSystemInfo.platform] ?? ""; const makeUrl = (reportDiagnostic) => { - const body = [ - "## What happened", - "", - "", - "", - "## Automatically captured diagnostics", - "", - "```json", - JSON.stringify({ diagnostic: reportDiagnostic, systemInfo: safeSystemInfo }, null, 2), - "```", - "", - "> This report was generated locally and common URLs, credentials, and home-directory names were redacted. GitHub Issues are public; please review the report before submitting it and do not add private note content, passwords, tokens, or instance URLs.", - ].join("\n"); - return `${GITHUB_NEW_ISSUE_URL}?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`; + const params = new URLSearchParams({ + template: "bug.yml", + title, + "system-info": systemInfoText, + diagnostics: JSON.stringify({ diagnostic: reportDiagnostic, systemInfo: safeSystemInfo }, null, 2), + }); + if (client) params.set("client", client); + return `${GITHUB_NEW_ISSUE_URL}?${params.toString()}`; }; const fullUrl = makeUrl(normalized); diff --git a/apps/desktop/src/main/desktop-diagnostics.test.mjs b/apps/desktop/src/main/desktop-diagnostics.test.mjs index b7a7b273..caf3cbc2 100644 --- a/apps/desktop/src/main/desktop-diagnostics.test.mjs +++ b/apps/desktop/src/main/desktop-diagnostics.test.mjs @@ -52,10 +52,14 @@ describe("desktop crash diagnostics", () => { }); const url = new URL(issueUrl); expect(url.origin + url.pathname).toBe("https://github.com/tianma-if/edgeever/issues/new"); + expect(url.searchParams.get("template")).toBe("bug.yml"); + expect(url.searchParams.get("client")).toBe("macOS"); expect(url.searchParams.get("title")).toContain("darwin x64"); - expect(url.searchParams.get("body")).toContain('"appVersion": "1.31.0"'); - expect(url.searchParams.get("body")).toContain("Intel UHD Graphics 630"); - expect(url.searchParams.get("body")).not.toContain("private.example.com"); + expect(url.searchParams.get("system-info")).toContain("- appVersion: 1.31.0"); + expect(url.searchParams.get("diagnostics")).toContain('"appVersion": "1.31.0"'); + expect(url.searchParams.get("diagnostics")).toContain("Intel UHD Graphics 630"); + expect(url.searchParams.get("diagnostics")).not.toContain("private.example.com"); + expect(url.searchParams.get("system-info")).not.toContain("private.example.com"); expect(issueUrl.length).toBeLessThan(8_000); }); diff --git a/apps/ios/EdgeEver/Features/Workspace/SettingsView.swift b/apps/ios/EdgeEver/Features/Workspace/SettingsView.swift index 213c9b48..3b35d58b 100644 --- a/apps/ios/EdgeEver/Features/Workspace/SettingsView.swift +++ b/apps/ios/EdgeEver/Features/Workspace/SettingsView.swift @@ -784,6 +784,7 @@ struct SettingsView: View { let notice = english ? "The following information was generated by EdgeEver to help diagnose the issue." : "以下信息由 EdgeEver 自动生成,可帮助定位问题。" + let info = systemInfoText(includeLocalOnly: false) let body = """ ## \(heading) @@ -796,13 +797,15 @@ struct SettingsView: View { \(notice) ```text - \(systemInfoText(includeLocalOnly: false)) + \(info) ``` """ var components = URLComponents(string: "https://github.com/tianma-if/edgeever/issues/new") components?.queryItems = [ URLQueryItem(name: "title", value: english ? "[Feedback] " : "[反馈] "), URLQueryItem(name: "body", value: body), + URLQueryItem(name: "system-info", value: info), + URLQueryItem(name: "client", value: "iOS"), ] return components?.url } diff --git a/apps/mobile/src/screens/WorkspaceSettingsView.tsx b/apps/mobile/src/screens/WorkspaceSettingsView.tsx index c96f98bc..cd39f8c2 100644 --- a/apps/mobile/src/screens/WorkspaceSettingsView.tsx +++ b/apps/mobile/src/screens/WorkspaceSettingsView.tsx @@ -819,5 +819,6 @@ const buildMobileFeedbackUrl = ( ? "The following information was generated by EdgeEver to help diagnose the issue." : "以下信息由 EdgeEver 自动生成,可帮助定位问题。", titlePrefix: english ? "[Feedback] " : "[反馈] ", + client: "Android", }); }; diff --git a/packages/shared/src/github-feedback.test.mjs b/packages/shared/src/github-feedback.test.mjs index 9e8330e9..e53a4940 100644 --- a/packages/shared/src/github-feedback.test.mjs +++ b/packages/shared/src/github-feedback.test.mjs @@ -24,6 +24,9 @@ describe("GitHub feedback URL", () => { expect(body).toContain("## Diagnostics"); expect(body).toContain('"errorCode":"memo_not_found"'); expect(body).toContain("- Version: v1.46.0"); + expect(url.searchParams.get("system-info")).toContain("- Version: v1.46.0"); + expect(url.searchParams.get("template")).toBe("bug.yml"); + expect(url.searchParams.get("diagnostics")).toContain('"errorCode":"memo_not_found"'); expect(body.indexOf("## Diagnostics")).toBeLessThan(body.indexOf("## System information")); }); }); diff --git a/packages/shared/src/github-feedback.ts b/packages/shared/src/github-feedback.ts index b13a1310..c8815620 100644 --- a/packages/shared/src/github-feedback.ts +++ b/packages/shared/src/github-feedback.ts @@ -14,6 +14,7 @@ export const buildGitHubFeedbackUrl = ({ systemInfoHeading, systemInfoNotice, titlePrefix, + client, }: { contentHeading: string; contentPrompt: string; @@ -27,7 +28,9 @@ export const buildGitHubFeedbackUrl = ({ systemInfoHeading: string; systemInfoNotice: string; titlePrefix: string; + client?: string; }) => { + const systemInfoText = systemInfo.map((item) => `- ${item.label}: ${item.value}`).join("\n"); const body = [ `## ${contentHeading}`, "", @@ -46,9 +49,19 @@ export const buildGitHubFeedbackUrl = ({ `## ${systemInfoHeading}`, "", ``, - ...systemInfo.map((item) => `- ${item.label}: ${item.value}`), + systemInfoText, "", `> ${privacyNotice}`, ].join("\n"); - return `${GITHUB_NEW_ISSUE_URL}?title=${encodeURIComponent(titlePrefix)}&body=${encodeURIComponent(body)}`; + const params = new URLSearchParams({ + title: titlePrefix, + body, + "system-info": systemInfoText, + }); + if (diagnostics) { + params.set("template", "bug.yml"); + params.set("diagnostics", diagnostics.text); + } + if (client) params.set("client", client); + return `${GITHUB_NEW_ISSUE_URL}?${params.toString()}`; }; diff --git a/tests/github-feedback.test.ts b/tests/github-feedback.test.ts index 9c2a0c3a..86542227 100644 --- a/tests/github-feedback.test.ts +++ b/tests/github-feedback.test.ts @@ -24,5 +24,8 @@ describe("buildGitHubFeedbackUrl", () => { expect(url.searchParams.get("body")).toContain("- 版本号: v0.5.0"); expect(url.searchParams.get("body")).toContain("- 系统: Android 16"); expect(url.searchParams.get("body")).toContain("> 请勿提交隐私信息"); + expect(url.searchParams.get("system-info")).toContain("- 版本号: v0.5.0"); + expect(url.searchParams.get("system-info")).toContain("- 系统: Android 16"); + expect(url.searchParams.get("template")).toBeNull(); }); });