Skip to content

Commit 8556f2f

Browse files
committed
feat(ui): extract request detail panel into separate component #371
- Create reusable ParameterDisplay component for JSON parameters - Move RequestDetailPanel to its own file - Simplify scrolling behavior in message log panel
1 parent e670f28 commit 8556f2f

File tree

3 files changed

+143
-152
lines changed

3 files changed

+143
-152
lines changed

core/src/main/kotlin/cc/unitmesh/devti/mcp/ui/McpMessageLogPanel.kt

Lines changed: 1 addition & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,13 @@ package cc.unitmesh.devti.mcp.ui
33
import cc.unitmesh.devti.mcp.ui.model.McpMessage
44
import cc.unitmesh.devti.mcp.ui.model.MessageType
55
import com.intellij.ui.JBColor
6-
import com.intellij.ui.components.JBLabel
76
import com.intellij.ui.components.JBScrollPane
87
import com.intellij.ui.table.JBTable
98
import com.intellij.util.ui.JBUI
10-
import kotlinx.serialization.json.Json
11-
import kotlinx.serialization.json.JsonElement
12-
import kotlinx.serialization.json.jsonObject
139
import java.awt.BorderLayout
1410
import java.awt.CardLayout
1511
import java.awt.Component
1612
import java.awt.Dimension
17-
import java.awt.FlowLayout
18-
import java.awt.Font
19-
import java.awt.GridBagConstraints
20-
import java.awt.GridBagLayout
2113
import java.time.format.DateTimeFormatter
2214
import javax.swing.*
2315
import javax.swing.table.DefaultTableCellRenderer
@@ -58,7 +50,7 @@ class McpMessageLogPanel : JPanel(BorderLayout()) {
5850

5951
val splitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT).apply {
6052
leftComponent = JBScrollPane(table)
61-
rightComponent = JBScrollPane(detailPanel)
53+
rightComponent = detailPanel // No need for JBScrollPane as components handle scrolling
6254
dividerLocation = 600
6355
resizeWeight = 0.5
6456
}
@@ -164,147 +156,4 @@ class McpMessageLogPanel : JPanel(BorderLayout()) {
164156
return label
165157
}
166158
}
167-
168-
private class RequestDetailPanel : JPanel(BorderLayout()) {
169-
private val headerPanel = JPanel(BorderLayout()).apply {
170-
border = JBUI.Borders.empty(10, 10, 5, 10)
171-
background = JBColor(0xF8F9FA, 0x2B2D30)
172-
}
173-
174-
private val toolLabel = JBLabel().apply {
175-
font = font.deriveFont(Font.BOLD, font.size + 2f)
176-
}
177-
178-
private val parametersPanel = JPanel(GridBagLayout()).apply {
179-
border = JBUI.Borders.empty(10)
180-
background = JBColor(0xFFFFFF, 0x2B2D30)
181-
}
182-
183-
init {
184-
headerPanel.add(JBLabel("Tool:").apply {
185-
font = font.deriveFont(Font.BOLD)
186-
border = JBUI.Borders.emptyRight(8)
187-
}, BorderLayout.WEST)
188-
headerPanel.add(toolLabel, BorderLayout.CENTER)
189-
190-
add(headerPanel, BorderLayout.NORTH)
191-
add(JBScrollPane(parametersPanel), BorderLayout.CENTER)
192-
}
193-
194-
fun displayMessage(message: McpMessage) {
195-
toolLabel.text = message.toolName ?: "Unknown Tool"
196-
197-
parametersPanel.removeAll()
198-
199-
val paramJson = message.parameters
200-
if (paramJson != null && paramJson != "{}" && paramJson.isNotBlank()) {
201-
try {
202-
val json = Json { ignoreUnknownKeys = true }
203-
val parsedJson = json.parseToJsonElement(paramJson).jsonObject
204-
205-
val headerConstraints = GridBagConstraints().apply {
206-
gridx = 0
207-
gridy = 0
208-
gridwidth = 2
209-
fill = GridBagConstraints.HORIZONTAL
210-
anchor = GridBagConstraints.NORTHWEST
211-
insets = JBUI.insetsBottom(10)
212-
}
213-
214-
parametersPanel.add(JBLabel("Parameters:").apply {
215-
font = font.deriveFont(Font.BOLD, font.size + 1f)
216-
}, headerConstraints)
217-
218-
var row = 1
219-
parsedJson.entries.forEach { (key, value) ->
220-
// Parameter name
221-
val nameConstraints = GridBagConstraints().apply {
222-
gridx = 0
223-
gridy = row
224-
anchor = GridBagConstraints.NORTHWEST
225-
insets = JBUI.insets(5, 0, 5, 10)
226-
}
227-
228-
parametersPanel.add(JBLabel("$key:").apply {
229-
font = font.deriveFont(Font.BOLD)
230-
}, nameConstraints)
231-
232-
// Parameter value
233-
val valueConstraints = GridBagConstraints().apply {
234-
gridx = 1
235-
gridy = row++
236-
weightx = 1.0
237-
fill = GridBagConstraints.HORIZONTAL
238-
anchor = GridBagConstraints.NORTHWEST
239-
insets = JBUI.insets(5, 0)
240-
}
241-
242-
val valueText = formatJsonValue(value)
243-
val valueTextArea = JTextArea(valueText).apply {
244-
lineWrap = true
245-
wrapStyleWord = true
246-
isEditable = false
247-
border = null
248-
background = parametersPanel.background
249-
}
250-
251-
parametersPanel.add(valueTextArea, valueConstraints)
252-
}
253-
254-
// Add filler to push everything to the top
255-
val fillerConstraints = GridBagConstraints().apply {
256-
gridx = 0
257-
gridy = row
258-
gridwidth = 2
259-
weighty = 1.0
260-
fill = GridBagConstraints.BOTH
261-
}
262-
parametersPanel.add(JPanel().apply { background = parametersPanel.background }, fillerConstraints)
263-
264-
} catch (e: Exception) {
265-
// If parsing fails, fall back to displaying raw JSON
266-
val rawParamConstraints = GridBagConstraints().apply {
267-
gridx = 0
268-
gridy = 0
269-
weightx = 1.0
270-
weighty = 1.0
271-
fill = GridBagConstraints.BOTH
272-
}
273-
274-
parametersPanel.add(JTextArea(paramJson).apply {
275-
lineWrap = true
276-
wrapStyleWord = true
277-
isEditable = false
278-
}, rawParamConstraints)
279-
}
280-
} else {
281-
val noParamsConstraints = GridBagConstraints().apply {
282-
gridx = 0
283-
gridy = 0
284-
weightx = 1.0
285-
fill = GridBagConstraints.HORIZONTAL
286-
}
287-
288-
parametersPanel.add(JBLabel("No parameters").apply {
289-
foreground = JBColor.GRAY
290-
}, noParamsConstraints)
291-
292-
val fillerConstraints = GridBagConstraints().apply {
293-
gridx = 0
294-
gridy = 1
295-
weightx = 1.0
296-
weighty = 1.0
297-
fill = GridBagConstraints.BOTH
298-
}
299-
parametersPanel.add(JPanel().apply { background = parametersPanel.background }, fillerConstraints)
300-
}
301-
302-
parametersPanel.revalidate()
303-
parametersPanel.repaint()
304-
}
305-
306-
private fun formatJsonValue(element: JsonElement): String {
307-
return element.toString()
308-
}
309-
}
310159
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package cc.unitmesh.devti.mcp.ui
2+
3+
import com.intellij.ui.JBColor
4+
import com.intellij.ui.components.JBLabel
5+
import com.intellij.ui.components.JBScrollPane
6+
import com.intellij.util.ui.JBUI
7+
import kotlinx.serialization.json.JsonElement
8+
import java.awt.BorderLayout
9+
import java.awt.Dimension
10+
import java.awt.Font
11+
import javax.swing.*
12+
13+
/**
14+
* A reusable component for displaying key-value parameters from JSON
15+
*/
16+
class ParameterDisplay : JPanel(BorderLayout()) {
17+
private val contentPanel = JPanel().apply {
18+
layout = BoxLayout(this, BoxLayout.Y_AXIS)
19+
background = JBColor(0xFFFFFF, 0x2B2D30)
20+
border = JBUI.Borders.empty(10)
21+
}
22+
23+
init {
24+
background = JBColor(0xFFFFFF, 0x2B2D30)
25+
add(JBScrollPane(contentPanel), BorderLayout.CENTER)
26+
}
27+
28+
fun displayParameters(parameters: Map<String, JsonElement>?) {
29+
contentPanel.removeAll()
30+
31+
if (parameters == null || parameters.isEmpty()) {
32+
contentPanel.add(JBLabel("No parameters").apply {
33+
foreground = JBColor.GRAY
34+
alignmentX = LEFT_ALIGNMENT
35+
})
36+
} else {
37+
contentPanel.add(JBLabel("Parameters:").apply {
38+
font = font.deriveFont(Font.BOLD, font.size + 1f)
39+
alignmentX = LEFT_ALIGNMENT
40+
border = JBUI.Borders.emptyBottom(10)
41+
})
42+
43+
parameters.forEach { (key, value) ->
44+
val paramPanel = JPanel(BorderLayout()).apply {
45+
background = contentPanel.background
46+
border = JBUI.Borders.emptyBottom(5)
47+
alignmentX = LEFT_ALIGNMENT
48+
maximumSize = Dimension(Int.MAX_VALUE, getPreferredSize().height)
49+
}
50+
51+
paramPanel.add(JBLabel("$key:").apply {
52+
font = font.deriveFont(Font.BOLD)
53+
border = JBUI.Borders.emptyRight(10)
54+
}, BorderLayout.WEST)
55+
56+
val valueText = formatJsonValue(value)
57+
val valueTextArea = JTextArea(valueText).apply {
58+
lineWrap = true
59+
wrapStyleWord = true
60+
isEditable = false
61+
border = null
62+
background = contentPanel.background
63+
}
64+
65+
paramPanel.add(valueTextArea, BorderLayout.CENTER)
66+
contentPanel.add(paramPanel)
67+
}
68+
}
69+
70+
contentPanel.add(Box.createVerticalGlue())
71+
72+
contentPanel.revalidate()
73+
contentPanel.repaint()
74+
}
75+
76+
private fun formatJsonValue(element: JsonElement): String {
77+
return element.toString()
78+
}
79+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package cc.unitmesh.devti.mcp.ui
2+
3+
import cc.unitmesh.devti.mcp.ui.model.McpMessage
4+
import com.intellij.ui.JBColor
5+
import com.intellij.ui.components.JBLabel
6+
import com.intellij.util.ui.JBUI
7+
import kotlinx.serialization.json.Json
8+
import kotlinx.serialization.json.jsonObject
9+
import java.awt.BorderLayout
10+
import java.awt.Font
11+
import javax.swing.*
12+
13+
/**
14+
* Panel for displaying request details from MCP messages
15+
*/
16+
class RequestDetailPanel : JPanel(BorderLayout()) {
17+
private val headerPanel = JPanel(BorderLayout()).apply {
18+
border = JBUI.Borders.empty(10, 10, 5, 10)
19+
background = JBColor(0xF8F9FA, 0x2B2D30)
20+
}
21+
22+
private val toolLabel = JBLabel().apply {
23+
font = font.deriveFont(Font.BOLD, font.size + 2f)
24+
}
25+
26+
private val parameterDisplay = ParameterDisplay()
27+
28+
init {
29+
headerPanel.add(JBLabel("Tool:").apply {
30+
font = font.deriveFont(Font.BOLD)
31+
border = JBUI.Borders.emptyRight(8)
32+
}, BorderLayout.WEST)
33+
headerPanel.add(toolLabel, BorderLayout.CENTER)
34+
35+
add(headerPanel, BorderLayout.NORTH)
36+
add(parameterDisplay, BorderLayout.CENTER)
37+
}
38+
39+
fun displayMessage(message: McpMessage) {
40+
toolLabel.text = message.toolName ?: "Unknown Tool"
41+
42+
val paramJson = message.parameters
43+
if (paramJson != null && paramJson != "{}" && paramJson.isNotBlank()) {
44+
try {
45+
val json = Json { ignoreUnknownKeys = true }
46+
val parsedJson = json.parseToJsonElement(paramJson).jsonObject
47+
parameterDisplay.displayParameters(parsedJson)
48+
} catch (e: Exception) {
49+
// If parsing fails, fall back to displaying raw JSON
50+
val errorPanel = JPanel(BorderLayout())
51+
parameterDisplay.displayParameters(null)
52+
53+
add(JTextArea(paramJson).apply {
54+
lineWrap = true
55+
wrapStyleWord = true
56+
isEditable = false
57+
}, BorderLayout.SOUTH)
58+
}
59+
} else {
60+
parameterDisplay.displayParameters(null)
61+
}
62+
}
63+
}

0 commit comments

Comments
 (0)