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
66 changes: 48 additions & 18 deletions packages/client/src/feedback-controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { showAnnotationCanvas } from './annotation.js'

Check failure on line 1 in packages/client/src/feedback-controller.ts

View workflow job for this annotation

GitHub Actions / Lint & Format

format

File content differs from formatting output
import { getConsoleErrors } from './console-capture.js'
import { getLabel, getPath, getText } from './helpers.js'
import { enrichElement } from './plugins.js'
Expand Down Expand Up @@ -489,33 +489,63 @@
)
if (state.disposed) return state.submitState

const adapterFailures = adapterResults.flatMap((entry) => {
if (entry.status === 'rejected') return ['adapter']
return entry.value.result.ok ? [] : [entry.value.name]
})
const adapterSuccesses: string[] = []
const adapterFailures: string[] = []
let hasDeliveryUrl = false
for (const entry of adapterResults) {
if (entry.status === 'rejected') {
adapterFailures.push('adapter')
} else if (entry.value.result.ok) {
const { deliveryId: id, deliveryUrl: url } = entry.value.result
if (url) {
adapterSuccesses.push(`<a href="${url}" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline">${entry.value.name} #${id ?? ''}</a>`)
hasDeliveryUrl = true
} else {
adapterSuccesses.push(id ? `${entry.value.name} #${id}` : entry.value.name)
}
} else {
adapterFailures.push(entry.value.name)
}
}

const hasAdapterSuccess = adapterSuccesses.length > 0
const hasAdapterFailure = adapterFailures.length > 0

if (!flushOk || adapterFailures.length > 0) {
if (hasAdapterSuccess && !hasAdapterFailure) {
state.submitState = {
kind: 'complete',
tone: 'success',
message: `Feedback delivered via ${adapterSuccesses.join(', ')}.`,
html: hasDeliveryUrl,
}
} else if (hasAdapterSuccess && hasAdapterFailure) {
state.submitState = {
kind: 'complete',
tone: 'warning',
message: [
flushOk
? 'Feedback saved and sent from this page.'
: 'Feedback saved locally. Server delivery will retry automatically.',
adapterFailures.length > 0
? `Adapter delivery failed: ${adapterFailures.join(', ')}.`
: '',
]
.filter(Boolean)
.join(' '),
message: `Delivered via ${adapterSuccesses.join(', ')}. Failed: ${adapterFailures.join(', ')}.`,
html: hasDeliveryUrl,
}
} else {
} else if (!hasAdapterSuccess && config.adapters.length > 0) {
state.submitState = {
kind: 'complete',
tone: 'warning',
message: flushOk
? 'Feedback saved to server. Adapter delivery failed.'
: 'Feedback saved locally. Delivery will retry automatically.',
}
} else if (flushOk) {
state.submitState = {
kind: 'complete',
tone: 'success',
message: state.includeScreenshot
? 'Feedback sent with the current screenshot attached.'
: 'Feedback sent without a screenshot.',
? 'Feedback sent with screenshot attached.'
: 'Feedback sent.',
}
} else {
state.submitState = {
kind: 'complete',
tone: 'warning',
message: 'Feedback saved locally. Server delivery will retry automatically.',
}
}

Expand Down
10 changes: 7 additions & 3 deletions packages/client/src/feedback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,12 @@ export function showFeedbackDialog(
return parts.length > 0 ? `Details · ${parts.join(' · ')}` : 'Details'
}

const updateStatus = (message: string, tone?: FeedbackStatusTone) => {
status.textContent = message
const updateStatus = (message: string, tone?: FeedbackStatusTone, html = false) => {
if (html) {
status.innerHTML = message
} else {
status.textContent = message
}
status.style.padding = message ? '8px 10px' : '0'
status.style.borderRadius = theme.panelRadius
if (tone) {
Expand Down Expand Up @@ -426,7 +430,7 @@ export function showFeedbackDialog(
sendButton.textContent = 'Close'
setButtonEnabled(sendButton, true)
cancelButton.style.display = 'none'
updateStatus(completion.message, completion.tone)
updateStatus(completion.message, completion.tone, completion.html)
schedulePosition()
return
}
Expand Down
6 changes: 5 additions & 1 deletion packages/client/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export type FeedbackScreenshotState = 'pending' | 'ready' | 'unavailable'
export type FeedbackSubmitState =
| { kind: 'idle' }
| { kind: 'submitting' }
| { kind: 'complete'; tone: FeedbackStatusTone; message: string }
| { kind: 'complete'; tone: FeedbackStatusTone; message: string; html?: boolean }

export interface FeedbackTrigger {
element: Element
Expand Down Expand Up @@ -103,6 +103,8 @@ export interface AdapterResult {
error?: string
/** Adapter-specific delivery ID (e.g. issue number, message ID). */
deliveryId?: string
/** URL to view the delivered feedback (e.g. GitHub issue link). */
deliveryUrl?: string
}

/**
Expand All @@ -111,6 +113,8 @@ export interface AdapterResult {
*/
export interface FeedbackAdapter {
name: string
/** Human-friendly label shown in the UI (e.g. "GitHub"). Defaults to name. */
displayName?: string
send(event: TelemetryEvent): Promise<AdapterResult>
}

Expand Down
Loading