-
Notifications
You must be signed in to change notification settings - Fork 251
Add support for Amazon Q chat on remote 242+ #4825
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
47706df
7f82602
1c06ff9
a2e4042
9f37025
4f4e3d2
9c49a0a
f46f20d
205251b
6257981
5ac379e
f94e290
f9fa72e
c1b9d17
baa8e8c
b7a8e2c
f5bb9bb
5f1a27a
fa2353e
e164b90
a878739
3a3671b
cc47655
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,10 +7,11 @@ | |
import com.intellij.openapi.Disposable | ||
import com.intellij.openapi.util.Disposer | ||
import com.intellij.ui.jcef.JBCefJSQuery | ||
import org.cef.CefApp | ||
import software.aws.toolkits.jetbrains.core.webview.LocalAssetJBCefRequestHandler | ||
import software.aws.toolkits.jetbrains.services.amazonq.util.HighlightCommand | ||
import software.aws.toolkits.jetbrains.services.amazonq.util.createBrowser | ||
import software.aws.toolkits.jetbrains.settings.MeetQSettings | ||
import java.nio.file.Paths | ||
|
||
/* | ||
Displays the web view for the Amazon Q tool window | ||
|
@@ -21,6 +22,17 @@ | |
|
||
val receiveMessageQuery = JBCefJSQuery.create(jcefBrowser) | ||
|
||
private val assetRequestHandler = LocalAssetJBCefRequestHandler(jcefBrowser) | ||
Check warning on line 25 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt
|
||
|
||
init { | ||
assetRequestHandler.addWildcardHandler("mynah") { path -> | ||
val asset = path.replaceFirst("mynah/", "/mynah-ui/assets/") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we test this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. follow up later |
||
Paths.get(asset).normalize().toString().let { | ||
this::class.java.getResourceAsStream(it) | ||
} | ||
Check warning on line 32 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt
|
||
} | ||
} | ||
Check warning on line 34 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt
|
||
|
||
fun init( | ||
isCodeTransformAvailable: Boolean, | ||
isFeatureDevAvailable: Boolean, | ||
|
@@ -29,15 +41,7 @@ | |
isCodeTestAvailable: Boolean, | ||
highlightCommand: HighlightCommand?, | ||
) { | ||
// register the scheme handler to route http://mynah/ URIs to the resources/assets directory on classpath | ||
CefApp.getInstance() | ||
.registerSchemeHandlerFactory( | ||
"http", | ||
"mynah", | ||
AssetResourceHandler.AssetResourceHandlerFactory(), | ||
) | ||
|
||
loadWebView(isCodeTransformAvailable, isFeatureDevAvailable, isDocAvailable, isCodeScanAvailable, isCodeTestAvailable, highlightCommand) | ||
Check warning on line 44 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt
|
||
} | ||
|
||
override fun dispose() { | ||
|
@@ -63,9 +67,13 @@ | |
// setup empty state. The message request handlers use this for storing state | ||
// that's persistent between page loads. | ||
jcefBrowser.setProperty("state", "") | ||
|
||
// load the web app | ||
jcefBrowser.loadHTML( | ||
getWebviewHTML(isCodeTransformAvailable, isFeatureDevAvailable, isDocAvailable, isCodeScanAvailable, isCodeTestAvailable, highlightCommand) | ||
jcefBrowser.loadURL( | ||
assetRequestHandler.createResource( | ||
"webview/chat.html", | ||
getWebviewHTML(isCodeTransformAvailable, isFeatureDevAvailable, isDocAvailable, isCodeScanAvailable, isCodeTestAvailable, highlightCommand) | ||
Check warning on line 75 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt
|
||
) | ||
) | ||
} | ||
|
||
|
@@ -84,7 +92,7 @@ | |
val postMessageToJavaJsCode = receiveMessageQuery.inject("JSON.stringify(message)") | ||
|
||
val jsScripts = """ | ||
<script type="text/javascript" src="$WEB_SCRIPT_URI" defer onload="init()"></script> | ||
<script type="text/javascript" src="http://toolkitasset/mynah/js/mynah-ui.js" defer onload="init()"></script> | ||
<script type="text/javascript"> | ||
const init = () => { | ||
mynahUI.createMynahUI( | ||
|
@@ -94,13 +102,13 @@ | |
} | ||
}, | ||
${MeetQSettings.getInstance().reinvent2024OnboardingCount < MAX_ONBOARDING_PAGE_COUNT}, | ||
${MeetQSettings.getInstance().disclaimerAcknowledged}, | ||
Check warning on line 105 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt
|
||
$isFeatureDevAvailable, // whether /dev is available | ||
$isCodeTransformAvailable, // whether /transform is available | ||
$isDocAvailable, // whether /doc is available | ||
$isCodeScanAvailable, // whether /scan is available | ||
$isCodeTestAvailable, // whether /test is available | ||
${OBJECT_MAPPER.writeValueAsString(highlightCommand)} | ||
Check warning on line 111 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt
|
||
); | ||
} | ||
</script> | ||
|
@@ -120,8 +128,7 @@ | |
} | ||
|
||
companion object { | ||
private const val WEB_SCRIPT_URI = "http://mynah/js/mynah-ui.js" | ||
private const val MAX_ONBOARDING_PAGE_COUNT = 3 | ||
private val OBJECT_MAPPER = jacksonObjectMapper() | ||
Check warning on line 132 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/Browser.kt
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
@file:Suppress("all") | ||
|
||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. | ||
// adapted from https://github.com/JetBrains/intellij-community/blob/54429f3ba00c695c22d09e164135b0713f2cfc0f/platform/ui.jcef/jcef/utils/JBCefLocalRequestHandler.kt | ||
|
||
package contrib.org.intellij.images.editor.impl.jcef | ||
|
||
import org.cef.browser.CefBrowser | ||
import org.cef.browser.CefFrame | ||
import org.cef.callback.CefCallback | ||
import org.cef.handler.CefRequestHandlerAdapter | ||
import org.cef.handler.CefResourceHandler | ||
import org.cef.handler.CefResourceHandlerAdapter | ||
import org.cef.handler.CefResourceRequestHandler | ||
import org.cef.handler.CefResourceRequestHandlerAdapter | ||
import org.cef.misc.BoolRef | ||
import org.cef.network.CefRequest | ||
import java.net.URL | ||
|
||
/** | ||
* Handles local protocol-specific CEF resource requests for a defined `protocol` and `authority`. | ||
* | ||
* This class implements a mechanism to serve protocol-specific resources based on mappings provided | ||
* through the `addResource` function. Only requests matching the configured protocol and authority are processed, | ||
* while others are rejected. | ||
* | ||
* @param myProtocol The protocol to handle (e.g., "http", "file"). | ||
* @param myAuthority The authority of the requests (e.g., "localhost", "mydomain"). | ||
*/ | ||
open class JBCefLocalRequestHandler( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can this be used directly? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a straight copy from jetbrains so we should keep it slim to make it easy to copy over any changes later |
||
private val myProtocol: String, | ||
private val myAuthority: String, | ||
) : CefRequestHandlerAdapter() { | ||
private val myResources: MutableMap<String, () -> CefResourceHandler?> = HashMap() | ||
|
||
private val REJECTING_RESOURCE_HANDLER: CefResourceHandler = object : CefResourceHandlerAdapter() { | ||
Check notice on line 36 in plugins/core/jetbrains-community/src/contrib/org/intellij/images/editor/impl/jcef/JBCefLocalRequestHandler.kt
|
||
Check noticeCode scanning / QDJVMC Private property naming convention Note
Private property name REJECTING_RESOURCE_HANDLER should not contain underscores in the middle or the end
|
||
override fun processRequest(request: CefRequest, callback: CefCallback): Boolean { | ||
callback.cancel() | ||
return false | ||
} | ||
} | ||
|
||
private val RESOURCE_REQUEST_HANDLER = resourceHandlerWrapper { path -> | ||
Check notice on line 43 in plugins/core/jetbrains-community/src/contrib/org/intellij/images/editor/impl/jcef/JBCefLocalRequestHandler.kt
|
||
Check noticeCode scanning / QDJVMC Private property naming convention Note
Private property name RESOURCE_REQUEST_HANDLER should not contain underscores in the middle or the end
|
||
myResources[path]?.let { it() } | ||
} | ||
|
||
protected fun resourceHandlerWrapper(handler: (String) -> CefResourceHandler?): CefResourceRequestHandler = | ||
object : CefResourceRequestHandlerAdapter() { | ||
override fun getResourceHandler(browser: CefBrowser?, frame: CefFrame?, request: CefRequest): CefResourceHandler { | ||
val url = URL(request.url) | ||
url.protocol | ||
if (!url.protocol.equals(myProtocol) || !url.authority.equals(myAuthority)) { | ||
return REJECTING_RESOURCE_HANDLER | ||
} | ||
return try { | ||
val path = url.path.trim('/') | ||
handler(path) ?: REJECTING_RESOURCE_HANDLER | ||
} catch (e: RuntimeException) { | ||
println(e.message) | ||
REJECTING_RESOURCE_HANDLER | ||
} | ||
} | ||
} | ||
|
||
fun addResource(resourcePath: String, resourceProvider: () -> CefResourceHandler?) { | ||
val normalisedPath = resourcePath.trim('/') | ||
myResources[normalisedPath] = resourceProvider | ||
} | ||
|
||
fun createResource(resourcePath: String, resourceProvider: () -> CefResourceHandler?): String { | ||
val normalisedPath = resourcePath.trim('/') | ||
myResources[normalisedPath] = resourceProvider | ||
return "$myProtocol://$myAuthority/$normalisedPath" | ||
} | ||
|
||
override fun getResourceRequestHandler( | ||
browser: CefBrowser?, | ||
frame: CefFrame?, | ||
request: CefRequest?, | ||
isNavigation: Boolean, | ||
isDownload: Boolean, | ||
requestInitiator: String?, | ||
disableDefaultHandling: BoolRef?, | ||
): CefResourceRequestHandler { | ||
return RESOURCE_REQUEST_HANDLER | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can we assign the file names to consts