From 9879d4029b251074df1571780d50f507e392402b Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Fri, 15 Sep 2023 10:23:00 -0500 Subject: [PATCH 1/9] Shortcircuit if no id or email --- .../context/toolWindow/MyToolWindowFactory.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt index 3e86980..3ad2061 100644 --- a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt +++ b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt @@ -179,8 +179,6 @@ class MyToolWindowFactory : ToolWindowFactory { } val commitMessages = commitHashes?.map { commitHash -> commitHash.message } ?: listOf() - val apiResponse = makeApiCall(commitMessages, email, id) - val data = apiResponse?.get("data")?.jsonObject val commitList = commitHashes?.map { commitHash -> ServiceData( @@ -190,6 +188,16 @@ class MyToolWindowFactory : ToolWindowFactory { }!! servicePanels = servicePanels + (setupServiceUI(commitList, "Commits")) + if (email.isNullOrEmpty() && !id.isNullOrEmpty()) { + servicePanels.forEach { servicePanel -> + mainPanel.add(servicePanel) + } + + return JBScrollPane(mainPanel) + } + + val apiResponse = makeApiCall(commitMessages, email, id) + val data = apiResponse?.get("data")?.jsonObject val serviceNames = data?.keys?.asSequence()?.map { key: String -> key }?.toList() if (serviceNames != null) { for (serviceName in serviceNames) { From 459f6041d771f2f7cc29f8d69694ecdf528d2bf6 Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Fri, 15 Sep 2023 10:40:18 -0500 Subject: [PATCH 2/9] Extract duplicated function --- .../context/toolWindow/MyToolWindowFactory.kt | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt index 3ad2061..31bef9f 100644 --- a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt +++ b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt @@ -24,7 +24,7 @@ class MyToolWindowFactory : ToolWindowFactory { data class ServiceData(val title: String, val body: String, val link: String? = null) - fun createToolWindowContent(project: Project, toolWindow: ToolWindow, startLine: Int, endLine: Int) { + private fun createContent(project: Project, toolWindow: ToolWindow, startLine: Int = 0, endLine: Int = 0) { // this only runs once val myToolWindow = MyToolWindow(toolWindow) val content = @@ -33,14 +33,12 @@ class MyToolWindowFactory : ToolWindowFactory { toolWindow.contentManager.addContent(content) } - override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { + fun createToolWindowContent(project: Project, toolWindow: ToolWindow, startLine: Int, endLine: Int) { + createContent(project, toolWindow, startLine, endLine) + } - // this only runs once - val myToolWindow = MyToolWindow(toolWindow) - val content = - ContentFactory.getInstance().createContent(myToolWindow.getContent(), null, false) - toolWindow.contentManager.removeAllContents(true) - toolWindow.contentManager.addContent(content) + override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { + createContent(project, toolWindow) } override fun shouldBeAvailable(project: Project) = true From dd3d500fdb1677df933ed34a314ec60b2f655649 Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Fri, 15 Sep 2023 10:40:32 -0500 Subject: [PATCH 3/9] Code improvements --- .../watermelon/context/toolWindow/MyToolWindowFactory.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt index 31bef9f..bc45e06 100644 --- a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt +++ b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt @@ -206,9 +206,8 @@ class MyToolWindowFactory : ToolWindowFactory { is JsonArray -> { if (serviceData.isEmpty()) { - val commitPanel = setupServiceUI(emptyList(), serviceName) - servicePanels = servicePanels + (commitPanel) - add(commitPanel) + val servicePanel = setupServiceUI(emptyList(), serviceName) + servicePanels = servicePanels + (servicePanel) } else { val returnArray = serviceData.map { serviceDataElement -> @@ -230,7 +229,7 @@ class MyToolWindowFactory : ToolWindowFactory { val message = serviceData.content if (message.contains(Regex("no .* token"))) { - servicePanels = servicePanels + (setupServiceUI(emptyList(), serviceName ?: "")) + servicePanels = servicePanels + (setupServiceUI(emptyList(), serviceName)) } } From cf249c60b583a5a94be368a17902cfb2e1f6ec6f Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Fri, 15 Sep 2023 11:02:53 -0500 Subject: [PATCH 4/9] Add error handling to function --- .../context/toolWindow/MyToolWindowFactory.kt | 119 ++++++++++-------- 1 file changed, 66 insertions(+), 53 deletions(-) diff --git a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt index bc45e06..4b675ce 100644 --- a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt +++ b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt @@ -130,11 +130,12 @@ class MyToolWindowFactory : ToolWindowFactory { } - private fun makeApiCall(commitMessages: List, email: String?, id: String?): JsonObject? { + private fun makeApiCall(commitMessages: List, email: String?, id: String?): Result { val apiUrl = "$backendUrl/api/extension/getContext" val url = URL(apiUrl) val connection = url.openConnection() as HttpURLConnection - try { + + return try { connection.requestMethod = "POST" connection.doOutput = true connection.setRequestProperty("Content-Type", "application/json") @@ -142,21 +143,26 @@ class MyToolWindowFactory : ToolWindowFactory { val commitListJson = commitMessages.joinToString(prefix = "[\"", separator = "\",\"", postfix = "\"]") val payload = """ - { - "email": $email, - "id": $id, - "repo": "watermelon", - "owner": "watermelontools", - "commitList": $commitListJson - } - """.trimIndent() + { + "email": $email, + "id": $id, + "repo": "watermelon", + "owner": "watermelontools", + "commitList": $commitListJson + } + """.trimIndent() + connection.outputStream.write(payload.toByteArray()) + val responseCode = connection.responseCode - return if (responseCode == HttpURLConnection.HTTP_OK) { - Json.parseToJsonElement(connection.inputStream.reader().readText()).jsonObject + if (responseCode == HttpURLConnection.HTTP_OK) { + val jsonResponse = Json.parseToJsonElement(connection.inputStream.reader().readText()).jsonObject + Result.success(jsonResponse) } else { - null + Result.failure(Exception("Server responded with code: $responseCode")) } + } catch (e: Exception) { // catch all exceptions related to I/O or JSON parsing + Result.failure(e) } finally { connection.disconnect() } @@ -195,57 +201,64 @@ class MyToolWindowFactory : ToolWindowFactory { } val apiResponse = makeApiCall(commitMessages, email, id) - val data = apiResponse?.get("data")?.jsonObject - val serviceNames = data?.keys?.asSequence()?.map { key: String -> key }?.toList() - if (serviceNames != null) { - for (serviceName in serviceNames) { - when (val serviceData = data[serviceName]) { - is JsonObject -> { - // Handle JsonObject case - } + val data = apiResponse.getOrThrow().get("data")?.jsonObject + if (apiResponse.isSuccess) { + val serviceNames = data?.keys?.asSequence()?.map { key: String -> key }?.toList() + if (serviceNames != null) { + for (serviceName in serviceNames) { + when (val serviceData = data[serviceName]) { + is JsonObject -> { + // Handle JsonObject case + } - is JsonArray -> { - if (serviceData.isEmpty()) { - val servicePanel = setupServiceUI(emptyList(), serviceName) - servicePanels = servicePanels + (servicePanel) - } else { - - val returnArray = serviceData.map { serviceDataElement -> - val serviceDataValueJson = serviceDataElement.jsonObject - val title = serviceDataValueJson["title"]?.jsonPrimitive?.content - val body = serviceDataValueJson["body"]?.jsonPrimitive?.content - val link = serviceDataValueJson["link"]?.jsonPrimitive?.content - ServiceData(title ?: "", body ?: "", link) - } - servicePanels = servicePanels + (setupServiceUI( - returnArray, - "$serviceName (${serviceData.size})" - )) + is JsonArray -> { + if (serviceData.isEmpty()) { + val servicePanel = setupServiceUI(emptyList(), serviceName) + servicePanels = servicePanels + (servicePanel) + } else { + + val returnArray = serviceData.map { serviceDataElement -> + val serviceDataValueJson = serviceDataElement.jsonObject + val title = serviceDataValueJson["title"]?.jsonPrimitive?.content + val body = serviceDataValueJson["body"]?.jsonPrimitive?.content + val link = serviceDataValueJson["link"]?.jsonPrimitive?.content + ServiceData(title ?: "", body ?: "", link) + } + servicePanels = servicePanels + (setupServiceUI( + returnArray, + "$serviceName (${serviceData.size})" + )) + } } - } - is JsonPrimitive -> { - val message = serviceData.content - if (message.contains(Regex("no .* token"))) { + is JsonPrimitive -> { + val message = serviceData.content + if (message.contains(Regex("no .* token"))) { - servicePanels = servicePanels + (setupServiceUI(emptyList(), serviceName)) + servicePanels = servicePanels + (setupServiceUI(emptyList(), serviceName)) + } } - } - else -> { - // Handle any other cases if needed + else -> { + // Handle any other cases if needed + } } } } - } - // add the servicePanels to the UI - servicePanels.forEach { servicePanel -> - mainPanel.add(servicePanel) - } + // add the servicePanels to the UI + servicePanels.forEach { servicePanel -> + mainPanel.add(servicePanel) + } - return JBScrollPane(mainPanel) + return JBScrollPane(mainPanel) + + } else { + val error = apiResponse.exceptionOrNull() + // Optionally log or show a message to the user + val errorPanel = JBPanel>() + + } } } } - From 047d30be5af95236f9474dd547d73a0460a8ec14 Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Fri, 15 Sep 2023 11:48:24 -0500 Subject: [PATCH 5/9] Add login suggestion --- .../context/toolWindow/MyToolWindowFactory.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt index 4b675ce..469bbb5 100644 --- a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt +++ b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt @@ -236,7 +236,15 @@ class MyToolWindowFactory : ToolWindowFactory { val message = serviceData.content if (message.contains(Regex("no .* token"))) { - servicePanels = servicePanels + (setupServiceUI(emptyList(), serviceName)) + val emptyTokenPane = ServiceData( + title = "Please login to $serviceName", + body = "Click here to login", + link = "$backendUrl/" + ) + + val list: List = listOf(emptyTokenPane) + + servicePanels = servicePanels + (setupServiceUI(list, serviceName)) } } @@ -257,7 +265,7 @@ class MyToolWindowFactory : ToolWindowFactory { val error = apiResponse.exceptionOrNull() // Optionally log or show a message to the user val errorPanel = JBPanel>() - + } } } From 2b47f90ed5e768f8867c544014754e24f7d420bd Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Fri, 15 Sep 2023 11:56:46 -0500 Subject: [PATCH 6/9] Open link on click --- .../watermelon/context/toolWindow/MyToolWindowFactory.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt index 469bbb5..57cf934 100644 --- a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt +++ b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt @@ -2,6 +2,7 @@ package com.watermelon.context.toolWindow import MyProjectService import com.intellij.credentialStore.CredentialAttributes +import com.intellij.ide.BrowserUtil import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.intellij.openapi.wm.ToolWindow @@ -48,7 +49,7 @@ class MyToolWindowFactory : ToolWindowFactory { private val service = toolWindow.project.service() - class ExpandablePanel(title: String, body: String) : JPanel() { + class ExpandablePanel(title: String, body: String, val link: String? = null) : JPanel() { private val cardLayout = CardLayout() override fun getMaximumSize(): Dimension { return Dimension(parent?.width ?: super.getMaximumSize().width, super.getMaximumSize().height) @@ -99,6 +100,10 @@ class MyToolWindowFactory : ToolWindowFactory { titleButton.addActionListener(switchPanelListener) bodyTextArea.addMouseListener(object : MouseAdapter() { override fun mouseClicked(e: MouseEvent?) { + if (!link.isNullOrEmpty()) { + println("Opening link: $link") + BrowserUtil.browse(link) + } remove(expandedPanel) add(titlePanel) revalidate() @@ -123,7 +128,7 @@ class MyToolWindowFactory : ToolWindowFactory { add(titlePanel) serviceDataArray.forEach { data -> - val expandablePanel = ExpandablePanel(data.title, data.body) + val expandablePanel = ExpandablePanel(data.title, data.body, data.link) add(expandablePanel) } } From 06dbe7533723c1ee41d2cbf910fc74f523482649 Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Fri, 15 Sep 2023 13:34:45 -0500 Subject: [PATCH 7/9] Make title and body a textpane, with arrows --- .../context/toolWindow/MyToolWindowFactory.kt | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt index 57cf934..ad58a5c 100644 --- a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt +++ b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt @@ -56,16 +56,21 @@ class MyToolWindowFactory : ToolWindowFactory { } init { - // Assuming the rest of your code remains the same... - - val titleButton = JButton(title) + val titleTextPane = JTextPane().apply { + contentType = "text/html" + text = "\u25B6 $title" + isEditable = false + isOpaque = false + background = null + font = UIManager.getFont("Button.font") + cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) + } - val bodyTextArea = JTextArea(body).apply { - wrapStyleWord = true - lineWrap = true + val bodyTextPane = JTextPane().apply { + contentType = "text/html" + text = "\u25BC $title
$body" isEditable = false isOpaque = false - border = null background = null font = UIManager.getFont("Button.font") cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) @@ -81,8 +86,8 @@ class MyToolWindowFactory : ToolWindowFactory { maximumSize = Dimension(10, 10) } - titlePanel.add(titleButton) - expandedPanel.add(bodyTextArea) + titlePanel.add(titleTextPane) + expandedPanel.add(bodyTextPane) // Use CardLayout for ExpandablePanel @@ -90,15 +95,16 @@ class MyToolWindowFactory : ToolWindowFactory { add(titlePanel, "TitleOnly") add(expandedPanel, "Expanded") - val switchPanelListener = ActionListener { - remove(titlePanel) - add(expandedPanel) - revalidate() - repaint() - } - titleButton.addActionListener(switchPanelListener) - bodyTextArea.addMouseListener(object : MouseAdapter() { + titleTextPane.addMouseListener(object : MouseAdapter() { + override fun mouseClicked(e: MouseEvent?) { + remove(titlePanel) + add(expandedPanel) + revalidate() + repaint() + } + }) + bodyTextPane.addMouseListener(object : MouseAdapter() { override fun mouseClicked(e: MouseEvent?) { if (!link.isNullOrEmpty()) { println("Opening link: $link") From 7d2c4973df8f7281088aa416fd47467910a8da68 Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Fri, 15 Sep 2023 13:36:07 -0500 Subject: [PATCH 8/9] Breaklines --- .../com/watermelon/context/toolWindow/MyToolWindowFactory.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt index ad58a5c..9543c78 100644 --- a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt +++ b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt @@ -65,10 +65,11 @@ class MyToolWindowFactory : ToolWindowFactory { font = UIManager.getFont("Button.font") cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) } + val formattedBody = body.replace("\n", "
") val bodyTextPane = JTextPane().apply { contentType = "text/html" - text = "\u25BC $title
$body" + text = "\u25BC $title
$formattedBody" isEditable = false isOpaque = false background = null From b21eadcbdd19344ce3d30aae921030d9f361f1e5 Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Fri, 15 Sep 2023 16:26:20 -0500 Subject: [PATCH 9/9] Fix panel opening --- .../context/toolWindow/MyToolWindowFactory.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt index 9543c78..020749c 100644 --- a/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt +++ b/src/main/kotlin/com/watermelon/context/toolWindow/MyToolWindowFactory.kt @@ -71,24 +71,28 @@ class MyToolWindowFactory : ToolWindowFactory { contentType = "text/html" text = "\u25BC $title
$formattedBody" isEditable = false - isOpaque = false + isOpaque = true background = null font = UIManager.getFont("Button.font") cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) } - + val scrollPane = JBScrollPane(bodyTextPane).apply { + verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_NEVER + horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_NEVER + } val titlePanel = JPanel().apply { layout = BoxLayout(this, BoxLayout.Y_AXIS) maximumSize = Dimension(10, 10) } val expandedPanel = JPanel().apply { layout = BoxLayout(this, BoxLayout.Y_AXIS) + maximumSize = Dimension(10, 10) } titlePanel.add(titleTextPane) - expandedPanel.add(bodyTextPane) + expandedPanel.add(scrollPane) // Use CardLayout for ExpandablePanel