Skip to content

Commit 2c416b2

Browse files
Merge main into feature/disable-sspc
2 parents 659855d + 161bf13 commit 2c416b2

File tree

15 files changed

+57
-279
lines changed

15 files changed

+57
-279
lines changed

.changes/next-release/feature-c8e68d82-96e3-4043-9fd5-4fa97fc00fe6.json

Lines changed: 0 additions & 4 deletions
This file was deleted.

.changes/next-release/feature-ddbdde68-769a-468f-bb42-e5aece51c729.json

Lines changed: 0 additions & 4 deletions
This file was deleted.

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt

Lines changed: 4 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
package software.aws.toolkits.jetbrains.services.amazonq.toolwindow
55

6-
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
76
import com.intellij.idea.AppMode
87
import com.intellij.openapi.Disposable
98
import com.intellij.openapi.components.service
@@ -21,8 +20,6 @@ import kotlinx.coroutines.CoroutineScope
2120
import kotlinx.coroutines.flow.first
2221
import kotlinx.coroutines.launch
2322
import kotlinx.coroutines.withContext
24-
import software.aws.toolkits.core.utils.error
25-
import software.aws.toolkits.core.utils.getLogger
2623
import software.aws.toolkits.jetbrains.core.coroutines.EDT
2724
import software.aws.toolkits.jetbrains.isDeveloperMode
2825
import software.aws.toolkits.jetbrains.services.amazonq.apps.AmazonQAppInitContext
@@ -47,12 +44,7 @@ import software.aws.toolkits.jetbrains.services.amazonqDoc.auth.isDocAvailable
4744
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.auth.isFeatureDevAvailable
4845
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isCodeTransformAvailable
4946
import software.aws.toolkits.resources.message
50-
import java.awt.datatransfer.DataFlavor
51-
import java.awt.dnd.DropTarget
52-
import java.awt.dnd.DropTargetDropEvent
53-
import java.io.File
5447
import java.util.concurrent.CompletableFuture
55-
import javax.imageio.ImageIO.read
5648
import javax.swing.JButton
5749

5850
class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Disposable {
@@ -130,76 +122,12 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di
130122

131123
withContext(EDT) {
132124
browser.complete(
133-
Browser(this@AmazonQPanel, webUri, project).also { browserInstance ->
134-
wrapper.setContent(browserInstance.component())
135-
136-
// Add DropTarget to the browser component
137-
// JCEF does not propagate OS-level dragenter, dragOver and drop into DOM.
138-
// As an alternative, enabling the native drag in JCEF,
139-
// and let the native handling the drop event, and update the UI through JS bridge.
140-
val dropTarget = object : DropTarget() {
141-
override fun drop(dtde: DropTargetDropEvent) {
142-
try {
143-
dtde.acceptDrop(dtde.dropAction)
144-
val transferable = dtde.transferable
145-
if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
146-
val fileList = transferable.getTransferData(DataFlavor.javaFileListFlavor) as List<*>
147-
148-
val errorMessages = mutableListOf<String>()
149-
val validImages = mutableListOf<File>()
150-
val allowedTypes = setOf("jpg", "jpeg", "png", "gif", "webp")
151-
val maxFileSize = 3.75 * 1024 * 1024 // 3.75MB in bytes
152-
val maxDimension = 8000
153-
154-
for (file in fileList as List<File>) {
155-
val validationResult = validateImageFile(file, allowedTypes, maxFileSize, maxDimension)
156-
if (validationResult != null) {
157-
errorMessages.add(validationResult)
158-
} else {
159-
validImages.add(file)
160-
}
161-
}
162-
163-
// File count restriction
164-
if (validImages.size > 20) {
165-
errorMessages.add("A maximum of 20 images can be added to a single message.")
166-
validImages.subList(20, validImages.size).clear()
167-
}
168-
169-
val json = OBJECT_MAPPER.writeValueAsString(validImages)
170-
browserInstance.jcefBrowser.cefBrowser.executeJavaScript(
171-
"window.handleNativeDrop('$json')",
172-
browserInstance.jcefBrowser.cefBrowser.url,
173-
0
174-
)
175-
176-
val errorJson = OBJECT_MAPPER.writeValueAsString(errorMessages)
177-
browserInstance.jcefBrowser.cefBrowser.executeJavaScript(
178-
"window.handleNativeNotify('$errorJson')",
179-
browserInstance.jcefBrowser.cefBrowser.url,
180-
0
181-
)
182-
dtde.dropComplete(true)
183-
} else {
184-
dtde.dropComplete(false)
185-
}
186-
} catch (e: Exception) {
187-
LOG.error { "Failed to handle file drop operation: ${e.message}" }
188-
dtde.dropComplete(false)
189-
}
190-
}
191-
}
192-
193-
// Set DropTarget on the browser component and its children
194-
browserInstance.component()?.let { component ->
195-
component.dropTarget = dropTarget
196-
// Also try setting on parent if needed
197-
component.parent?.dropTarget = dropTarget
198-
}
125+
Browser(this@AmazonQPanel, webUri, project).also {
126+
wrapper.setContent(it.component())
199127

200128
initConnections()
201-
connectUi(browserInstance)
202-
connectApps(browserInstance)
129+
connectUi(it)
130+
connectApps(it)
203131

204132
loadingPanel.stopLoading()
205133
}
@@ -283,36 +211,6 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di
283211
}
284212
}
285213

286-
private fun validateImageFile(file: File, allowedTypes: Set<String>, maxFileSize: Double, maxDimension: Int): String? {
287-
val fileName = file.name
288-
val ext = fileName.substringAfterLast('.', "").lowercase()
289-
290-
if (ext !in allowedTypes) {
291-
return "$fileName: File must be an image in JPEG, PNG, GIF, or WebP format."
292-
}
293-
294-
if (file.length() > maxFileSize) {
295-
return "$fileName: Image must be no more than 3.75MB in size."
296-
}
297-
298-
return try {
299-
val img = read(file)
300-
when {
301-
img == null -> "$fileName: File could not be read as an image."
302-
img.width > maxDimension -> "$fileName: Image must be no more than 8,000px in width."
303-
img.height > maxDimension -> "$fileName: Image must be no more than 8,000px in height."
304-
else -> null
305-
}
306-
} catch (e: Exception) {
307-
"$fileName: File could not be read as an image."
308-
}
309-
}
310-
311-
companion object {
312-
private val LOG = getLogger<AmazonQPanel>()
313-
private val OBJECT_MAPPER = jacksonObjectMapper()
314-
}
315-
316214
override fun dispose() {
317215
}
318216
}

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,6 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project)
8585
// setup empty state. The message request handlers use this for storing state
8686
// that's persistent between page loads.
8787
jcefBrowser.setProperty("state", "")
88-
jcefBrowser.jbCefClient.addDragHandler({ browser, dragData, mask ->
89-
true // Allow drag operations
90-
}, jcefBrowser.cefBrowser)
9188
// load the web app
9289
jcefBrowser.loadHTML(
9390
getWebviewHTML(
@@ -125,7 +122,7 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project)
125122
<script type="text/javascript" charset="UTF-8" src="$webUri" defer onload="init()"></script>
126123
127124
<script type="text/javascript">
128-
125+
129126
const init = () => {
130127
const hybridChatConnector = connectorAdapter.initiateAdapter(
131128
${MeetQSettings.getInstance().reinvent2024OnboardingCount < MAX_ONBOARDING_PAGE_COUNT},
@@ -142,7 +139,7 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project)
142139
},
143140
144141
"${activeProfile?.profileName.orEmpty()}")
145-
const qChat = amazonQChat.createChat(
142+
amazonQChat.createChat(
146143
{
147144
postMessage: message => {
148145
$postMessageToJavaJsCode
@@ -158,29 +155,6 @@ class Browser(parent: Disposable, private val webUri: URI, val project: Project)
158155
hybridChatConnector,
159156
${CodeWhispererFeatureConfigService.getInstance().getFeatureConfigJsonString()}
160157
);
161-
162-
window.handleNativeDrop = function(filePath) {
163-
const parsedFilePath = JSON.parse(filePath);
164-
const contextArray = parsedFilePath.map(fullPath => {
165-
const fileName = fullPath.split(/[\\/]/).pop();
166-
return {
167-
command: fileName,
168-
label: 'image',
169-
route: [fullPath],
170-
description: fullPath
171-
};
172-
});
173-
qChat.addCustomContextToPrompt(qChat.getSelectedTabId(), contextArray);
174-
};
175-
176-
window.handleNativeNotify = function(errorMessages) {
177-
const messages = JSON.parse(errorMessages);
178-
messages.forEach(msg => {
179-
qChat.notify({
180-
content: msg
181-
})
182-
});
183-
};
184158
}
185159
</script>
186160
""".trimIndent()

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,6 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.GetSe
7777
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LIST_MCP_SERVERS_REQUEST_METHOD
7878
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LIST_RULES_REQUEST_METHOD
7979
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.MCP_SERVER_CLICK_REQUEST_METHOD
80-
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_FILE_DIALOG
81-
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_FILE_DIALOG_REQUEST_METHOD
8280
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_SETTINGS
8381
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_WORKSPACE_SETTINGS_KEY
8482
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OpenSettingsNotification
@@ -491,19 +489,6 @@ class BrowserConnector(
491489
)
492490
}
493491
}
494-
495-
OPEN_FILE_DIALOG -> {
496-
handleChat(AmazonQChatServer.showOpenFileDialog, node)
497-
.whenComplete { response, _ ->
498-
browser.postChat(
499-
FlareUiMessage(
500-
command = OPEN_FILE_DIALOG_REQUEST_METHOD,
501-
params = response
502-
)
503-
)
504-
}
505-
}
506-
507492
LIST_RULES_REQUEST_METHOD -> {
508493
handleChat(AmazonQChatServer.listRules, node)
509494
.whenComplete { response, _ ->

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/commands/ActionRegistrar.kt

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
@file:Suppress("BannedImports")
44
package software.aws.toolkits.jetbrains.services.cwc.commands
55

6+
import com.google.gson.Gson
67
import com.intellij.openapi.application.ApplicationManager
78
import com.intellij.openapi.project.Project
89
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -16,6 +17,7 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SEND_
1617
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SendToPromptParams
1718
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TriggerType
1819
import software.aws.toolkits.jetbrains.services.amazonq.messages.AmazonQMessage
20+
import software.aws.toolkits.jetbrains.services.amazonqCodeTest.controller.TestCommandMessage
1921
import software.aws.toolkits.jetbrains.services.cwc.editor.context.ActiveFileContextExtractor
2022
import software.aws.toolkits.jetbrains.services.cwc.editor.context.ExtractionTriggerType
2123

@@ -26,21 +28,25 @@ class ActionRegistrar {
2628
val flow = _messages.asSharedFlow()
2729

2830
fun reportMessageClick(command: EditorContextCommand, project: Project) {
29-
// new agentic chat route
30-
ApplicationManager.getApplication().executeOnPooledThread {
31-
runBlocking {
32-
val contextExtractor = ActiveFileContextExtractor.create(fqnWebviewAdapter = null, project = project)
33-
val fileContext = contextExtractor.extractContextForTrigger(ExtractionTriggerType.ContextMenu)
34-
val codeSelection = "\n```\n${fileContext.focusAreaContext?.codeSelection?.trimIndent()?.trim()}\n```\n"
35-
var uiMessage: FlareUiMessage? = null
36-
if (command.verb != SEND_TO_PROMPT) {
37-
val params = GenericCommandParams(selection = codeSelection, triggerType = TriggerType.CONTEXT_MENU, genericCommand = command.name)
38-
uiMessage = FlareUiMessage(command = GENERIC_COMMAND, params = params)
39-
} else {
40-
val params = SendToPromptParams(selection = codeSelection, triggerType = TriggerType.CONTEXT_MENU)
41-
uiMessage = FlareUiMessage(command = SEND_TO_PROMPT, params = params)
31+
if (command == EditorContextCommand.GenerateUnitTests) {
32+
AsyncChatUiListener.notifyPartialMessageUpdate(project, Gson().toJson(TestCommandMessage()))
33+
} else {
34+
// new agentic chat route
35+
ApplicationManager.getApplication().executeOnPooledThread {
36+
runBlocking {
37+
val contextExtractor = ActiveFileContextExtractor.create(fqnWebviewAdapter = null, project = project)
38+
val fileContext = contextExtractor.extractContextForTrigger(ExtractionTriggerType.ContextMenu)
39+
val codeSelection = "\n```\n${fileContext.focusAreaContext?.codeSelection?.trimIndent()?.trim()}\n```\n"
40+
var uiMessage: FlareUiMessage? = null
41+
if (command.verb != SEND_TO_PROMPT) {
42+
val params = GenericCommandParams(selection = codeSelection, triggerType = TriggerType.CONTEXT_MENU, genericCommand = command.name)
43+
uiMessage = FlareUiMessage(command = GENERIC_COMMAND, params = params)
44+
} else {
45+
val params = SendToPromptParams(selection = codeSelection, triggerType = TriggerType.CONTEXT_MENU)
46+
uiMessage = FlareUiMessage(command = SEND_TO_PROMPT, params = params)
47+
}
48+
AsyncChatUiListener.notifyPartialMessageUpdate(project, uiMessage)
4249
}
43-
AsyncChatUiListener.notifyPartialMessageUpdate(project, uiMessage)
4450
}
4551
}
4652
}

plugins/amazonq/mynah-ui/src/mynah-ui/ui/quickActions/generator.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export class QuickActionGenerator {
3838

3939
const quickActionCommands = [
4040
{
41+
groupName: `Q Developer Agent for <b>Software Development</b>`,
4142
commands: [
4243
...(this.isFeatureDevEnabled
4344
? [
@@ -77,6 +78,11 @@ export class QuickActionGenerator {
7778
},
7879
]
7980
: []),
81+
],
82+
},
83+
{
84+
groupName: `Q Developer Agent for <b>Code Transformation</b>`,
85+
commands:[
8086
...(this.isCodeTransformEnabled
8187
? [
8288
{
@@ -87,7 +93,22 @@ export class QuickActionGenerator {
8793
]
8894
: []),
8995
],
90-
}
96+
},
97+
{
98+
groupName: 'Quick Actions',
99+
commands: [
100+
{
101+
command: '/help',
102+
icon: MynahIcons.HELP,
103+
description: 'Learn more about Amazon Q',
104+
},
105+
{
106+
command: '/clear',
107+
icon: MynahIcons.TRASH,
108+
description: 'Clear this session',
109+
},
110+
],
111+
},
91112
].filter((section) => section.commands.length > 0)
92113

93114
const commandUnavailability: Record<

plugins/amazonq/mynah-ui/src/mynah-ui/ui/quickActions/handler.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,14 @@ private handleDocCommand(chatPrompt: ChatPrompt, tabID: string, taskName: string
344344
this.connector.startTestGen(testTabId, realPromptText)
345345
return
346346
}
347-
347+
/**
348+
* right click -> generate test has no tab id
349+
* we have to manually create one if a testgen tab
350+
* wasn't previously created
351+
*/
352+
if (!tabID) {
353+
tabID = this.mynahUI?.updateStore('', {})
354+
}
348355
const affectedTabId: string | undefined = this.addTab(tabID)
349356

350357
// if there is no test tab, open a new one

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/lsp/AmazonQChatServer.kt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LIST_
4545
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.LinkClickParams
4646
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.ListConversationsParams
4747
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.MCP_SERVER_CLICK_REQUEST_METHOD
48-
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.OPEN_FILE_DIALOG_REQUEST_METHOD
4948
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PROMPT_INPUT_OPTIONS_CHANGE
5049
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.PromptInputOptionChangeParams
5150
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.RULE_CLICK_REQUEST_METHOD
@@ -249,10 +248,4 @@ object AmazonQChatServer : JsonRpcMethodProvider {
249248
TELEMETRY_EVENT,
250249
Any::class.java
251250
)
252-
253-
val showOpenFileDialog = JsonRpcRequest(
254-
OPEN_FILE_DIALOG_REQUEST_METHOD,
255-
Any::class.java,
256-
LSPAny::class.java
257-
)
258251
}

0 commit comments

Comments
 (0)