diff --git a/packages/i18n/src/locales/en/settings.yaml b/packages/i18n/src/locales/en/settings.yaml index d847c34ac..e82d7ce5d 100644 --- a/packages/i18n/src/locales/en/settings.yaml +++ b/packages/i18n/src/locales/en/settings.yaml @@ -68,6 +68,23 @@ dialogs: stateRequesting: Requesting... stateGranted: Granted stateNotGranted: Not granted + bug-report: + title: Bug report (´;ω;`)ヾ(・∀・`) + subtitle: Oops, sorry we made something wrong. Would you mind telling us what happened? + trigger-label: Report a Bug + submit-label: Send Bug Report + triage-description: Include screenshot and page context to help us triage this issue. + description-placeholder: Steps to reproduce, expected behavior, and actual behavior + include-current-page-screenshot: Include current page screenshot + manual-media: + label: Manually choose screenshots / recordings + optional: Optional. + media-files: + label: Media files + description: 'Optional: manually select.' + placeholder: Choose screenshot or video file + selected-count: '{count} file(s) selected' + last-submitted-preview: Last Submitted Payload Preview language: title: Language description: | diff --git a/packages/i18n/src/locales/en/tamagotchi/stage.yaml b/packages/i18n/src/locales/en/tamagotchi/stage.yaml index d14c7ccaa..a0a3894f1 100644 --- a/packages/i18n/src/locales/en/tamagotchi/stage.yaml +++ b/packages/i18n/src/locales/en/tamagotchi/stage.yaml @@ -45,3 +45,49 @@ notice: preparing: Preparing… read-more: Read more preview-title: What is it? + +about: + subtitle: Desktop ver. + current-version: Current Version + common: + cancel: Cancel + links: + title: Links + home: Home + documentation: Documentations + github: GitHub + update: + lane: + label: Update lane + description: Choose which release lane updater checks against. Auto follows the current app prerelease lane. + placeholder: Choose update lane + channels: + auto: Auto + stable: Stable + alpha: Alpha + beta: Beta + nightly: Nightly + canary: Canary + status: + downloading: Downloading update... + error-prefix: Error + latest: Up to date (v{version}). + downloaded: + windows: Update ready to install silently (v{version}). + restart: Update ready to install on restart (v{version}). + actions: + download: Download Update + download-short: Download + confirm-download: Confirm Download + check-for-updates: Check for updates + checking: Checking... + latest-version: Latest version + disabled-dev: Updates disabled in Dev + retry-check: Retry Check + restart-silent: Restart to update silently + restart-install: Restart to install update + confirm-restart: Confirm Restart + dialog: + title: Update Available + description: A new version (v{version}) is available. + no-release-notes-markdown: _No release notes provided._ diff --git a/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-dialog.vue b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-dialog.vue new file mode 100644 index 000000000..38915c72a --- /dev/null +++ b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-dialog.vue @@ -0,0 +1,214 @@ + + + + showDialog = value"> + + + + + + {{ resolvedTitle }} + + + {{ resolvedSubtitle }} + + + + + + + + + showDialog = value"> + + + + + {{ resolvedTitle }} + + + + + + {{ resolvedTitle }} + + + {{ resolvedSubtitle }} + + + + + + + + diff --git a/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-form.vue b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-form.vue new file mode 100644 index 000000000..0cefdb1d8 --- /dev/null +++ b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-form.vue @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + {{ t('settings.dialogs.bug-report.media-files.selected-count', { count: selectedScreenshotCount }) }} + + + + + + + + + {{ resolvedSubmitLabel }} + + + diff --git a/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-payload.test.ts b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-payload.test.ts new file mode 100644 index 000000000..c13f4ba6f --- /dev/null +++ b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-payload.test.ts @@ -0,0 +1,68 @@ +import { describe, expect, it } from 'vitest' + +import { buildBugReportPayload, createBugReportPageContext } from './bug-report-payload' + +describe('bug report payload helpers', () => { + it('builds markdown payload with description and optional context/screenshot flags', () => { + const payload = buildBugReportPayload({ + description: 'Clicking send does nothing', + includeTriageContext: true, + context: { + url: 'https://airi.local/chat?room=debug', + title: 'AIRI Chat', + userAgent: 'test-agent', + viewport: '1440x900', + language: 'en-US', + timeZone: 'Asia/Shanghai', + timestamp: '2026-04-09T11:22:33.000Z', + }, + screenshotAttached: true, + }) + + expect(payload).toContain('## Bug Report') + expect(payload).toContain('Clicking send does nothing') + expect(payload).toContain('## Triage Context') + expect(payload).toContain('- URL: https://airi.local/chat?room=debug') + expect(payload).toContain('- Screenshot attached: yes') + }) + + it('returns null page context when window is unavailable', () => { + const context = createBugReportPageContext(undefined) + expect(context).toBeNull() + }) + + it('extracts page context from a window-like object', () => { + const context = createBugReportPageContext({ + location: { + href: 'https://airi.local/settings?tab=providers', + }, + document: { + title: 'Settings', + }, + navigator: { + userAgent: 'unit-test', + language: 'en-US', + }, + innerWidth: 1280, + innerHeight: 720, + Intl: { + DateTimeFormat: () => ({ + resolvedOptions: () => ({ timeZone: 'UTC' }), + }), + }, + Date: { + now: () => 1_700_000_000_000, + }, + }) + + expect(context).toEqual({ + url: 'https://airi.local/settings?tab=providers', + title: 'Settings', + userAgent: 'unit-test', + viewport: '1280x720', + language: 'en-US', + timeZone: 'UTC', + timestamp: '2023-11-14T22:13:20.000Z', + }) + }) +}) diff --git a/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-payload.ts b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-payload.ts new file mode 100644 index 000000000..65cba2a7c --- /dev/null +++ b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-payload.ts @@ -0,0 +1,91 @@ +export interface BugReportPageContext { + url: string + title: string + userAgent: string + viewport: string + language: string + timeZone: string + timestamp: string +} + +export interface BuildBugReportPayloadOptions { + description: string + includeTriageContext?: boolean + context?: BugReportPageContext | null + screenshotAttached?: boolean +} + +interface WindowLike { + location?: { + href?: string + } + document?: { + title?: string + } + navigator?: { + userAgent?: string + language?: string + } + innerWidth?: number + innerHeight?: number + Intl?: { + DateTimeFormat?: () => { + resolvedOptions?: () => { + timeZone?: string + } + } + } + Date?: { + now?: () => number + } +} + +export function createBugReportPageContext(win: WindowLike | undefined = globalThis.window): BugReportPageContext | null { + if (!win) + return null + + const now = win.Date?.now?.() ?? Date.now() + const timeZone = win.Intl?.DateTimeFormat?.()?.resolvedOptions?.()?.timeZone ?? 'unknown' + + return { + url: win.location?.href ?? 'unknown', + title: win.document?.title ?? '', + userAgent: win.navigator?.userAgent ?? 'unknown', + viewport: `${win.innerWidth ?? 0}x${win.innerHeight ?? 0}`, + language: win.navigator?.language ?? 'unknown', + timeZone, + timestamp: new Date(now).toISOString(), + } +} + +export function buildBugReportPayload(options: BuildBugReportPayloadOptions): string { + const sections: string[] = [ + '## Bug Report', + '', + options.description.trim() || '_No description provided._', + ] + + if (!options.includeTriageContext) + return sections.join('\n') + + sections.push('', '## Triage Context') + + if (options.context) { + sections.push( + `- URL: ${options.context.url}`, + `- Title: ${options.context.title || 'unknown'}`, + `- Viewport: ${options.context.viewport}`, + `- User Agent: ${options.context.userAgent}`, + `- Language: ${options.context.language}`, + `- Time Zone: ${options.context.timeZone}`, + `- Captured At: ${options.context.timestamp}`, + ) + } + else { + sections.push('- Page context unavailable') + } + + sections.push(`- Screenshot attached: ${options.screenshotAttached ? 'yes' : 'no'}`) + + return sections.join('\n') +} diff --git a/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-trigger.vue b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-trigger.vue new file mode 100644 index 000000000..c45ae224f --- /dev/null +++ b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report-trigger.vue @@ -0,0 +1,114 @@ + + + + + + + + {{ resolvedTriggerLabel }} + + + + + + {{ t('settings.dialogs.bug-report.last-submitted-preview') }} + + {{ submittedReport }} + + + + + diff --git a/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report.story.vue b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report.story.vue new file mode 100644 index 000000000..90b626f7a --- /dev/null +++ b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/bug-report.story.vue @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + Use this to test reporting from a chat-like screen. + + + + + + diff --git a/packages/stage-ui/src/components/scenarios/dialogs/bug-report/index.ts b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/index.ts new file mode 100644 index 000000000..4d0265eb0 --- /dev/null +++ b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/index.ts @@ -0,0 +1,4 @@ +export { default as BugReportDialog } from './bug-report-dialog.vue' +export * from './bug-report-payload' +export { default as BugReportTrigger } from './bug-report-trigger.vue' +export * from './types' diff --git a/packages/stage-ui/src/components/scenarios/dialogs/bug-report/types.ts b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/types.ts new file mode 100644 index 000000000..1e79e8d57 --- /dev/null +++ b/packages/stage-ui/src/components/scenarios/dialogs/bug-report/types.ts @@ -0,0 +1,10 @@ +import type { BugReportPageContext } from './bug-report-payload' + +export interface BugReportDialogSubmitPayload { + description: string + includeTriageContext: boolean + context: BugReportPageContext | null + screenshotAttached: boolean + screenshotFiles: File[] + formattedReport: string +} diff --git a/packages/stage-ui/src/components/scenarios/dialogs/index.ts b/packages/stage-ui/src/components/scenarios/dialogs/index.ts index 365073882..67129f020 100644 --- a/packages/stage-ui/src/components/scenarios/dialogs/index.ts +++ b/packages/stage-ui/src/components/scenarios/dialogs/index.ts @@ -2,5 +2,6 @@ export * from './about' export { default as AboutDialogWithContent } from './about.vue' export * from './audio-input' export * from './background-picker' +export * from './bug-report' export * from './onboarding' export * from './validation-details'
{{ submittedReport }}