feat: integrate structured GitHub issue forms and prefilled feedback URLs

This commit is contained in:
tianma-if committed 2026-09-30 17:49:20 +08:00
1 parent 1ff8a44f92
commit ae6ae99eeb
11 files changed
+250 -20

No files matched your search

+79
View File
@@ -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"
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
+67
View File
@@ -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
+52
View File
@@ -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
+18 -14
View File
@@ -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",
"",
"<!-- Please describe what you were doing immediately before EdgeEver showed the recovery screen. -->",
"",
"## 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);
@@ -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);
});
@@ -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
}
@@ -819,5 +819,6 @@ const buildMobileFeedbackUrl = (
? "The following information was generated by EdgeEver to help diagnose the issue."
: "以下信息由 EdgeEver 自动生成,可帮助定位问题。",
titlePrefix: english ? "[Feedback] " : "[反馈] ",
client: "Android",
});
};
@@ -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"));
});
});
+15 -2
View File
@@ -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}`,
"",
`<!-- ${systemInfoNotice} -->`,
...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()}`;
};
+3
View File
@@ -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();
});
});