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
25 changes: 25 additions & 0 deletions packages/app/e2e/sidebar/sidebar-session-organization.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,31 @@ test("users can delete a session from the PawWork sidebar", async ({ page, sdk,
await expect(sidebar.locator(`[data-session-id="${session.id}"]`)).toHaveCount(0)
})

test("session row menu does not expose raw export as a troubleshooting entry", async ({ page, sdk, gotoSession }) => {
const stamp = Date.now()
const session = await sdk.session.create({ title: `e2e sidebar diagnostics ${stamp}` }).then((r) => r.data)

if (!session?.id) throw new Error("missing session id")

try {
await gotoSession(session.id)
await openSidebar(page)

const sidebar = page.locator(pawworkSidebarSelector).first()
const row = sidebar.locator(`[data-session-id="${session.id}"]`).first()
await expect(row).toBeVisible()

await row.hover()
await row.locator('[data-action="session-row-menu"]').click()

await expect(page.getByRole("menuitem", { name: /rename/i })).toBeVisible()
await expect(page.getByRole("menuitem", { name: /export session/i })).toHaveCount(0)
await expect(page.getByRole("menuitem", { name: /diagnostics package/i })).toHaveCount(0)
} finally {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
await cleanupSession({ sdk, sessionID: session.id })
}
})

test("previous and next session follow time order across PawWork projects", async ({ page, backend, project }) => {
const stamp = Date.now()
const other = await createTestProject({ serverUrl: backend.url })
Expand Down
8 changes: 8 additions & 0 deletions packages/app/src/desktop-api-contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ export type ReportProblemResult =
| { status: "ready"; fileName: string; locationHint: string }
| { status: "failed" }
}
| {
status: "package-only"
summaryCopied: true
feedbackOpened: false
fullReport:
| { status: "ready"; fileName: string; locationHint: string }
| { status: "failed" }
}
| { status: "cancelled"; summaryCopied: false; feedbackOpened: false; fullReport: { status: "none" } }
| { status: "unavailable"; summaryCopied: false; feedbackOpened: false; fullReport: { status: "none" } }
| { status: "failed"; summaryCopied: false; feedbackOpened: false; fullReport: { status: "failed" } }
Expand Down
30 changes: 16 additions & 14 deletions packages/app/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,30 +504,32 @@ export const dict = {
"error.page.known.localState.title": "Local state problem",
"error.page.known.localState.description":
"PawWork had trouble reading local state for this workspace. Your original project files are usually not affected.",
"error.page.report.action": "Report a problem",
"error.page.report.preparing": "Preparing report...",
"error.page.report.action": "Prepare diagnostics package",
"error.page.report.preparing": "Preparing diagnostics package...",
"error.page.report.githubFallback": "You can also report this on GitHub.",
"error.page.report.formFallbackAction": "Open the feedback form manually.",
"error.page.report.confirm.description": "PawWork will prepare a problem report and open the feedback form.",
"error.page.report.confirm.description": "PawWork will prepare one diagnostics package and open the feedback form.",
"error.page.report.confirm.privacy":
"The report is for diagnostics. It will not automatically upload your original project files.",
"The package can include conversation content, app logs, local paths, and environment details. It will not automatically upload your original project files.",
"error.page.report.confirm.details": "See what is included",
"error.page.report.confirm.item.error": "Error summary and full error details",
"error.page.report.confirm.item.app": "App version and system information",
"error.page.report.confirm.item.app": "App version, system information, and environment details",
"error.page.report.confirm.item.logs": "Recent diagnostic logs",
"error.page.report.confirm.item.context": "Current page, workspace, and session context",
"error.page.report.confirm.continue": "Prepare report and open form",
"error.page.report.confirm.item.context": "Current page, workspace path, and session context",
"error.page.report.confirm.continue": "Prepare package and open form",
"error.page.report.success":
"The feedback form is open. A short summary was copied, and the full report was saved locally for manual upload.",
"The feedback form is open. A short summary was copied, and the diagnostics package was saved locally for manual upload.",
"error.page.report.summaryOnly": "The current error summary was copied. Paste it into the feedback form.",
"error.page.report.formFallback":
"The feedback form did not open automatically. Open the link manually, then paste the copied summary.",
"error.page.report.packageOnly":
"The diagnostics package was saved locally. This build does not have a feedback form configured, so attach the package when reporting this.",
"error.page.report.failed":
"PawWork could not prepare the report. Use the technical details below when reporting this.",
"PawWork could not prepare the diagnostics package. Use the technical details below when reporting this.",
"error.page.report.copiedFallback":
"PawWork could not prepare the report. The current error details were copied instead.",
"PawWork could not prepare the diagnostics package. The current error details were copied instead.",
"error.page.report.unavailable":
"Problem reporting is not available in this build. Use the GitHub link or the technical details below.",
"Diagnostics packages are not available in this build. Use the GitHub link or the technical details below.",
"error.page.version": "Version: {{version}}",

"error.dev.rootNotFound":
Expand Down Expand Up @@ -744,9 +746,9 @@ export const dict = {
"session.share.copy.copied": "Copied",
"session.share.copy.copyLink": "Copy link",

"session.export.action.export": "Export session",
"session.export.success": "Session exported",
"session.export.error.failed": "Export failed",
"session.export.action.export": "Prepare diagnostics package",
"session.export.success": "Diagnostics package ready",
"session.export.error.failed": "Diagnostics package failed",

"lsp.tooltip.none": "No LSP servers",
"lsp.label.connected": "{{count}} LSP",
Expand Down
29 changes: 15 additions & 14 deletions packages/app/src/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -488,24 +488,25 @@ export const dict = {
"error.page.known.localState.title": "本地状态问题",
"error.page.known.localState.description":
"爪印在读取这个工作区的本地状态时遇到了问题。这通常不影响你的原始项目文件。",
"error.page.report.action": "报告问题",
"error.page.report.preparing": "正在准备报告...",
"error.page.report.action": "准备诊断包",
"error.page.report.preparing": "正在准备诊断包...",
"error.page.report.githubFallback": "也可以在 GitHub 反馈。",
"error.page.report.formFallbackAction": "手动打开反馈表单。",
"error.page.report.confirm.description": "爪印会准备一份问题报告并打开反馈表单。",
"error.page.report.confirm.privacy": "报告用于排查问题,默认不会自动上传你的原始项目文件。",
"error.page.report.confirm.description": "爪印会准备一份诊断包并打开反馈表单。",
"error.page.report.confirm.privacy": "诊断包可能包含会话内容、应用日志、本地路径和环境信息。不会自动上传你的原始项目文件。",
"error.page.report.confirm.details": "查看会包含哪些信息",
"error.page.report.confirm.item.error": "错误摘要和完整错误详情",
"error.page.report.confirm.item.app": "应用版本和系统信息",
"error.page.report.confirm.item.app": "应用版本、系统信息和环境信息",
"error.page.report.confirm.item.logs": "最近的诊断日志",
"error.page.report.confirm.item.context": "当前页面、工作区和会话上下文",
"error.page.report.confirm.continue": "准备报告并打开表单",
"error.page.report.success": "反馈表单已打开。摘要已复制,完整报告已保存到本地,可手动上传。",
"error.page.report.confirm.item.context": "当前页面、工作区路径和会话上下文",
"error.page.report.confirm.continue": "准备诊断包并打开表单",
"error.page.report.success": "反馈表单已打开。摘要已复制,诊断包已保存到本地,可手动上传。",
"error.page.report.summaryOnly": "已复制当前错误摘要。请在表单里粘贴这段内容。",
"error.page.report.formFallback": "反馈表单没有自动打开。请手动打开链接,然后粘贴已复制的摘要。",
"error.page.report.failed": "爪印无法准备问题报告。反馈时请使用下面的技术详情。",
"error.page.report.copiedFallback": "爪印无法准备问题报告。已改为复制当前错误详情。",
"error.page.report.unavailable": "当前构建不支持问题报告。请使用 GitHub 链接,或复制下面的技术详情。",
"error.page.report.packageOnly": "诊断包已保存到本地。当前构建没有配置反馈表单,反馈时请附上这份诊断包。",
"error.page.report.failed": "爪印无法准备诊断包。反馈时请使用下面的技术详情。",
"error.page.report.copiedFallback": "爪印无法准备诊断包。已改为复制当前错误详情。",
"error.page.report.unavailable": "当前构建不支持诊断包。请使用 GitHub 链接,或复制下面的技术详情。",
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"error.page.version": "版本:{{version}}",
"error.dev.rootNotFound": "未找到根元素。你是不是忘了把它添加到 index.html?或者 id 属性拼写错了?",
"error.globalSync.connectFailed": "无法连接到服务器。是否有服务器正在 `{{url}}` 运行?",
Expand Down Expand Up @@ -676,9 +677,9 @@ export const dict = {
"session.share.copy.copied": "已复制",
"session.share.copy.copyLink": "复制链接",

"session.export.action.export": "导出会话",
"session.export.success": "会话已导出",
"session.export.error.failed": "导出失败",
"session.export.action.export": "准备诊断包",
"session.export.success": "诊断包已准备好",
"session.export.error.failed": "诊断包准备失败",

"lsp.tooltip.none": "没有 LSP 服务器",
"lsp.label.connected": "{{count}} LSP",
Expand Down
27 changes: 21 additions & 6 deletions packages/app/src/pages/error-report.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ const t: ErrorReportTranslator = (key, vars) => {
"error.page.known.localState.description":
"PawWork had trouble reading local state for this workspace. Your original project files are usually not affected.",
"error.page.report.success":
"The feedback form is open. A short summary was copied, and the full report was saved locally for manual upload.",
"The feedback form is open. A short summary was copied, and the diagnostics package was saved locally for manual upload.",
"error.page.report.summaryOnly": "The current error summary was copied. Paste it into the feedback form.",
"error.page.report.formFallback":
"The feedback form did not open automatically. Open the link manually, then paste the copied summary.",
"error.page.report.packageOnly":
"The diagnostics package was saved locally. This build does not have a feedback form configured.",
"error.page.report.failed":
"PawWork could not prepare the report. Use the technical details below when reporting this.",
"PawWork could not prepare the diagnostics package. Use the technical details below when reporting this.",
"error.page.report.unavailable":
"Problem reporting is not available in this build. Use the GitHub link or the technical details below.",
"Diagnostics packages are not available in this build. Use the GitHub link or the technical details below.",
"error.chain.causedBy": "Caused by",
"error.page.circular": "[Circular]",
}
Expand Down Expand Up @@ -141,6 +143,16 @@ describe("error page reporting helpers", () => {
locationHint: "PawWork app data/.../problem-reports/pawwork-problem-report.md",
},
}
const packageOnly: ReportProblemResult = {
status: "package-only",
summaryCopied: true,
feedbackOpened: false,
fullReport: {
status: "ready",
fileName: "pawwork-problem-report.md",
locationHint: "PawWork app data/.../problem-reports/pawwork-problem-report.md",
},
}
const failed: ReportProblemResult = {
status: "failed",
summaryCopied: false,
Expand All @@ -161,20 +173,23 @@ describe("error page reporting helpers", () => {
}

expect(errorReportStatusMessage(ready, t)).toBe(
"The feedback form is open. A short summary was copied, and the full report was saved locally for manual upload.",
"The feedback form is open. A short summary was copied, and the diagnostics package was saved locally for manual upload.",
)
expect(errorReportStatusMessage(summaryOnly, t)).toBe(
"The current error summary was copied. Paste it into the feedback form.",
)
expect(errorReportStatusMessage(fallback, t)).toBe(
"The feedback form did not open automatically. Open the link manually, then paste the copied summary.",
)
expect(errorReportStatusMessage(packageOnly, t)).toBe(
"The diagnostics package was saved locally. This build does not have a feedback form configured.",
)
expect(errorReportStatusMessage(failed, t)).toBe(
"PawWork could not prepare the report. Use the technical details below when reporting this.",
"PawWork could not prepare the diagnostics package. Use the technical details below when reporting this.",
)
expect(errorReportStatusMessage(cancelled, t)).toBeUndefined()
expect(errorReportStatusMessage(unavailable, t)).toBe(
"Problem reporting is not available in this build. Use the GitHub link or the technical details below.",
"Diagnostics packages are not available in this build. Use the GitHub link or the technical details below.",
)
})
})
1 change: 1 addition & 0 deletions packages/app/src/pages/error-report.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import type { RendererErrorDetails, ReportProblemResult } from "@/context/platform"
import { ChildStoreError } from "@/context/global-sync/child-store-error"

Expand Down Expand Up @@ -266,6 +266,7 @@
if (result.status === "ready") return t("error.page.report.success")
if (result.status === "summary-only") return t("error.page.report.summaryOnly")
if (result.status === "form-fallback") return t("error.page.report.formFallback", { url: result.feedbackUrl })
if (result.status === "package-only") return t("error.page.report.packageOnly")
if (result.status === "cancelled") return undefined
if (result.status === "unavailable") return t("error.page.report.unavailable")
return t("error.page.report.failed")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,10 @@ describe("createPawworkSessionCommands", () => {
})
})

test("exportSessionAvailable requires platform export and a sidecar server", () => {
test("exportSessionAvailable no longer exposes raw session JSON export", () => {
createRoot((dispose) => {
const sidecar = setup({ exportSession: (() => Promise.resolve({ ok: true, path: "" })) as never, serverCurrent: { type: "sidecar" } })
expect(createPawworkSessionCommands(sidecar.input).exportSessionAvailable()).toBe(true)
expect(createPawworkSessionCommands(sidecar.input).exportSessionAvailable()).toBe(false)

const remote = setup({ exportSession: (() => Promise.resolve({ ok: true, path: "" })) as never, serverCurrent: { type: "remote" } })
expect(createPawworkSessionCommands(remote.input).exportSessionAvailable()).toBe(false)
Expand Down
10 changes: 4 additions & 6 deletions packages/app/src/pages/layout/pawwork-session-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,10 @@ export function createPawworkSessionCommands(input: PawworkSessionCommandsInput)
}
}

// Export hits the embedded sidecar via main-process IPC. When the user has
// switched the active server to a remote target, the sidecar holds different
// data than the UI; hide the action rather than ship a misleading export.
const exportSessionAvailable = createMemo(
() => !!input.platform.exportSession && input.server.current?.type === "sidecar",
)
// The old raw JSON session export is intentionally hidden from the sidebar.
// Troubleshooting now goes through Help -> diagnostics package so logs,
// renderer diagnostics, environment context, and session content stay together.
const exportSessionAvailable = createMemo(() => false)

async function exportSession(session: Session) {
if (!input.platform.exportSession) return
Expand Down
4 changes: 4 additions & 0 deletions packages/desktop-electron/scripts/report-problem-smoke.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ try {
markdownHasRendererError:
report.markdown.includes(rendererError.summary) && report.markdown.includes('\\"kind\\":\\"manual-smoke\\"'),
markdownHasReportPayload: report.markdown.includes("```json"),
markdownHasMainLog: report.markdown.includes("== Main process log:"),
markdownHasBackendLog: report.markdown.includes("== Backend log:"),
}

console.log(JSON.stringify(summary, null, 2))
Expand All @@ -132,6 +134,8 @@ try {
assert(summary.clipboardRedactedStorage, "expected clipboard summary to redact storage and key diagnostics")
assert(summary.markdownHasRendererError, "expected full report to include renderer error details")
assert(summary.markdownHasReportPayload, "expected full report to include the fenced JSON payload")
assert(summary.markdownHasMainLog, "expected full report to include main process log tail")
assert(summary.markdownHasBackendLog, "expected full report to include backend log tail")
} finally {
await closeApp(app)
rmSync(homeDir, { force: true, maxRetries: 5, recursive: true, retryDelay: 100 })
Expand Down
Loading
Loading