feat(diagnostics): the issue composer — draft, review, screenshots, zip export (E16 S3)
After Stop (or at the cap, or from Settings → Diagnosztika's past sessions) one dialog drafts the issue: title, description, the steps drafted from the session's markers and page changes (a marker without a label is named by its time), the environment (version, browser, system, window, language). Beside it, what goes with it: the browser and server logs — each reviewable line by line, an unticked line is not sent — and the screenshots, removable, with paste / drop / pick to add more. - it saves as it goes (debug_sessions.draft, migration 0090): the rendered markdown in the user's language, the excluded rows, and its own fields to reopen as it was; a sent session is read-only - the zip export (issue.md, client.log, server.log, screenshots) is built from the saved draft by app/issues/bundle.py — the one definition the Gitea delivery (S4) will share; .log, not .jsonl, which Gitea refuses - the log line's level tags and clock move to components/logLineParts so the review list draws a level the way both log viewers do
This commit is contained in:
@@ -54,6 +54,17 @@ export interface DebugSession {
|
||||
/** The issue it was sent as, once sent. */
|
||||
issue_url: string | null;
|
||||
screenshots: number;
|
||||
/** The issue being written from it (the composer saves as it goes); null until it first does. */
|
||||
draft: DebugDraft | null;
|
||||
}
|
||||
|
||||
/** A saved draft: the rendered text the export and the issue carry, plus the composer's own fields
|
||||
* (`form`, lib/issueDraft `DraftForm`) to reopen it as it was. */
|
||||
export interface DebugDraft {
|
||||
title: string;
|
||||
body: string;
|
||||
excluded: number[];
|
||||
form: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface DebugScreenshot {
|
||||
@@ -87,6 +98,15 @@ export const debugSessionsApi = {
|
||||
headers: { "Content-Type": image.type || "application/octet-stream", ...identityHeaders() },
|
||||
body: image,
|
||||
}),
|
||||
saveDebugDraft: (id: string, draft: DebugDraft): Promise<{ ok: true; session: DebugSession }> =>
|
||||
req(`${SESSIONS}/${id}/draft`, { method: "PUT", body: JSON.stringify(draft) }),
|
||||
/** The issue as a zip, built from the SAVED draft. A navigation, not a `req` — so the account
|
||||
* rides as `?account=`, as for every download. */
|
||||
debugExportUrl: (id: string): string => {
|
||||
const a = getActiveAccount();
|
||||
const url = `${SESSIONS}/${id}/export`;
|
||||
return a != null ? `${url}?account=${a}` : url;
|
||||
},
|
||||
removeDebugScreenshot: (id: string, shotId: number): Promise<{ ok: true; deleted: number }> =>
|
||||
req(`${SESSIONS}/${id}/screenshots/${shotId}`, { method: "DELETE" }),
|
||||
/** Where an `<img>` loads a screenshot from. An `<img>` cannot send the account header, so the
|
||||
|
||||
Reference in New Issue
Block a user