Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/jetbrains-revert-loading.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@kilocode/kilo-jetbrains": patch
---

Show rollback/redo progress inline (on the message and redo controls) with a cancel action instead of a full-screen loading overlay.
2 changes: 1 addition & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class KiloBackendChatManager(
companion object {
private val JSON_TYPE = "application/json".toMediaType()
private const val ENHANCE_TIMEOUT_MINUTES = 2L
private const val REVERT_TIMEOUT_SECONDS = 35L

private val CHAT_EVENTS = setOf(
"message.updated",
Expand Down Expand Up @@ -257,15 +258,15 @@ class KiloBackendChatManager(
}
}

fun revert(id: String, dir: String, message: String, part: String?) {
suspend fun revert(id: String, dir: String, message: String, part: String?) {
log.info("${ChatLogSummary.sid(id)} kind=revert ${ChatLogSummary.dir(dir)} message=$message part=${part ?: "none"}")
val body = KiloCliDataParser.buildRevertJson(message, part)
post("/session/$id/revert?directory=${encode(dir)}", body, "revert", "${ChatLogSummary.sid(id)} kind=revert", strict = true)
postCancellable("/session/$id/revert?directory=${encode(dir)}", body, "revert", "${ChatLogSummary.sid(id)} kind=revert")
}

fun unrevert(id: String, dir: String) {
suspend fun unrevert(id: String, dir: String) {
log.info("${ChatLogSummary.sid(id)} kind=unrevert ${ChatLogSummary.dir(dir)}")
post("/session/$id/unrevert?directory=${encode(dir)}", "{}", "unrevert", "${ChatLogSummary.sid(id)} kind=unrevert", strict = true)
postCancellable("/session/$id/unrevert?directory=${encode(dir)}", "{}", "unrevert", "${ChatLogSummary.sid(id)} kind=unrevert")
}

// ------ messages ------
Expand Down Expand Up @@ -387,6 +388,27 @@ class KiloBackendChatManager(
}
}

private suspend fun postCancellable(path: String, body: String, op: String, meta: String) {
val http = requireClient()
val url = requireBase()
val request = Request.Builder()
.url("$url$path")
.post(body.toRequestBody(JSON_TYPE))
.build()
val call = http.newCall(request)
call.timeout().timeout(REVERT_TIMEOUT_SECONDS, TimeUnit.SECONDS)
call.await().use { response ->
if (!response.isSuccessful) {
val code = response.code
val raw = response.body?.string()
log.warn("$op failed: HTTP $code")
raw?.let { log.debug { "$meta op=$op error=${ChatLogSummary.body(it)}" } }
throw RuntimeException("$op failed: HTTP $code")
}
log.debug { "$meta op=$op ok=true code=${response.code}" }
}
}

private fun get(path: String, op: String): String? {
val http = requireClient()
val url = requireBase()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class KiloBackendChatManagerTest {
}

@Test
fun `revert posts message and part to revert endpoint`() {
fun `revert posts message and part to revert endpoint`() = runBlocking {
val port = mock.start()
val chat = KiloBackendChatManager(scope, TestLog())
chat.start(OkHttpClient(), port, MutableSharedFlow())
Expand All @@ -65,7 +65,7 @@ class KiloBackendChatManagerTest {
}

@Test
fun `revert omits part when absent`() {
fun `revert omits part when absent`() = runBlocking {
val port = mock.start()
val chat = KiloBackendChatManager(scope, TestLog())
chat.start(OkHttpClient(), port, MutableSharedFlow())
Expand All @@ -78,7 +78,7 @@ class KiloBackendChatManagerTest {
}

@Test
fun `unrevert posts empty body to unrevert endpoint`() {
fun `unrevert posts empty body to unrevert endpoint`() = runBlocking {
val port = mock.start()
val chat = KiloBackendChatManager(scope, TestLog())
chat.start(OkHttpClient(), port, MutableSharedFlow())
Expand All @@ -91,7 +91,7 @@ class KiloBackendChatManagerTest {
}

@Test
fun `revert failure throws on non successful response`() {
fun `revert failure throws on non successful response`() = runBlocking {
val port = mock.start()
val chat = KiloBackendChatManager(scope, TestLog())
chat.start(OkHttpClient(), port, MutableSharedFlow())
Expand All @@ -107,7 +107,7 @@ class KiloBackendChatManagerTest {
}

@Test
fun `unrevert failure throws on non successful response`() {
fun `unrevert failure throws on non successful response`() = runBlocking {
val port = mock.start()
val chat = KiloBackendChatManager(scope, TestLog())
chat.start(OkHttpClient(), port, MutableSharedFlow())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ class SessionUi(
is SessionState.Idle,
is SessionState.Loading,
is SessionState.Busy,
is SessionState.Reverting,
is SessionState.Retry,
is SessionState.Offline,
is SessionState.Error -> null
Expand Down Expand Up @@ -361,7 +362,8 @@ class SessionUi(
repo = workspace.directory,
resize = { anchor, fn -> scroll.preserve(anchor, fn) },
revert = ::revert,
banner = RevertBanner(controller.model, controller::redo, controller::redoAll, focus),
cancelRevert = controller::cancelRevert,
banner = RevertBanner(controller.model, controller::redo, controller::redoAll, controller::cancelRevert, focus),
).also {
it.onHover = { view, on -> if (on) popup.show(view) else popup.notifyExit(view) }
}
Expand Down Expand Up @@ -808,6 +810,7 @@ class SessionUi(

private fun onStateChanged(state: SessionState) {
if (disposed) return
if (state is SessionState.Reverting) overlay.clear()
prompt.setBusy(state.isBusy())
load.setState(state)
scroll.setQuestionPending(questionPending(state))
Expand Down
Loading
Loading