From 92b30dc2437b48bee4f34167e3466b4039188da6 Mon Sep 17 00:00:00 2001 From: Yaofu Zuo Date: Fri, 20 Jun 2025 16:40:51 -0700 Subject: [PATCH 1/6] feat(q): enable image context --- .../amazonq/webview/BrowserConnector.kt | 13 +++++++++++++ .../services/amazonq/lsp/AmazonQChatServer.kt | 7 +++++++ .../amazonq/lsp/AmazonQLanguageClient.kt | 4 ++++ .../amazonq/lsp/AmazonQLanguageClientImpl.kt | 19 +++++++++++++++++++ .../lsp/model/aws/chat/FlareChatCommands.kt | 3 +++ 5 files changed, 46 insertions(+) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt index f030d69aa3..98dea5156e 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt @@ -74,6 +74,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GET_S import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatResponse import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LIST_MCP_SERVERS_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.MCP_SERVER_CLICK_REQUEST_METHOD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_FILE_DIALOG_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_SETTINGS import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_WORKSPACE_SETTINGS_KEY import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenSettingsNotification @@ -85,6 +86,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PROMP import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.QuickChatActionRequest import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SEND_CHAT_COMMAND_PROMPT import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.STOP_CHAT_RESPONSE +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_FILE_DIALOG import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SendChatPromptRequest import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.StopResponseMessage import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TELEMETRY_EVENT @@ -485,6 +487,17 @@ class BrowserConnector( ) } } + OPEN_FILE_DIALOG -> { + handleChat(AmazonQChatServer.showOpenFileDialog, node) + .whenComplete { response, _ -> + browser.postChat( + FlareUiMessage( + command = OPEN_FILE_DIALOG_REQUEST_METHOD, + params = response + ) + ) + } + } } } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt index 7c644894bb..410f90fb9d 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt @@ -42,6 +42,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LIST_ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LinkClickParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ListConversationsParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.MCP_SERVER_CLICK_REQUEST_METHOD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_FILE_DIALOG_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PROMPT_INPUT_OPTIONS_CHANGE import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PromptInputOptionChangeParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SEND_CHAT_COMMAND_PROMPT @@ -222,4 +223,10 @@ object AmazonQChatServer : JsonRpcMethodProvider { TELEMETRY_EVENT, Any::class.java ) + + val showOpenFileDialog = JsonRpcRequest( + OPEN_FILE_DIALOG_REQUEST_METHOD, + Any::class.java, + LSPAny::class.java + ) } diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt index c5141c4446..5051a452f5 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt @@ -22,6 +22,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GET_S import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatResult import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_FILE_DIFF import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenFileDiffParams +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SHOW_OPEN_FILE_DIALOG_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SHOW_SAVE_FILE_DIALOG_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ShowSaveFileDialogParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ShowSaveFileDialogResult @@ -42,6 +43,9 @@ interface AmazonQLanguageClient : LanguageClient { @JsonRequest(SHOW_SAVE_FILE_DIALOG_REQUEST_METHOD) fun showSaveFileDialog(params: ShowSaveFileDialogParams): CompletableFuture + @JsonRequest(SHOW_OPEN_FILE_DIALOG_REQUEST_METHOD) + fun showOpenFileDialog(params: LSPAny): CompletableFuture + @JsonRequest(GET_SERIALIZED_CHAT_REQUEST_METHOD) fun getSerializedChat(params: LSPAny): CompletableFuture diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt index 6eab2f5484..471b7cc0c6 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt @@ -12,6 +12,8 @@ import com.intellij.notification.NotificationType import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.fileChooser.FileChooserFactory import com.intellij.openapi.fileChooser.FileSaverDescriptor +import com.intellij.openapi.fileChooser.FileChooser +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.LocalFileSystem @@ -249,6 +251,23 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC ) } + override fun showOpenFileDialog(params: LSPAny): CompletableFuture { + return CompletableFuture.supplyAsync( + { + val descriptor = FileChooserDescriptorFactory.createMultipleFilesNoJarsDescriptor().apply { + title = "Select Files" + description = "Choose files to open" + } + + val chosenFiles = FileChooser.chooseFiles(descriptor, project, null) + val uris = chosenFiles.map { it.url } + + mapOf("uris" to uris) as LSPAny + }, + ApplicationManager.getApplication()::invokeLater + ) + } + override fun getSerializedChat(params: LSPAny): CompletableFuture { val requestId = UUID.randomUUID().toString() val result = CompletableFuture() diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt index e53835701a..c0e249acd1 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/FlareChatCommands.kt @@ -48,10 +48,13 @@ const val PROMPT_INPUT_OPTIONS_CHANGE = "aws/chat/promptInputOptionChange" const val SEND_CHAT_COMMAND_PROMPT = "aws/chat/sendChatPrompt" const val SHOW_SAVE_FILE_DIALOG_REQUEST_METHOD = "aws/showSaveFileDialog" +const val SHOW_OPEN_FILE_DIALOG_REQUEST_METHOD = "aws/showOpenFileDialog" const val STOP_CHAT_RESPONSE = "stopChatResponse" const val SEND_TO_PROMPT = "sendToPrompt" +const val OPEN_FILE_DIALOG = "openFileDialog" const val TELEMETRY_EVENT = "telemetry/event" // https://github.com/aws/language-server-runtimes/blob/112feba70219a98a12f13727d67c540205fa9c9f/types/chat.ts#L32 const val LIST_MCP_SERVERS_REQUEST_METHOD = "aws/chat/listMcpServers" const val MCP_SERVER_CLICK_REQUEST_METHOD = "aws/chat/mcpServerClick" +const val OPEN_FILE_DIALOG_REQUEST_METHOD = "aws/chat/openFileDialog" From 79f86f61afb1da5a040c8f6dab19ef3b5c260b4a Mon Sep 17 00:00:00 2001 From: Yaofu Zuo Date: Fri, 20 Jun 2025 17:33:39 -0700 Subject: [PATCH 2/6] feat(q): add image context support --- .../services/amazonq/webview/Browser.kt | 7 ++++++ .../amazonq/webview/BrowserConnector.kt | 24 +++++++++---------- .../amazonq/lsp/AmazonQLanguageClient.kt | 3 ++- .../amazonq/lsp/AmazonQLanguageClientImpl.kt | 19 +++++++++------ .../aws/chat/showOpenFileDialogParams.kt | 13 ++++++++++ 5 files changed, 46 insertions(+), 20 deletions(-) create mode 100644 plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/showOpenFileDialogParams.kt diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt index 6f785067db..548b8a0557 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt @@ -8,8 +8,12 @@ import com.google.gson.Gson import com.intellij.openapi.Disposable import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer +import com.intellij.ui.jcef.JBCefClient import com.intellij.ui.jcef.JBCefJSQuery import org.cef.CefApp +import org.cef.browser.CefBrowser +import org.cef.callback.CefDragData +import org.cef.handler.CefDragHandler import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AwsServerCapabilitiesProvider import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.FlareUiMessage @@ -85,6 +89,9 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project) // setup empty state. The message request handlers use this for storing state // that's persistent between page loads. jcefBrowser.setProperty("state", "") + jcefBrowser.jbCefClient.addDragHandler({ browser, dragData, mask -> + true // Allow drag operations + }, jcefBrowser.cefBrowser) // load the web app jcefBrowser.loadHTML( getWebviewHTML( diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt index 98dea5156e..439d8277a6 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt @@ -14,17 +14,6 @@ import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.options.ShowSettingsUtil import com.intellij.openapi.project.Project import com.intellij.ui.jcef.JBCefJSQuery.Response -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.CompletableDeferred -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.merge -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch import org.cef.browser.CefBrowser import org.eclipse.lsp4j.TextDocumentIdentifier import org.eclipse.lsp4j.jsonrpc.ResponseErrorException @@ -74,6 +63,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GET_S import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatResponse import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LIST_MCP_SERVERS_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.MCP_SERVER_CLICK_REQUEST_METHOD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_FILE_DIALOG import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_FILE_DIALOG_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_SETTINGS import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_WORKSPACE_SETTINGS_KEY @@ -86,7 +76,6 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PROMP import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.QuickChatActionRequest import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SEND_CHAT_COMMAND_PROMPT import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.STOP_CHAT_RESPONSE -import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_FILE_DIALOG import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SendChatPromptRequest import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.StopResponseMessage import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TELEMETRY_EVENT @@ -108,6 +97,17 @@ import software.aws.toolkits.telemetry.Telemetry import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletionException import java.util.function.Function +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch class BrowserConnector( private val serializer: MessageSerializer = MessageSerializer.getInstance(), diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt index 5051a452f5..7352e476b2 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClient.kt @@ -24,6 +24,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenFileDiffParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SHOW_OPEN_FILE_DIALOG_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SHOW_SAVE_FILE_DIALOG_REQUEST_METHOD +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ShowOpenFileDialogParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ShowSaveFileDialogParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ShowSaveFileDialogResult import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.credentials.ConnectionMetadata @@ -44,7 +45,7 @@ interface AmazonQLanguageClient : LanguageClient { fun showSaveFileDialog(params: ShowSaveFileDialogParams): CompletableFuture @JsonRequest(SHOW_OPEN_FILE_DIALOG_REQUEST_METHOD) - fun showOpenFileDialog(params: LSPAny): CompletableFuture + fun showOpenFileDialog(params: ShowOpenFileDialogParams): CompletableFuture @JsonRequest(GET_SERIALIZED_CHAT_REQUEST_METHOD) fun getSerializedChat(params: LSPAny): CompletableFuture diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt index 471b7cc0c6..a0fa8365c7 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt @@ -10,10 +10,10 @@ import com.intellij.ide.BrowserUtil import com.intellij.notification.NotificationAction import com.intellij.notification.NotificationType import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.fileChooser.FileChooserFactory -import com.intellij.openapi.fileChooser.FileSaverDescriptor import com.intellij.openapi.fileChooser.FileChooser import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory +import com.intellij.openapi.fileChooser.FileChooserFactory +import com.intellij.openapi.fileChooser.FileSaverDescriptor import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.LocalFileSystem @@ -53,6 +53,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.FileP import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GET_SERIALIZED_CHAT_REQUEST_METHOD import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSerializedChatResult import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenFileDiffParams +import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ShowOpenFileDialogParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ShowSaveFileDialogParams import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ShowSaveFileDialogResult import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.credentials.ConnectionMetadata @@ -251,17 +252,21 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC ) } - override fun showOpenFileDialog(params: LSPAny): CompletableFuture { + override fun showOpenFileDialog(params: ShowOpenFileDialogParams): CompletableFuture { return CompletableFuture.supplyAsync( { - val descriptor = FileChooserDescriptorFactory.createMultipleFilesNoJarsDescriptor().apply { - title = "Select Files" - description = "Choose files to open" + val descriptor = if (params.canSelectMany) { + FileChooserDescriptorFactory.createMultipleFilesNoJarsDescriptor().apply { + title = "Select Files" + description = "Choose files to open" + } + } else { + FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor() } val chosenFiles = FileChooser.chooseFiles(descriptor, project, null) val uris = chosenFiles.map { it.url } - + mapOf("uris" to uris) as LSPAny }, ApplicationManager.getApplication()::invokeLater diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/showOpenFileDialogParams.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/showOpenFileDialogParams.kt new file mode 100644 index 0000000000..7bd075496d --- /dev/null +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/showOpenFileDialogParams.kt @@ -0,0 +1,13 @@ +// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat + +data class ShowOpenFileDialogParams( + val canSelectFiles: Boolean = false, + val canSelectFolders: Boolean = false, + val canSelectMany: Boolean = false, + val filters: Map> = emptyMap(), + val defaultUri: String? = null, + val title: String? = null +) From 9d0fd61ca397e4d683e130532fe6a24fe257aaa1 Mon Sep 17 00:00:00 2001 From: Yaofu Zuo Date: Fri, 20 Jun 2025 17:40:20 -0700 Subject: [PATCH 3/6] add change log + fix some styles --- ...-ddbdde68-769a-468f-bb42-e5aece51c729.json | 4 ++++ .../services/amazonq/webview/Browser.kt | 5 ----- .../amazonq/webview/BrowserConnector.kt | 22 +++++++++---------- .../aws/chat/showOpenFileDialogParams.kt | 2 +- 4 files changed, 16 insertions(+), 17 deletions(-) create mode 100644 .changes/next-release/feature-ddbdde68-769a-468f-bb42-e5aece51c729.json diff --git a/.changes/next-release/feature-ddbdde68-769a-468f-bb42-e5aece51c729.json b/.changes/next-release/feature-ddbdde68-769a-468f-bb42-e5aece51c729.json new file mode 100644 index 0000000000..c2163d366b --- /dev/null +++ b/.changes/next-release/feature-ddbdde68-769a-468f-bb42-e5aece51c729.json @@ -0,0 +1,4 @@ +{ + "type" : "feature", + "description" : "Add image context support" +} \ No newline at end of file diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt index 548b8a0557..86c060103b 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt @@ -8,12 +8,7 @@ import com.google.gson.Gson import com.intellij.openapi.Disposable import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer -import com.intellij.ui.jcef.JBCefClient -import com.intellij.ui.jcef.JBCefJSQuery import org.cef.CefApp -import org.cef.browser.CefBrowser -import org.cef.callback.CefDragData -import org.cef.handler.CefDragHandler import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AwsServerCapabilitiesProvider import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.FlareUiMessage diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt index 439d8277a6..a1f76471c9 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt @@ -14,6 +14,17 @@ import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.options.ShowSettingsUtil import com.intellij.openapi.project.Project import com.intellij.ui.jcef.JBCefJSQuery.Response +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch import org.cef.browser.CefBrowser import org.eclipse.lsp4j.TextDocumentIdentifier import org.eclipse.lsp4j.jsonrpc.ResponseErrorException @@ -97,17 +108,6 @@ import software.aws.toolkits.telemetry.Telemetry import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletionException import java.util.function.Function -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.CompletableDeferred -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.merge -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch class BrowserConnector( private val serializer: MessageSerializer = MessageSerializer.getInstance(), diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/showOpenFileDialogParams.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/showOpenFileDialogParams.kt index 7bd075496d..af3acb54db 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/showOpenFileDialogParams.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/showOpenFileDialogParams.kt @@ -9,5 +9,5 @@ data class ShowOpenFileDialogParams( val canSelectMany: Boolean = false, val filters: Map> = emptyMap(), val defaultUri: String? = null, - val title: String? = null + val title: String? = null, ) From 4621012094dd75df6344c32d250093ce6764b799 Mon Sep 17 00:00:00 2001 From: Yang Zhang Date: Mon, 23 Jun 2025 22:41:13 -0700 Subject: [PATCH 4/6] pass the dropped files from Kotlin to webView --- .../amazonq/toolwindow/AmazonQPanel.kt | 107 +++++++++++++++++- .../services/amazonq/webview/Browser.kt | 29 ++++- 2 files changed, 130 insertions(+), 6 deletions(-) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt index 53323b638b..d41d4615c1 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt @@ -46,6 +46,11 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isCodeTrans import software.aws.toolkits.resources.message import java.util.concurrent.CompletableFuture import javax.swing.JButton +import java.awt.dnd.DropTarget +import java.awt.dnd.DropTargetDropEvent +import java.awt.datatransfer.DataFlavor +import com.google.gson.Gson +import java.util.Base64 class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Disposable { private val browser = CompletableFuture() @@ -122,12 +127,106 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di withContext(EDT) { browser.complete( - Browser(this@AmazonQPanel, webUri, project).also { - wrapper.setContent(it.component()) + Browser(this@AmazonQPanel, webUri, project).also { browserInstance -> + wrapper.setContent(browserInstance.component()) + + // Add DropTarget to the browser component + val dropTarget = object : DropTarget() { + override fun drop(dtde: DropTargetDropEvent) { + + try { + dtde.acceptDrop(dtde.dropAction) + val transferable = dtde.transferable + if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { + val fileList = transferable.getTransferData(DataFlavor.javaFileListFlavor) as List<*> + + val errorMessages = mutableListOf() + val validImages = mutableListOf() + val allowedTypes = setOf("jpg", "jpeg", "png", "gif", "webp") + val maxFileSize = 3.75 * 1024 * 1024 // 3.75MB in bytes + val maxDimension = 8000 + + for (file in fileList) { + val fileObj = file as? java.io.File ?: continue + val fileName = fileObj.name + val ext = fileName.substringAfterLast('.', "").lowercase() + + // File type restriction + if (ext !in allowedTypes) { + errorMessages.add("$fileName: File must be an image in JPEG, PNG, GIF, or WebP format.") + continue + } + + // Size restriction + if (fileObj.length() > maxFileSize) { + errorMessages.add("$fileName: Image must be no more than 3.75MB in size.") + continue + } + + // Width/Height restriction (only for image types) + try { + val img = javax.imageio.ImageIO.read(fileObj) + if (img == null) { + errorMessages.add("$fileName: File could not be read as an image.") + continue + } + if (img.width > maxDimension) { + errorMessages.add("$fileName: Image must be no more than 8,000px in width.") + continue + } + if (img.height > maxDimension) { + errorMessages.add("$fileName: Image must be no more than 8,000px in height.") + continue + } + } catch (e: Exception) { + errorMessages.add("$fileName: File could not be read as an image.") + continue + } + + validImages.add(fileObj) + } + + // File count restriction + if (validImages.size > 20) { + errorMessages.add("A maximum of 20 images can be added to a single message.") + validImages.subList(20, validImages.size).clear() + } + + + + val json = Gson().toJson(validImages).replace("\\", "\\\\").replace("'", "\\'") + browserInstance.jcefBrowser.cefBrowser.executeJavaScript( + "window.handleNativeDrop('$json')", + browserInstance.jcefBrowser.cefBrowser.url, + 0 + ) + + val errorJson = Gson().toJson(errorMessages).replace("\\", "\\\\").replace("'", "\\'") + browserInstance.jcefBrowser.cefBrowser.executeJavaScript( + "window.handleNativeNotify('$errorJson')", + browserInstance.jcefBrowser.cefBrowser.url, + 0 + ) + + } + dtde.dropComplete(true) + } catch (e: Exception) { + e.printStackTrace() + dtde.dropComplete(false) + } + } + } + + // Set DropTarget on the browser component and its children + browserInstance.component()?.let { component -> + component.dropTarget = dropTarget + // Also try setting on parent if needed + component.parent?.dropTarget = dropTarget + } initConnections() - connectUi(it) - connectApps(it) + connectUi(browserInstance) + connectApps(browserInstance) loadingPanel.stopLoading() } diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt index 86c060103b..d8a61690fb 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt @@ -8,6 +8,7 @@ import com.google.gson.Gson import com.intellij.openapi.Disposable import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer +import com.intellij.ui.jcef.JBCefJSQuery import org.cef.CefApp import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AwsServerCapabilitiesProvider @@ -124,7 +125,7 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project) """.trimIndent() From eb596bd19945b9a7423af5db2c2f606a34214b29 Mon Sep 17 00:00:00 2001 From: Yaofu Zuo Date: Wed, 25 Jun 2025 14:03:50 -0700 Subject: [PATCH 5/6] use params to select different file descriptor --- .../amazonq/toolwindow/AmazonQPanel.kt | 15 ++--- .../amazonq/lsp/AmazonQLanguageClientImpl.kt | 67 +++++++++++++++++-- .../aws/chat/showOpenFileDialogParams.kt | 1 - 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt index d41d4615c1..8dff7f3ce2 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt @@ -3,6 +3,7 @@ package software.aws.toolkits.jetbrains.services.amazonq.toolwindow +import com.google.gson.Gson import com.intellij.idea.AppMode import com.intellij.openapi.Disposable import com.intellij.openapi.components.service @@ -44,13 +45,11 @@ import software.aws.toolkits.jetbrains.services.amazonqDoc.auth.isDocAvailable import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.auth.isFeatureDevAvailable import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isCodeTransformAvailable import software.aws.toolkits.resources.message -import java.util.concurrent.CompletableFuture -import javax.swing.JButton +import java.awt.datatransfer.DataFlavor import java.awt.dnd.DropTarget import java.awt.dnd.DropTargetDropEvent -import java.awt.datatransfer.DataFlavor -import com.google.gson.Gson -import java.util.Base64 +import java.util.concurrent.CompletableFuture +import javax.swing.JButton class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Disposable { private val browser = CompletableFuture() @@ -133,7 +132,6 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di // Add DropTarget to the browser component val dropTarget = object : DropTarget() { override fun drop(dtde: DropTargetDropEvent) { - try { dtde.acceptDrop(dtde.dropAction) val transferable = dtde.transferable @@ -192,8 +190,6 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di validImages.subList(20, validImages.size).clear() } - - val json = Gson().toJson(validImages).replace("\\", "\\\\").replace("'", "\\'") browserInstance.jcefBrowser.cefBrowser.executeJavaScript( "window.handleNativeDrop('$json')", @@ -207,7 +203,6 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di browserInstance.jcefBrowser.cefBrowser.url, 0 ) - } dtde.dropComplete(true) } catch (e: Exception) { @@ -216,7 +211,7 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di } } } - + // Set DropTarget on the browser component and its children browserInstance.component()?.let { component -> component.dropTarget = dropTarget diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt index a0fa8365c7..025138ef4d 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQLanguageClientImpl.kt @@ -255,13 +255,68 @@ class AmazonQLanguageClientImpl(private val project: Project) : AmazonQLanguageC override fun showOpenFileDialog(params: ShowOpenFileDialogParams): CompletableFuture { return CompletableFuture.supplyAsync( { - val descriptor = if (params.canSelectMany) { - FileChooserDescriptorFactory.createMultipleFilesNoJarsDescriptor().apply { - title = "Select Files" - description = "Choose files to open" + // Handle the case where both canSelectFiles and canSelectFolders are false (should never be sent from flare) + if (!params.canSelectFiles && !params.canSelectFolders) { + return@supplyAsync mapOf("uris" to emptyList()) as LSPAny + } + + val descriptor = when { + params.canSelectFolders && params.canSelectFiles -> { + if (params.canSelectMany) { + FileChooserDescriptorFactory.createSingleFileOrFolderDescriptor() + } else { + FileChooserDescriptorFactory.createAllButJarContentsDescriptor() + } + } + params.canSelectFolders -> { + if (params.canSelectMany) { + FileChooserDescriptorFactory.createMultipleFoldersDescriptor() + } else { + FileChooserDescriptorFactory.createSingleFolderDescriptor() + } + } + else -> { + if (params.canSelectMany) { + FileChooserDescriptorFactory.createMultipleFilesNoJarsDescriptor() + } else { + FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor() + } + } + }.apply { + withTitle( + params.title ?: when { + params.canSelectFolders && params.canSelectFiles -> "Select Files or Folders" + params.canSelectFolders -> "Select Folders" + else -> "Select Files" + } + ) + withDescription( + when { + params.canSelectFolders && params.canSelectFiles -> "Choose files or folders to open" + params.canSelectFolders -> "Choose folders to open" + else -> "Choose files to open" + } + ) + + // Apply file filters if provided + if (params.filters.isNotEmpty() && !params.canSelectFolders) { + // Create a combined list of all allowed extensions + val allowedExtensions = params.filters.values.flatten() + .map { pattern -> + // Convert patterns like "*.jpg" to "jpg" + pattern.removePrefix("*.").lowercase() + } + .toSet() + + withFileFilter { virtualFile -> + if (virtualFile.isDirectory) { + true // Always allow directories for navigation + } else { + val extension = virtualFile.extension?.lowercase() + extension != null && allowedExtensions.contains(extension) + } + } } - } else { - FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor() } val chosenFiles = FileChooser.chooseFiles(descriptor, project, null) diff --git a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/showOpenFileDialogParams.kt b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/showOpenFileDialogParams.kt index af3acb54db..204160bf3b 100644 --- a/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/showOpenFileDialogParams.kt +++ b/plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/model/aws/chat/showOpenFileDialogParams.kt @@ -8,6 +8,5 @@ data class ShowOpenFileDialogParams( val canSelectFolders: Boolean = false, val canSelectMany: Boolean = false, val filters: Map> = emptyMap(), - val defaultUri: String? = null, val title: String? = null, ) From 3df8ef9752fb0090c41a4c787745d375a6a0a461 Mon Sep 17 00:00:00 2001 From: Yang Zhang Date: Wed, 25 Jun 2025 16:17:19 -0700 Subject: [PATCH 6/6] add feature flag --- .../amazonq/toolwindow/AmazonQPanel.kt | 23 +++++++++++++++---- .../services/amazonq/webview/Browser.kt | 4 ++-- .../lsp/model/ExtendedClientMetadata.kt | 2 ++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt index 8dff7f3ce2..571f337907 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt @@ -21,6 +21,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import software.aws.toolkits.core.utils.getLogger import software.aws.toolkits.jetbrains.core.coroutines.EDT import software.aws.toolkits.jetbrains.isDeveloperMode import software.aws.toolkits.jetbrains.services.amazonq.apps.AmazonQAppInitContext @@ -47,9 +48,12 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isCodeTrans import software.aws.toolkits.resources.message import java.awt.datatransfer.DataFlavor import java.awt.dnd.DropTarget +import java.awt.dnd.DropTargetDragEvent import java.awt.dnd.DropTargetDropEvent +import java.awt.dnd.DropTargetEvent import java.util.concurrent.CompletableFuture import javax.swing.JButton +import javax.imageio.ImageIO.read class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Disposable { private val browser = CompletableFuture() @@ -163,7 +167,7 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di // Width/Height restriction (only for image types) try { - val img = javax.imageio.ImageIO.read(fileObj) + val img = read(fileObj) if (img == null) { errorMessages.add("$fileName: File could not be read as an image.") continue @@ -190,23 +194,26 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di validImages.subList(20, validImages.size).clear() } - val json = Gson().toJson(validImages).replace("\\", "\\\\").replace("'", "\\'") + val json = Gson().toJson(validImages) browserInstance.jcefBrowser.cefBrowser.executeJavaScript( "window.handleNativeDrop('$json')", browserInstance.jcefBrowser.cefBrowser.url, 0 ) - val errorJson = Gson().toJson(errorMessages).replace("\\", "\\\\").replace("'", "\\'") + val errorJson = Gson().toJson(errorMessages) browserInstance.jcefBrowser.cefBrowser.executeJavaScript( "window.handleNativeNotify('$errorJson')", browserInstance.jcefBrowser.cefBrowser.url, 0 ) + + dtde.dropComplete(true) + } else { + dtde.dropComplete(false) } - dtde.dropComplete(true) } catch (e: Exception) { - e.printStackTrace() + LOG.error("Failed to handle file drop operation", e.message) dtde.dropComplete(false) } } @@ -305,6 +312,12 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di } } + companion object { + private val LOG = getLogger() + + fun getInstance(project: Project) = project.service() + } + override fun dispose() { } } diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt index d8a61690fb..1382465dc5 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt @@ -125,7 +125,7 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project)