mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-29 03:44:06 +08:00
fix(jetbrains): align chat PR badge
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@kilocode/kilo-jetbrains": patch
|
||||
---
|
||||
|
||||
Use regular PR title text and vertically center the PR badge in the JetBrains chat tool window.
|
||||
+1
-1
@@ -21,7 +21,7 @@ internal class WorktreePrHeaderView(
|
||||
openTerminal: () -> Unit = {},
|
||||
openDiff: () -> Unit,
|
||||
) : BorderLayoutPanel() {
|
||||
private val core = PrHeaderView(openDiff)
|
||||
private val core = PrHeaderView(openDiff = openDiff)
|
||||
private val terminal = hoverTextButton(
|
||||
ToolbarButtonAction(TerminalIcons.OpenTerminal_13x13, KiloBundle.message("worktree.session.terminal.action"), openTerminal),
|
||||
tooltip = KiloBundle.message("worktree.session.terminal.tooltip"),
|
||||
|
||||
+5
-3
@@ -17,6 +17,7 @@ import com.intellij.openapi.actionSystem.DataSink
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup
|
||||
import com.intellij.openapi.actionSystem.UiDataProvider
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.ui.SimpleTextAttributes
|
||||
import com.intellij.util.concurrency.annotations.RequiresEdt
|
||||
import com.intellij.util.ui.JBUI
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel
|
||||
@@ -43,8 +44,9 @@ internal class BranchDock(
|
||||
openDiff: () -> Unit,
|
||||
private val onMove: (() -> Unit)?,
|
||||
private val onNewWorktree: (() -> Unit)? = null,
|
||||
titleStyle: Int = SimpleTextAttributes.STYLE_PLAIN,
|
||||
) : BorderLayoutPanel(), SessionEditorStyleTarget, UiDataProvider {
|
||||
private val core = PrHeaderView(openDiff)
|
||||
private val core = PrHeaderView(titleStyle = titleStyle, openDiff = openDiff)
|
||||
private val changes = BranchChangesBadge(openDiff)
|
||||
private val group = DefaultActionGroup().apply {
|
||||
ActionManager.getInstance().getAction("Kilo.Chat.NewWorktree")?.let { add(it) }
|
||||
@@ -66,7 +68,7 @@ internal class BranchDock(
|
||||
toolbar.targetComponent = this
|
||||
// Transparent so the toolbar shows the dock's prompt-matching background and tracks LaF.
|
||||
toolbar.component.isOpaque = false
|
||||
addToCenter(Stack.vertical().next(core).next(actionRow))
|
||||
addToCenter(Stack.vertical().next(core).next(actionRow).align(HAlign.TRACK, VAlign.CENTER))
|
||||
isVisible = false
|
||||
sync()
|
||||
}
|
||||
@@ -77,7 +79,7 @@ internal class BranchDock(
|
||||
super.updateUI()
|
||||
border = JBUI.Borders.compound(
|
||||
JBUI.Borders.customLineTop(JBUI.CurrentTheme.EditorTabs.borderColor()),
|
||||
JBUI.Borders.empty(0, 0),
|
||||
JBUI.Borders.empty(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -36,6 +36,7 @@ import java.awt.event.MouseEvent
|
||||
* Stays non-opaque so the host owns background and borders.
|
||||
*/
|
||||
internal class PrHeaderView(
|
||||
private val titleStyle: Int = SimpleTextAttributes.STYLE_BOLD,
|
||||
openDiff: () -> Unit,
|
||||
) : BorderLayoutPanel(), SessionEditorStyleTarget {
|
||||
private val status = JBLabel()
|
||||
@@ -165,10 +166,11 @@ internal class PrHeaderView(
|
||||
val number = number ?: return
|
||||
title.clear()
|
||||
val body = body
|
||||
val attrs = SimpleTextAttributes(titleStyle, UIUtil.getLabelForeground())
|
||||
if (body == null) {
|
||||
title.append(number, SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, UIUtil.getLabelForeground()))
|
||||
title.append(number, attrs)
|
||||
} else {
|
||||
title.append(body, SimpleTextAttributes(SimpleTextAttributes.STYLE_BOLD, UIUtil.getLabelForeground()))
|
||||
title.append(body, attrs)
|
||||
title.append(" $number", SimpleTextAttributes.GRAYED_ATTRIBUTES)
|
||||
}
|
||||
}
|
||||
@@ -184,7 +186,7 @@ internal class PrHeaderView(
|
||||
override fun applyStyle(style: SessionEditorStyle) {
|
||||
this.style = style
|
||||
changes.applyStyle(style)
|
||||
// Re-render the title so its bold foreground follows the theme, then repaint.
|
||||
// Re-render the title so its foreground follows the theme, then repaint.
|
||||
renderTitle()
|
||||
changed()
|
||||
}
|
||||
|
||||
+58
@@ -3,6 +3,7 @@ package ai.kilocode.client.session.ui.header
|
||||
import ai.kilocode.client.actions.ChatMoveToWorktreeAction
|
||||
import ai.kilocode.client.actions.ChatNewWorktreeAction
|
||||
import ai.kilocode.client.plugin.KiloBundle
|
||||
import ai.kilocode.client.ui.FilledBadgeIcon
|
||||
import ai.kilocode.client.util.edtWait
|
||||
import ai.kilocode.rpc.dto.BranchStatusDto
|
||||
import ai.kilocode.rpc.dto.DiffFileDto
|
||||
@@ -15,6 +16,13 @@ import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.openapi.actionSystem.Presentation
|
||||
import com.intellij.openapi.actionSystem.ex.ActionUtil
|
||||
import com.intellij.testFramework.fixtures.BasePlatformTestCase
|
||||
import com.intellij.ui.SimpleColoredComponent
|
||||
import com.intellij.ui.SimpleTextAttributes
|
||||
import com.intellij.ui.components.JBLabel
|
||||
import java.awt.Component
|
||||
import java.awt.Container
|
||||
import java.awt.Point
|
||||
import javax.swing.SwingUtilities
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
class BranchDockTest : BasePlatformTestCase() {
|
||||
@@ -71,6 +79,27 @@ class BranchDockTest : BasePlatformTestCase() {
|
||||
assertTrue(edt { dock.isVisible })
|
||||
}
|
||||
|
||||
fun `test PR title uses normal text in the tool window dock`() {
|
||||
val dock = dock()
|
||||
edt { dock.setBranch(prBranch()) }
|
||||
|
||||
val title = edt { components(dock).filterIsInstance<SimpleColoredComponent>().single() }
|
||||
assertEquals(SimpleTextAttributes.STYLE_PLAIN, edt { firstAttrs(title).style })
|
||||
}
|
||||
|
||||
fun `test PR state badge is vertically centered in the reserved dock row`() {
|
||||
val dock = dock()
|
||||
edt {
|
||||
dock.setBranch(prBranch())
|
||||
dock.setSize(500, dock.preferredSize.height)
|
||||
layout(dock)
|
||||
}
|
||||
|
||||
val badge = edt { components(dock).filterIsInstance<JBLabel>().single { it.icon is FilledBadgeIcon } }
|
||||
val center = edt { SwingUtilities.convertPoint(badge, Point(0, 0), dock).y + badge.height / 2 }
|
||||
assertTrue(kotlin.math.abs(edt { dock.height / 2 } - center) <= 1)
|
||||
}
|
||||
|
||||
// ---- active session ----
|
||||
|
||||
fun `test dock hidden while session is busy`() {
|
||||
@@ -257,6 +286,35 @@ class BranchDockTest : BasePlatformTestCase() {
|
||||
|
||||
private fun dockWithNewWorktree(): BranchDock = edt { BranchDock(openDiff = {}, onMove = {}, onNewWorktree = {}) }
|
||||
|
||||
private fun prBranch() = BranchStatusDto(
|
||||
branch = "feature-x",
|
||||
worktree = true,
|
||||
availability = GhAvailability.OK,
|
||||
pr = WorktreePrDto("/repo", 7, GhState.OPEN, "https://pr/7", "Title"),
|
||||
)
|
||||
|
||||
private fun firstAttrs(title: SimpleColoredComponent): SimpleTextAttributes {
|
||||
val iter = title.iterator()
|
||||
check(iter.hasNext()) { "missing title fragment" }
|
||||
iter.next()
|
||||
return iter.textAttributes
|
||||
}
|
||||
|
||||
private fun layout(root: Component) {
|
||||
root.doLayout()
|
||||
if (root is Container) root.components.forEach(::layout)
|
||||
}
|
||||
|
||||
private fun components(root: Component): List<Component> {
|
||||
val out = mutableListOf<Component>()
|
||||
fun visit(item: Component) {
|
||||
out += item
|
||||
if (item is Container) item.components.forEach { visit(it) }
|
||||
}
|
||||
visit(root)
|
||||
return out
|
||||
}
|
||||
|
||||
private fun update(action: AnAction, dock: BranchDock): Presentation {
|
||||
val event = event(action, dock)
|
||||
edt { ActionUtil.updateAction(action, event) }
|
||||
|
||||
+17
@@ -10,6 +10,7 @@ import ai.kilocode.rpc.dto.WorktreePrDto
|
||||
import ai.kilocode.rpc.dto.WorktreeStatsDto
|
||||
import com.intellij.testFramework.fixtures.BasePlatformTestCase
|
||||
import com.intellij.ui.SimpleColoredComponent
|
||||
import com.intellij.ui.SimpleTextAttributes
|
||||
import com.intellij.ui.components.JBLabel
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import java.awt.Component
|
||||
@@ -31,6 +32,15 @@ class PrHeaderViewTest : BasePlatformTestCase() {
|
||||
assertEquals(Cursor.HAND_CURSOR, edt { title.cursor.type })
|
||||
}
|
||||
|
||||
fun `test title style can be configured`() {
|
||||
val view = edt { PrHeaderView(openDiff = {}, titleStyle = SimpleTextAttributes.STYLE_PLAIN) }
|
||||
|
||||
edt { view.update(files = 0, additions = 0, deletions = 0, pull = pull(GhState.OPEN), name = "feature-x") }
|
||||
|
||||
val title = edt { title(view) }
|
||||
assertEquals(SimpleTextAttributes.STYLE_PLAIN, edt { firstAttrs(title).style })
|
||||
}
|
||||
|
||||
fun `test no PR hides badge and title`() {
|
||||
val view = edt { PrHeaderView {} }
|
||||
|
||||
@@ -112,6 +122,13 @@ class PrHeaderViewTest : BasePlatformTestCase() {
|
||||
return out
|
||||
}
|
||||
|
||||
private fun firstAttrs(title: SimpleColoredComponent): SimpleTextAttributes {
|
||||
val iter = title.iterator()
|
||||
check(iter.hasNext()) { "missing title fragment" }
|
||||
iter.next()
|
||||
return iter.textAttributes
|
||||
}
|
||||
|
||||
private fun components(root: Component): List<Component> {
|
||||
val out = mutableListOf<Component>()
|
||||
fun visit(item: Component) {
|
||||
|
||||
Reference in New Issue
Block a user