fix: correct bulk session delete endpoint + surface deleted count (#653)
* fix: correct bulk session delete endpoint + surface deleted count
- Fix Retrofit @POST path from 'api/sessions/delete' to 'api/sessions/bulk-delete'
- Change response type from Response<Unit> to Response<BulkDeleteResponse>
- Add BulkDeleteResponse model (ok, deleted) matching backend contract
- Surface backend 'deleted' count in toast message instead of using client-side count
Backend contract (web_server.py:10750):
POST /api/sessions/bulk-delete
Body: { "ids": [...], "delete_all": false }
Response: { "ok": true, "deleted": <count> }
Fixes #651
* fix: replace client-side session list filter with full refresh after bulk delete
- Call loadSessions() + loadStats() after successful bulk delete instead of
filtering sessions/searchResults locally via 'ids' — fixes state desync
when backend deletes fewer sessions than requested (partial success) and
is correct for delete_all=true where ids may be empty
- Show 'No sessions were deleted' toast when deletedCount == 0
- Extract toastMsg to separate val to satisfy ktlint lint rules
Addresses review findings: UI state desync, delete_all handling, hardcoded
pluralizing, and zero-deletion UX.
---------
Co-authored-by: M57 <Hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
a62bc7e16c
commit
e12a23befe
3 files changed
+19
-6
No files matched your search
@@ -41,6 +41,12 @@ data class BulkDeleteRequest(
|
|||||||
val delete_all: Boolean = false,
|
val delete_all: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BulkDeleteResponse(
|
||||||
|
val ok: Boolean = false,
|
||||||
|
val deleted: Int = 0,
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class PruneRequest(
|
data class PruneRequest(
|
||||||
val days: Int,
|
val days: Int,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.m57.hermescontrol.data.model.AgentPluginInstallBody
|
|||||||
import com.m57.hermescontrol.data.model.AnalyticsResponse
|
import com.m57.hermescontrol.data.model.AnalyticsResponse
|
||||||
import com.m57.hermescontrol.data.model.AuxiliaryModelsResponse
|
import com.m57.hermescontrol.data.model.AuxiliaryModelsResponse
|
||||||
import com.m57.hermescontrol.data.model.BulkDeleteRequest
|
import com.m57.hermescontrol.data.model.BulkDeleteRequest
|
||||||
|
import com.m57.hermescontrol.data.model.BulkDeleteResponse
|
||||||
import com.m57.hermescontrol.data.model.CheckpointsResponse
|
import com.m57.hermescontrol.data.model.CheckpointsResponse
|
||||||
import com.m57.hermescontrol.data.model.CloneProfileRequest
|
import com.m57.hermescontrol.data.model.CloneProfileRequest
|
||||||
import com.m57.hermescontrol.data.model.ConfigSchemaResponse
|
import com.m57.hermescontrol.data.model.ConfigSchemaResponse
|
||||||
@@ -156,10 +157,10 @@ interface HermesApiService {
|
|||||||
@Body body: SessionRenameRequest,
|
@Body body: SessionRenameRequest,
|
||||||
): Response<Unit>
|
): Response<Unit>
|
||||||
|
|
||||||
@POST("api/sessions/delete")
|
@POST("api/sessions/bulk-delete")
|
||||||
suspend fun bulkDeleteSessions(
|
suspend fun bulkDeleteSessions(
|
||||||
@Body body: BulkDeleteRequest,
|
@Body body: BulkDeleteRequest,
|
||||||
): Response<Unit>
|
): Response<BulkDeleteResponse>
|
||||||
|
|
||||||
@DELETE("api/sessions/{id}")
|
@DELETE("api/sessions/{id}")
|
||||||
suspend fun deleteSession(
|
suspend fun deleteSession(
|
||||||
|
|||||||
@@ -401,17 +401,23 @@ class SessionsViewModel : ViewModel(), ToastHost {
|
|||||||
}
|
}
|
||||||
when (result) {
|
when (result) {
|
||||||
is NetworkResult.Success -> {
|
is NetworkResult.Success -> {
|
||||||
|
val deletedCount = result.data.deleted
|
||||||
|
val toastMsg =
|
||||||
|
if (deletedCount > 0) {
|
||||||
|
"$deletedCount session(s) deleted"
|
||||||
|
} else {
|
||||||
|
"No sessions were deleted"
|
||||||
|
}
|
||||||
_uiState.update {
|
_uiState.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
isDeletingBulk = false,
|
isDeletingBulk = false,
|
||||||
isSelecting = false,
|
isSelecting = false,
|
||||||
selectedIds = emptySet(),
|
selectedIds = emptySet(),
|
||||||
sessions = it.sessions.filter { s -> s.id !in ids },
|
toastMessage = toastMsg,
|
||||||
searchResults = it.searchResults.filter { it.session_id !in ids },
|
|
||||||
total = (it.total - ids.size).coerceAtLeast(0),
|
|
||||||
toastMessage = "${ids.size} session(s) deleted",
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
loadSessions()
|
||||||
|
loadStats()
|
||||||
}
|
}
|
||||||
|
|
||||||
is NetworkResult.Failure -> {
|
is NetworkResult.Failure -> {
|
||||||
|
|||||||
Reference in new issue
Block a user