diff --git a/packages/amazonq/.changes/next-release/Bug Fix-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json b/packages/amazonq/.changes/next-release/Bug Fix-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json new file mode 100644 index 00000000000..01d6ec7c8b0 --- /dev/null +++ b/packages/amazonq/.changes/next-release/Bug Fix-704d175a-a99f-4ce7-bf08-b94d6f7218c0.json @@ -0,0 +1,4 @@ +{ + "type": "Bug Fix", + "description": "`Send to prompt` and other context menu options not sent if chat was closed" +} diff --git a/packages/core/src/amazonq/apps/initContext.ts b/packages/core/src/amazonq/apps/initContext.ts index e33fafca7c3..f8b06e4b46a 100644 --- a/packages/core/src/amazonq/apps/initContext.ts +++ b/packages/core/src/amazonq/apps/initContext.ts @@ -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, tabType: TabType): void - getAppsToWebViewMessagePublisher(): MessagePublisher + getAppsToWebViewMessagePublisher(): UiMessagePublisher onDidChangeAmazonQVisibility: EventEmitter } export class DefaultAmazonQAppInitContext implements AmazonQAppInitContext { private readonly appsToWebViewEventEmitter = new EventEmitter() private readonly appsToWebViewMessageListener = new MessageListener(this.appsToWebViewEventEmitter) - private readonly appsToWebViewMessagePublisher = new MessagePublisher(this.appsToWebViewEventEmitter) + private readonly appsToWebViewMessagePublisher = new UiMessagePublisher(this.appsToWebViewEventEmitter) private readonly webViewToAppsMessagePublishers: Map> = new Map() public readonly onDidChangeAmazonQVisibility = new EventEmitter() @@ -41,7 +41,7 @@ export class DefaultAmazonQAppInitContext implements AmazonQAppInitContext { return this.appsToWebViewMessageListener } - getAppsToWebViewMessagePublisher(): MessagePublisher { + getAppsToWebViewMessagePublisher(): UiMessagePublisher { return this.appsToWebViewMessagePublisher } } diff --git a/packages/core/src/amazonq/messages/messagePublisher.ts b/packages/core/src/amazonq/messages/messagePublisher.ts index d2987a99536..7fa6976b9a9 100644 --- a/packages/core/src/amazonq/messages/messagePublisher.ts +++ b/packages/core/src/amazonq/messages/messagePublisher.ts @@ -12,3 +12,48 @@ export class MessagePublisher { 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 extends MessagePublisher { + private isUiReady: boolean = false + private buffer: T[] = [] + + constructor(eventEmitter: EventEmitter) { + super(eventEmitter) + } + + public override publish(event: T): void { + // 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 = [] + } +} diff --git a/packages/core/src/amazonq/webview/messages/messageDispatcher.ts b/packages/core/src/amazonq/webview/messages/messageDispatcher.ts index 8acd04e8953..fdd1584b767 100644 --- a/packages/core/src/amazonq/webview/messages/messageDispatcher.ts +++ b/packages/core/src/amazonq/webview/messages/messageDispatcher.ts @@ -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, @@ -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, diff --git a/packages/core/src/shared/logger/logger.ts b/packages/core/src/shared/logger/logger.ts index d5bf5f13380..19be5ac2887 100644 --- a/packages/core/src/shared/logger/logger.ts +++ b/packages/core/src/shared/logger/logger.ts @@ -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(