feat(kanban): add typed models and KanbanApiService for desktop parity
This commit is contained in:
1 parent
7520008ae3
commit
a486191d9d
10 files changed
+1307
-56
No files matched your search
@@ -1,44 +0,0 @@
|
||||
package com.m57.hermescontrol.data.model
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class KanbanBoard(
|
||||
@SerialName("slug") val id: String,
|
||||
val name: String,
|
||||
val description: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanTask(
|
||||
val id: String,
|
||||
val title: String,
|
||||
@SerialName("body") val description: String? = null,
|
||||
val status: String,
|
||||
@SerialName("assignee") val assignedTo: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CreateTaskBody(
|
||||
val title: String,
|
||||
val body: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanColumn(
|
||||
val name: String,
|
||||
val tasks: List<KanbanTask>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanBoardResponse(
|
||||
val columns: List<KanbanColumn>,
|
||||
val assignees: List<String>? = null,
|
||||
val tenants: List<String>? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanBoardsResponse(
|
||||
val boards: List<KanbanBoard>,
|
||||
val current: String? = null,
|
||||
)
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.m57.hermescontrol.data.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
|
||||
@Serializable
|
||||
data class KanbanComment(
|
||||
val id: Long,
|
||||
val author: String,
|
||||
val body: String,
|
||||
val createdAt: Long,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanDetailEvent(
|
||||
val id: Long,
|
||||
val kind: String,
|
||||
val payload: JsonElement? = null,
|
||||
val createdAt: Long,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanRun(
|
||||
val id: Long,
|
||||
val profile: String? = null,
|
||||
val status: String,
|
||||
val outcome: String? = null,
|
||||
val summary: String? = null,
|
||||
val error: String? = null,
|
||||
val metadata: JsonElement? = null,
|
||||
val workerPid: Int? = null,
|
||||
val startedAt: Long? = null,
|
||||
val endedAt: Long? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class WorkerLog(
|
||||
val taskId: String,
|
||||
val path: String? = null,
|
||||
val exists: Boolean = false,
|
||||
val sizeBytes: Long = 0L,
|
||||
val content: String = "",
|
||||
val truncated: Boolean = false,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanAttachment(
|
||||
val id: Long,
|
||||
val taskId: String? = null,
|
||||
val filename: String,
|
||||
val contentType: String? = null,
|
||||
val size: Long? = null,
|
||||
val uploadedBy: String? = null,
|
||||
val storedPath: String? = null,
|
||||
val createdAt: Long? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class AttachmentUploadResponse(
|
||||
val attachment: KanbanAttachment? = null,
|
||||
)
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.m57.hermescontrol.data.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
|
||||
@Serializable
|
||||
data class KanbanBoard(
|
||||
@SerialName("slug") val id: String,
|
||||
val name: String? = null,
|
||||
val description: String? = null,
|
||||
val isCurrent: Boolean = false,
|
||||
val total: Int? = null,
|
||||
val counts: Map<String, Int> = emptyMap(),
|
||||
val defaultWorkdir: String? = null,
|
||||
val defaultWorkspaceKind: String? = null,
|
||||
val projectId: String? = null,
|
||||
val projectName: String? = null,
|
||||
val createdAt: Long? = null,
|
||||
val archived: Boolean = false,
|
||||
) {
|
||||
val slug: String get() = id
|
||||
val displayName: String get() = name?.takeIf { it.isNotBlank() } ?: id
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class KanbanColumn(
|
||||
val name: String,
|
||||
val tasks: List<KanbanTask> = emptyList(),
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanBoardResponse(
|
||||
val columns: List<KanbanColumn> = emptyList(),
|
||||
val assignees: List<String>? = null,
|
||||
val tenants: List<String>? = null,
|
||||
val latestEventId: Long = 0L,
|
||||
val now: Long = 0L,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanBoardsResponse(
|
||||
val boards: List<KanbanBoard> = emptyList(),
|
||||
val current: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanProject(
|
||||
val id: String,
|
||||
val slug: String,
|
||||
val name: String,
|
||||
val primaryPath: String? = null,
|
||||
val icon: String? = null,
|
||||
val color: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanProjectsResponse(
|
||||
val projects: List<KanbanProject> = emptyList(),
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CreateBoardBody(
|
||||
val slug: String,
|
||||
val name: String? = null,
|
||||
val description: String? = null,
|
||||
val projectId: String? = null,
|
||||
val switch: Boolean = false,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CreateBoardResponse(
|
||||
val board: KanbanBoard? = null,
|
||||
val current: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class RenameBoardBody(
|
||||
val name: String? = null,
|
||||
val description: String? = null,
|
||||
val defaultWorkdir: String? = null,
|
||||
val projectId: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class RenameBoardResponse(
|
||||
val board: KanbanBoard? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class DeleteBoardResponse(
|
||||
val result: JsonElement? = null,
|
||||
val current: String? = null,
|
||||
)
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.m57.hermescontrol.data.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
|
||||
@Serializable
|
||||
data class KanbanProfile(
|
||||
val name: String,
|
||||
val isDefault: Boolean = false,
|
||||
val description: String = "",
|
||||
val descriptionAuto: Boolean = false,
|
||||
val model: String? = null,
|
||||
val provider: String? = null,
|
||||
val skillCount: Int = 0,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanProfilesResponse(
|
||||
val profiles: List<KanbanProfile> = emptyList(),
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class OrchestrationSettings(
|
||||
val orchestratorProfile: String = "",
|
||||
val defaultAssignee: String = "",
|
||||
val autoDecompose: Boolean = true,
|
||||
val autoPromoteChildren: Boolean = true,
|
||||
val resolvedOrchestratorProfile: String = "",
|
||||
val resolvedDefaultAssignee: String = "",
|
||||
val activeProfile: String = "default",
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class OrchestrationSettingsUpdate(
|
||||
val orchestratorProfile: String? = null,
|
||||
val defaultAssignee: String? = null,
|
||||
val autoDecompose: Boolean? = null,
|
||||
val autoPromoteChildren: Boolean? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class AutoDescribeResponse(
|
||||
val ok: Boolean = false,
|
||||
val profile: String? = null,
|
||||
val reason: String? = null,
|
||||
val description: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class BoardExportResult(
|
||||
val board: String,
|
||||
val archive: String,
|
||||
val size: Long = 0L,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class BoardImportResult(
|
||||
val board: String,
|
||||
val name: String = "",
|
||||
val renamed: Boolean = false,
|
||||
val requestedBoard: String = "",
|
||||
val counts: Map<String, Int> = emptyMap(),
|
||||
val warnings: List<String> = emptyList(),
|
||||
val current: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class DispatchResult(
|
||||
val spawned: List<JsonElement> = emptyList(),
|
||||
)
|
||||
@@ -0,0 +1,255 @@
|
||||
package com.m57.hermescontrol.data.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
|
||||
@Serializable
|
||||
data class TaskLinkCounts(
|
||||
val parents: Int = 0,
|
||||
val children: Int = 0,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TaskProgress(
|
||||
val done: Int = 0,
|
||||
val total: Int = 0,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TaskWarnings(
|
||||
val count: Int = 0,
|
||||
val highestSeverity: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TaskDiagnosticAction(
|
||||
val kind: String,
|
||||
val label: String,
|
||||
val payload: Map<String, JsonElement> = emptyMap(),
|
||||
val suggested: Boolean = false,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TaskDiagnostic(
|
||||
val kind: String,
|
||||
val severity: String,
|
||||
val title: String,
|
||||
val detail: String,
|
||||
val actions: List<TaskDiagnosticAction> = emptyList(),
|
||||
val count: Int = 1,
|
||||
val lastSeenAt: Long = 0L,
|
||||
val data: Map<String, JsonElement> = emptyMap(),
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TaskLinks(
|
||||
val parents: List<String> = emptyList(),
|
||||
val children: List<String> = emptyList(),
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ChildTaskResult(
|
||||
val id: String,
|
||||
val title: String,
|
||||
val status: String,
|
||||
val latestSummary: String? = null,
|
||||
val result: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class KanbanTask(
|
||||
val id: String,
|
||||
val title: String,
|
||||
val body: String? = null,
|
||||
val status: String,
|
||||
val assignee: String? = null,
|
||||
val priority: Int? = null,
|
||||
val tenant: String? = null,
|
||||
val createdAt: Long? = null,
|
||||
val latestSummary: String? = null,
|
||||
val commentCount: Int = 0,
|
||||
val linkCounts: TaskLinkCounts? = null,
|
||||
val progress: TaskProgress? = null,
|
||||
val warnings: TaskWarnings? = null,
|
||||
val startedAt: Long? = null,
|
||||
val workerPid: Int? = null,
|
||||
val lastHeartbeatAt: Long? = null,
|
||||
) {
|
||||
val description: String? get() = body
|
||||
val assignedTo: String? get() = assignee
|
||||
|
||||
constructor(
|
||||
id: String,
|
||||
title: String,
|
||||
description: String? = null,
|
||||
status: String,
|
||||
assignedTo: String? = null,
|
||||
) : this(
|
||||
id = id,
|
||||
title = title,
|
||||
body = description,
|
||||
status = status,
|
||||
assignee = assignedTo,
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class KanbanTaskFull(
|
||||
val id: String,
|
||||
val title: String,
|
||||
val body: String? = null,
|
||||
val status: String,
|
||||
val assignee: String? = null,
|
||||
val priority: Int? = null,
|
||||
val tenant: String? = null,
|
||||
val createdAt: Long? = null,
|
||||
val latestSummary: String? = null,
|
||||
val commentCount: Int = 0,
|
||||
val linkCounts: TaskLinkCounts? = null,
|
||||
val progress: TaskProgress? = null,
|
||||
val warnings: TaskWarnings? = null,
|
||||
val startedAt: Long? = null,
|
||||
val workerPid: Int? = null,
|
||||
val lastHeartbeatAt: Long? = null,
|
||||
val result: String? = null,
|
||||
val createdBy: String? = null,
|
||||
val modelOverride: String? = null,
|
||||
val providerOverride: String? = null,
|
||||
val reasoningEffort: String? = null,
|
||||
val completedAt: Long? = null,
|
||||
val lastFailureError: String? = null,
|
||||
val workspaceKind: String? = null,
|
||||
val workspacePath: String? = null,
|
||||
val branchName: String? = null,
|
||||
val consecutiveFailures: Int = 0,
|
||||
val diagnostics: List<TaskDiagnostic> = emptyList(),
|
||||
) {
|
||||
val description: String? get() = body
|
||||
val assignedTo: String? get() = assignee
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class KanbanTaskDetailResponse(
|
||||
val task: KanbanTaskFull,
|
||||
val comments: List<KanbanComment> = emptyList(),
|
||||
val events: List<KanbanDetailEvent> = emptyList(),
|
||||
val attachments: List<KanbanAttachment>? = null,
|
||||
val links: TaskLinks = TaskLinks(),
|
||||
val childResults: List<ChildTaskResult> = emptyList(),
|
||||
val runs: List<KanbanRun> = emptyList(),
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CreateTaskBody(
|
||||
val title: String,
|
||||
val body: String? = null,
|
||||
val assignee: String? = null,
|
||||
val tenant: String? = null,
|
||||
val priority: Int = 0,
|
||||
val workspaceKind: String? = null,
|
||||
val workspacePath: String? = null,
|
||||
val parents: List<String> = emptyList(),
|
||||
val triage: Boolean = false,
|
||||
val maxRuntimeSeconds: Int? = null,
|
||||
val skills: List<String>? = null,
|
||||
val goalMode: Boolean = false,
|
||||
val goalMaxTurns: Int? = null,
|
||||
val modelOverride: String? = null,
|
||||
val providerOverride: String? = null,
|
||||
val reasoningEffort: String? = null,
|
||||
val projectId: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CreateTaskResponse(
|
||||
val task: KanbanTask? = null,
|
||||
val warning: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class UpdateTaskBody(
|
||||
val status: String? = null,
|
||||
val assignee: String? = null,
|
||||
val priority: Int? = null,
|
||||
val title: String? = null,
|
||||
val body: String? = null,
|
||||
val result: String? = null,
|
||||
val blockReason: String? = null,
|
||||
val summary: String? = null,
|
||||
val metadata: Map<String, JsonElement>? = null,
|
||||
val modelOverride: String? = null,
|
||||
val providerOverride: String? = null,
|
||||
val clearModelOverride: Boolean = false,
|
||||
val reasoningEffort: String? = null,
|
||||
val clearReasoningEffort: Boolean = false,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class UpdateTaskResponse(
|
||||
val task: KanbanTask? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class BulkTasksBody(
|
||||
val ids: List<String>,
|
||||
val status: String? = null,
|
||||
val assignee: String? = null,
|
||||
val priority: Int? = null,
|
||||
val archive: Boolean = false,
|
||||
val result: String? = null,
|
||||
val summary: String? = null,
|
||||
val metadata: Map<String, JsonElement>? = null,
|
||||
val reclaimFirst: Boolean = false,
|
||||
val modelOverride: String? = null,
|
||||
val providerOverride: String? = null,
|
||||
val clearModelOverride: Boolean = false,
|
||||
val reasoningEffort: String? = null,
|
||||
val clearReasoningEffort: Boolean = false,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class BulkTaskResult(
|
||||
val id: String,
|
||||
val ok: Boolean,
|
||||
val error: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class BulkTasksResponse(
|
||||
val results: List<BulkTaskResult> = emptyList(),
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReassignTaskBody(
|
||||
val profile: String? = null,
|
||||
val reclaimFirst: Boolean = true,
|
||||
val reason: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReassignTaskResponse(
|
||||
val ok: Boolean = true,
|
||||
val taskId: String,
|
||||
val assignee: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReclaimTaskBody(
|
||||
val reason: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ReclaimTaskResponse(
|
||||
val ok: Boolean = true,
|
||||
val taskId: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TaskEstimate(
|
||||
val ok: Boolean,
|
||||
val reason: String? = null,
|
||||
val estTokens: Int? = null,
|
||||
val complexity: String? = null,
|
||||
val rationale: String? = null,
|
||||
val model: String? = null,
|
||||
)
|
||||
Reference in new issue
Block a user