Skip to content

Commit 405ab15

Browse files
authored
Merge pull request #21 from microsoft/feat/adapter-feedback-ux
Feat/adapter feedback ux
2 parents 755fb59 + 298644e commit 405ab15

3 files changed

Lines changed: 60 additions & 22 deletions

File tree

packages/client/src/feedback-controller.ts

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -489,33 +489,63 @@ export function createHeadlessFeedbackController(
489489
)
490490
if (state.disposed) return state.submitState
491491

492-
const adapterFailures = adapterResults.flatMap((entry) => {
493-
if (entry.status === 'rejected') return ['adapter']
494-
return entry.value.result.ok ? [] : [entry.value.name]
495-
})
492+
const adapterSuccesses: string[] = []
493+
const adapterFailures: string[] = []
494+
let hasDeliveryUrl = false
495+
for (const entry of adapterResults) {
496+
if (entry.status === 'rejected') {
497+
adapterFailures.push('adapter')
498+
} else if (entry.value.result.ok) {
499+
const { deliveryId: id, deliveryUrl: url } = entry.value.result
500+
if (url) {
501+
adapterSuccesses.push(`<a href="${url}" target="_blank" rel="noopener" style="color:inherit;text-decoration:underline">${entry.value.name} #${id ?? ''}</a>`)
502+
hasDeliveryUrl = true
503+
} else {
504+
adapterSuccesses.push(id ? `${entry.value.name} #${id}` : entry.value.name)
505+
}
506+
} else {
507+
adapterFailures.push(entry.value.name)
508+
}
509+
}
510+
511+
const hasAdapterSuccess = adapterSuccesses.length > 0
512+
const hasAdapterFailure = adapterFailures.length > 0
496513

497-
if (!flushOk || adapterFailures.length > 0) {
514+
if (hasAdapterSuccess && !hasAdapterFailure) {
515+
state.submitState = {
516+
kind: 'complete',
517+
tone: 'success',
518+
message: `Feedback delivered via ${adapterSuccesses.join(', ')}.`,
519+
html: hasDeliveryUrl,
520+
}
521+
} else if (hasAdapterSuccess && hasAdapterFailure) {
498522
state.submitState = {
499523
kind: 'complete',
500524
tone: 'warning',
501-
message: [
502-
flushOk
503-
? 'Feedback saved and sent from this page.'
504-
: 'Feedback saved locally. Server delivery will retry automatically.',
505-
adapterFailures.length > 0
506-
? `Adapter delivery failed: ${adapterFailures.join(', ')}.`
507-
: '',
508-
]
509-
.filter(Boolean)
510-
.join(' '),
525+
message: `Delivered via ${adapterSuccesses.join(', ')}. Failed: ${adapterFailures.join(', ')}.`,
526+
html: hasDeliveryUrl,
511527
}
512-
} else {
528+
} else if (!hasAdapterSuccess && config.adapters.length > 0) {
529+
state.submitState = {
530+
kind: 'complete',
531+
tone: 'warning',
532+
message: flushOk
533+
? 'Feedback saved to server. Adapter delivery failed.'
534+
: 'Feedback saved locally. Delivery will retry automatically.',
535+
}
536+
} else if (flushOk) {
513537
state.submitState = {
514538
kind: 'complete',
515539
tone: 'success',
516540
message: state.includeScreenshot
517-
? 'Feedback sent with the current screenshot attached.'
518-
: 'Feedback sent without a screenshot.',
541+
? 'Feedback sent with screenshot attached.'
542+
: 'Feedback sent.',
543+
}
544+
} else {
545+
state.submitState = {
546+
kind: 'complete',
547+
tone: 'warning',
548+
message: 'Feedback saved locally. Server delivery will retry automatically.',
519549
}
520550
}
521551

packages/client/src/feedback.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,12 @@ export function showFeedbackDialog(
344344
return parts.length > 0 ? `Details · ${parts.join(' · ')}` : 'Details'
345345
}
346346

347-
const updateStatus = (message: string, tone?: FeedbackStatusTone) => {
348-
status.textContent = message
347+
const updateStatus = (message: string, tone?: FeedbackStatusTone, html = false) => {
348+
if (html) {
349+
status.innerHTML = message
350+
} else {
351+
status.textContent = message
352+
}
349353
status.style.padding = message ? '8px 10px' : '0'
350354
status.style.borderRadius = theme.panelRadius
351355
if (tone) {
@@ -426,7 +430,7 @@ export function showFeedbackDialog(
426430
sendButton.textContent = 'Close'
427431
setButtonEnabled(sendButton, true)
428432
cancelButton.style.display = 'none'
429-
updateStatus(completion.message, completion.tone)
433+
updateStatus(completion.message, completion.tone, completion.html)
430434
schedulePosition()
431435
return
432436
}

packages/client/src/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export type FeedbackScreenshotState = 'pending' | 'ready' | 'unavailable'
3535
export type FeedbackSubmitState =
3636
| { kind: 'idle' }
3737
| { kind: 'submitting' }
38-
| { kind: 'complete'; tone: FeedbackStatusTone; message: string }
38+
| { kind: 'complete'; tone: FeedbackStatusTone; message: string; html?: boolean }
3939

4040
export interface FeedbackTrigger {
4141
element: Element
@@ -103,6 +103,8 @@ export interface AdapterResult {
103103
error?: string
104104
/** Adapter-specific delivery ID (e.g. issue number, message ID). */
105105
deliveryId?: string
106+
/** URL to view the delivered feedback (e.g. GitHub issue link). */
107+
deliveryUrl?: string
106108
}
107109

108110
/**
@@ -111,6 +113,8 @@ export interface AdapterResult {
111113
*/
112114
export interface FeedbackAdapter {
113115
name: string
116+
/** Human-friendly label shown in the UI (e.g. "GitHub"). Defaults to name. */
117+
displayName?: string
114118
send(event: TelemetryEvent): Promise<AdapterResult>
115119
}
116120

0 commit comments

Comments
 (0)