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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "Bug Fix",
"description": "`Send to prompt` and other context menu options not sent if chat was closed"
}
8 changes: 4 additions & 4 deletions packages/core/src/amazonq/apps/initContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@
*/

import { EventEmitter } from 'vscode'
import { MessagePublisher } from '../messages/messagePublisher'
import { MessagePublisher, UiMessagePublisher } from '../messages/messagePublisher'
import { MessageListener } from '../messages/messageListener'
import { TabType } from '../webview/ui/storages/tabsStorage'

export interface AmazonQAppInitContext {
registerWebViewToAppMessagePublisher(eventEmitter: MessagePublisher<any>, tabType: TabType): void
getAppsToWebViewMessagePublisher(): MessagePublisher<any>
getAppsToWebViewMessagePublisher(): UiMessagePublisher<any>
onDidChangeAmazonQVisibility: EventEmitter<boolean>
}

export class DefaultAmazonQAppInitContext implements AmazonQAppInitContext {
private readonly appsToWebViewEventEmitter = new EventEmitter<any>()
private readonly appsToWebViewMessageListener = new MessageListener<any>(this.appsToWebViewEventEmitter)
private readonly appsToWebViewMessagePublisher = new MessagePublisher<any>(this.appsToWebViewEventEmitter)
private readonly appsToWebViewMessagePublisher = new UiMessagePublisher<any>(this.appsToWebViewEventEmitter)
private readonly webViewToAppsMessagePublishers: Map<TabType, MessagePublisher<any>> = new Map()
public readonly onDidChangeAmazonQVisibility = new EventEmitter<boolean>()

Expand All @@ -41,7 +41,7 @@ export class DefaultAmazonQAppInitContext implements AmazonQAppInitContext {
return this.appsToWebViewMessageListener
}

getAppsToWebViewMessagePublisher(): MessagePublisher<any> {
getAppsToWebViewMessagePublisher(): UiMessagePublisher<any> {
return this.appsToWebViewMessagePublisher
}
}
45 changes: 45 additions & 0 deletions packages/core/src/amazonq/messages/messagePublisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,48 @@ export class MessagePublisher<T> {
this.eventEmitter.fire(event)
}
}

/**
* Same as {@link MessagePublisher}, but will wait until the UI indicates it
* is ready to recieve messages, before the message is published.
*
* This solves a problem when running a right click menu option like
* "Send To Prompt" BUT chat is not opened yet, it would result in the prompt failing to
* be recieved by chat.
*/
export class UiMessagePublisher<T> extends MessagePublisher<T> {
private isUiReady: boolean = false
private buffer: T[] = []

constructor(eventEmitter: EventEmitter<T>) {
super(eventEmitter)
}

public override publish(event: T): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to encapsulate the logic for isUiReady in this class somehow? Technically, it seems like this class is meant to hold requests until the UI is ready so keeping the uiReady logic close might make more sense

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this makes sense, updated

// immediately send if Chat UI is ready
if (this.isUiReady) {
super.publish(event)
return
}

this.buffer.push(event)
}

/**
* Indicate the Q Chat UI is ready to recieve messages.
*/
public setUiReady() {
this.isUiReady = true
this.flush()
}

/**
* Publishes all blocked messages
*/
private flush() {
for (const msg of this.buffer) {
super.publish(msg)
}
this.buffer = []
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { telemetry } from '../../../shared/telemetry'
import { AmazonQChatMessageDuration } from '../../messages/chatMessageDuration'
import { globals, openUrl } from '../../../shared'
import { isClickTelemetry, isOpenAgentTelemetry } from '../ui/telemetry/actions'
import { DefaultAmazonQAppInitContext } from '../../apps/initContext'

export function dispatchWebViewMessagesToApps(
webview: Webview,
Expand All @@ -21,12 +22,12 @@ export function dispatchWebViewMessagesToApps(
webview.onDidReceiveMessage((msg) => {
switch (msg.command) {
case 'ui-is-ready': {
DefaultAmazonQAppInitContext.instance.getAppsToWebViewMessagePublisher().setUiReady()
/**
* ui-is-ready isn't associated to any tab so just record the telemetry event and continue.
* This would be equivalent of the duration between "user clicked open q" and "ui has become available"
* NOTE: Amazon Q UI is only loaded ONCE. The state is saved between each hide/show of the webview.
*/

telemetry.webview_load.emit({
webviewName: 'amazonq',
duration: performance.measure(amazonqMark.uiReady, amazonqMark.open).duration,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/shared/logger/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import * as vscode from 'vscode'

export type LogTopic = 'crashMonitoring' | 'dev/beta' | 'notifications' | 'test' | 'childProcess' | 'unknown'
export type LogTopic = 'crashMonitoring' | 'dev/beta' | 'notifications' | 'test' | 'childProcess' | 'unknown' | 'chat'

class ErrorLog {
constructor(
Expand Down
Loading