fix(jetbrains): restore history back context

This commit is contained in:
kirillk
2026-08-11 10:47:34 -04:00
parent ac23a8e2cb
commit a39dc5ddfd
29 changed files with 61 additions and 16 deletions
@@ -11,6 +11,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.DataProvider
import com.intellij.openapi.actionSystem.PlatformDataKeys
import com.intellij.openapi.project.DumbAware
import com.intellij.ui.content.Content
class HistoryAction : AnAction(
KiloBundle.message("action.Kilo.History.text"),
@@ -20,16 +21,17 @@ class HistoryAction : AnAction(
override fun actionPerformed(e: AnActionEvent) {
val manager = e.getData(SessionManager.KEY) ?: return
Telemetry.send("History Opened", mapOf("surface" to "tool_window"))
// History renders inside the chat content, which only lives on the AI Chat tab, so bring
// that tab forward first when invoked from the Agent Manager tab.
if (e.getData(SidePanelKeys.MODE) == SidePanelMode.AGENT_MANAGER) selectChat(e)
manager.showHistory()
val agent = if (e.getData(SidePanelKeys.MODE) == SidePanelMode.AGENT_MANAGER) selected(e) else null
if (agent != null) selectChat(e)
manager.showHistory(agent?.let { { select(e, it) } })
}
override fun update(e: AnActionEvent) {
e.presentation.isEnabled = e.getData(SessionManager.KEY) != null
}
private fun selected(e: AnActionEvent) = e.getData(PlatformDataKeys.TOOL_WINDOW)?.contentManager?.selectedContent
private fun selectChat(e: AnActionEvent) {
val manager = e.getData(PlatformDataKeys.TOOL_WINDOW)?.contentManager ?: return
val chat = manager.contents.firstOrNull {
@@ -37,4 +39,8 @@ class HistoryAction : AnAction(
} ?: return
manager.setSelectedContent(chat, true)
}
private fun select(e: AnActionEvent, content: Content) {
e.getData(PlatformDataKeys.TOOL_WINDOW)?.contentManager?.setSelectedContent(content, true)
}
}
@@ -110,7 +110,7 @@ open class WorktreeSessionEditorManager(
}
@RequiresEdt
override fun showHistory() {
override fun showHistory(back: (() -> Unit)?) {
list.reload()
onListChanged?.invoke()
}
@@ -12,7 +12,7 @@ interface SessionManager {
fun newSession()
fun showHistory()
fun showHistory(back: (() -> Unit)? = null)
fun openSession(ref: SessionRef)
@@ -47,6 +47,7 @@ class SessionSidePanelManager(
}
private var panel: JComponent? = null
private var historyBack: (() -> Unit)? = null
val defaultFocusedComponent: JComponent? get() = currentUi()?.defaultFocusedComponent ?: (panel as? HistoryPanel)?.defaultFocusedComponent
@@ -57,7 +58,8 @@ class SessionSidePanelManager(
}
@RequiresEdt
override fun showHistory() {
override fun showHistory(back: (() -> Unit)?) {
historyBack = back
val active = currentUi()
register(active)
release(active)
@@ -94,6 +96,12 @@ class SessionSidePanelManager(
@RequiresEdt
private fun back() {
val callback = historyBack
historyBack = null
if (callback != null) {
callback()
return
}
val ui = latestUi()
if (ui != null) {
show(ui)
@@ -365,7 +365,7 @@ worktree.session.rename.failed.title=Failed to rename session "{0}"
worktree.session.new=New session
worktree.session.untitled=Untitled session
worktree.menu.from=New Worktree from {0}
worktree.menu.configure=Configure new worktree
worktree.menu.configure=Configure New Worktree...
worktree.configure.title=New Worktree
worktree.configure.branch=Branch name:
worktree.configure.base=Base branch:
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=أدخل نمط glob لتجاهله:
# Auto-Approve settings
settings.autoApprove.edit=تحرير
worktree.menu.configure=تكوين Worktree جديد...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=Unesite glob uzorak za ignoriranje:
# Auto-Approve settings
settings.autoApprove.edit=Uredi
worktree.menu.configure=Konfiguriši novi worktree...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=Indtast et glob-mønster, der skal ignorer
# Auto-Approve settings
settings.autoApprove.edit=Rediger
worktree.menu.configure=Konfigurer nyt worktree...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=Glob-Muster zum Ignorieren eingeben:
# Auto-Approve settings
settings.autoApprove.edit=Bearbeiten
worktree.menu.configure=Neuen Worktree konfigurieren...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=Introduce un patrón glob para ignorar:
# Auto-Approve settings
settings.autoApprove.edit=Editar
worktree.menu.configure=Configurar nuevo worktree...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=Saisissez un motif glob à ignorer :
# Auto-Approve settings
settings.autoApprove.edit=Modifier
worktree.menu.configure=Configurer un nouveau worktree...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=無視するglobパターンを入力し
# Auto-Approve settings
settings.autoApprove.edit=編集
worktree.menu.configure=新しいワークツリーを設定...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=무시할 glob 패턴을 입력하세요:
# Auto-Approve settings
settings.autoApprove.edit=편집
worktree.menu.configure=새 워크트리 구성...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=Voer een glob-patroon in om te negeren:
# Auto-Approve settings
settings.autoApprove.edit=Bewerken
worktree.menu.configure=Nieuwe worktree configureren...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=Skriv inn et glob-mønster som skal ignore
# Auto-Approve settings
settings.autoApprove.edit=Rediger
worktree.menu.configure=Konfigurer nytt worktree...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=Wpisz wzorzec glob do ignorowania:
# Auto-Approve settings
settings.autoApprove.edit=Edytuj
worktree.menu.configure=Skonfiguruj nowy worktree...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=Digite um padrão glob para ignorar:
# Auto-Approve settings
settings.autoApprove.edit=Editar
worktree.menu.configure=Configurar novo worktree...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=Введите glob-шаблон для и
# Auto-Approve settings
settings.autoApprove.edit=Изменить
worktree.menu.configure=Настроить новое рабочее дерево...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=ป้อนรูปแบบ glob ที
# Auto-Approve settings
settings.autoApprove.edit=แก้ไข
worktree.menu.configure=กำหนดค่า worktree ใหม่...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=Yok sayılacak bir glob kalıbı girin:
# Auto-Approve settings
settings.autoApprove.edit=Düzenle
worktree.menu.configure=Yeni worktree yapılandır...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=Введіть glob-шаблон для і
# Auto-Approve settings
settings.autoApprove.edit=Редагувати
worktree.menu.configure=Налаштувати нове робоче дерево...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=输入要忽略的 glob 模式:
# Auto-Approve settings
settings.autoApprove.edit=编辑
worktree.menu.configure=配置新工作树...
@@ -461,3 +461,4 @@ settings.context.watcher.input.prompt=輸入要忽略的 glob 模式:
# Auto-Approve settings
settings.autoApprove.edit=編輯
worktree.menu.configure=設定新工作樹...
@@ -441,7 +441,7 @@ class HistorySessionActionsTest : BasePlatformTestCase() {
private class FakeManager : SessionManager {
override fun newSession() {}
override fun showHistory() {}
override fun showHistory(back: (() -> Unit)?) {}
override fun openSession(ref: SessionRef) {}
}
}
@@ -50,7 +50,7 @@ class NewSessionActionTest : BasePlatformTestCase() {
created++
}
override fun showHistory() {
override fun showHistory(back: (() -> Unit)?) {
}
override fun openSession(ref: SessionRef) {
@@ -138,6 +138,19 @@ class SessionSidePanelManagerTest : BasePlatformTestCase() {
assertSame(history.defaultFocusedComponent, manager.defaultFocusedComponent)
}
fun `test history back callback overrides local session fallback`() {
val manager = manager()
var calls = 0
manager.newSession()
manager.showHistory { calls++ }
settle()
val history = active(manager) as HistoryPanel
history.clickBack()
assertEquals(1, calls)
}
fun `test opening same existing session reuses component`() {
useLongInactiveDisposeTimeout()
val manager = manager()
@@ -123,7 +123,7 @@ class SessionUiFactoryTest : BasePlatformTestCase() {
override fun newSession() {
}
override fun showHistory() {
override fun showHistory(back: (() -> Unit)?) {
history++
}
@@ -92,7 +92,7 @@ abstract class SessionUiTestBase : BasePlatformTestCase() {
val manager = open?.let { fn ->
object : SessionManager {
override fun newSession() {}
override fun showHistory() {}
override fun showHistory(back: (() -> Unit)?) {}
override fun openSession(ref: SessionRef) = fn(ref)
}
}
@@ -239,7 +239,7 @@ class HistoryControllerTest : BasePlatformTestCase() {
rpc.listed += session("ses_1", "Local One")
val panel = HistoryPanel(parent, controller(), manager = object : SessionManager {
override fun newSession() {}
override fun showHistory() {}
override fun showHistory(back: (() -> Unit)?) {}
override fun openSession(ref: SessionRef) {}
override fun activity() = mapOf("ses_1" to SessionActivityKind.PERMISSION)
})
@@ -255,7 +255,7 @@ class HistoryControllerTest : BasePlatformTestCase() {
var kind: SessionActivityKind? = null
val panel = HistoryPanel(parent, controller(), manager = object : SessionManager {
override fun newSession() {}
override fun showHistory() {}
override fun showHistory(back: (() -> Unit)?) {}
override fun openSession(ref: SessionRef) {}
override fun activity() = sessions.activitySnapshot() + kind?.let { mapOf("ses_1" to it) }.orEmpty()
})
@@ -276,7 +276,7 @@ class HistoryControllerTest : BasePlatformTestCase() {
var title = "Live"
val panel = HistoryPanel(parent, controller(), manager = object : SessionManager {
override fun newSession() {}
override fun showHistory() {}
override fun showHistory(back: (() -> Unit)?) {}
override fun openSession(ref: SessionRef) {}
override fun titles() = title.takeIf { it.isNotBlank() }?.let { mapOf("ses_1" to it) }.orEmpty()
})
@@ -946,7 +946,7 @@ class HistoryControllerTest : BasePlatformTestCase() {
private class FakeManager : SessionManager {
override fun newSession() {}
override fun showHistory() {}
override fun showHistory(back: (() -> Unit)?) {}
override fun openSession(ref: SessionRef) {}
}