Skip to content

Commit 45bf139

Browse files
committed
feat(ui): enhance section status handling and UI updates #331
- Added status indicators for sections based on task completion - Updated section completion status when task status changes - Improved UI revalidation and repaint logic - Enhanced Markdown parsing to handle section status markers
1 parent fe3dfc8 commit 45bf139

File tree

3 files changed

+112
-26
lines changed

3 files changed

+112
-26
lines changed

core/src/main/kotlin/cc/unitmesh/devti/observer/agent/PlanList.kt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,24 @@ import kotlinx.serialization.Serializable
66
data class PlanList(
77
val title: String,
88
val planTasks: List<PlanTask>,
9-
val completed: Boolean = false
10-
)
9+
var completed: Boolean = false,
10+
var status: TaskStatus = TaskStatus.TODO
11+
) {
12+
/**
13+
* Updates the completion status based on the tasks' statuses
14+
*/
15+
fun updateCompletionStatus() {
16+
if (planTasks.isEmpty()) return
17+
18+
// Check if all tasks are completed
19+
completed = planTasks.all { it.status == TaskStatus.COMPLETED }
20+
21+
// Determine section status based on tasks
22+
status = when {
23+
planTasks.all { it.status == TaskStatus.COMPLETED } -> TaskStatus.COMPLETED
24+
planTasks.any { it.status == TaskStatus.FAILED } -> TaskStatus.FAILED
25+
planTasks.any { it.status == TaskStatus.IN_PROGRESS } -> TaskStatus.IN_PROGRESS
26+
else -> TaskStatus.TODO
27+
}
28+
}
29+
}

core/src/main/kotlin/cc/unitmesh/devti/sketch/ui/ThoughtPlanSketchProvider.kt

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,22 @@ class PlanSketch(
106106
border = JBUI.Borders.empty()
107107
}
108108

109-
val titleText = if (planItem.completed)
110-
"<html><b>${index + 1}. ${planItem.title} ✓</b></html>"
111-
else
109+
// Check if all tasks in the section are completed
110+
updateSectionCompletionStatus(planItem)
111+
112+
// Create a formatted title with the appropriate status marker
113+
val statusIndicator = when (planItem.status) {
114+
TaskStatus.COMPLETED -> ""
115+
TaskStatus.FAILED -> "!"
116+
TaskStatus.IN_PROGRESS -> "*"
117+
TaskStatus.TODO -> ""
118+
}
119+
120+
val titleText = if (statusIndicator.isNotEmpty()) {
121+
"<html><b>${index + 1}. ${planItem.title} [$statusIndicator]</b></html>"
122+
} else {
112123
"<html><b>${index + 1}. ${planItem.title}</b></html>"
124+
}
113125

114126
val sectionLabel = JLabel(titleText)
115127
sectionLabel.border = JBUI.Borders.empty()
@@ -138,7 +150,14 @@ class PlanSketch(
138150
} else {
139151
task.updateStatus(TaskStatus.TODO)
140152
}
153+
154+
// Update section status when task status changes
155+
val currentSection = planLists.find { it.planTasks.contains(task) }
156+
currentSection?.let { updateSectionCompletionStatus(it) }
157+
141158
updateTaskLabel(taskLabel, task)
159+
contentPanel.revalidate()
160+
contentPanel.repaint()
142161
}
143162
isBorderPainted = false
144163
isContentAreaFilled = false
@@ -176,27 +195,44 @@ class PlanSketch(
176195
markCompletedItem.addActionListener {
177196
task.updateStatus(TaskStatus.COMPLETED)
178197
updateTaskLabel(taskLabel, task)
198+
199+
// Update section status after changing task status
200+
val currentSection = planLists.find { it.planTasks.contains(task) }
201+
currentSection?.let { updateSectionCompletionStatus(it) }
202+
179203
contentPanel.revalidate()
180204
contentPanel.repaint()
181205
}
182206

183207
markInProgressItem.addActionListener {
184208
task.updateStatus(TaskStatus.IN_PROGRESS)
185209
updateTaskLabel(taskLabel, task)
210+
211+
val currentSection = planLists.find { it.planTasks.contains(task) }
212+
currentSection?.let { updateSectionCompletionStatus(it) }
213+
186214
contentPanel.revalidate()
187215
contentPanel.repaint()
188216
}
189217

190218
markFailedItem.addActionListener {
191219
task.updateStatus(TaskStatus.FAILED)
192220
updateTaskLabel(taskLabel, task)
221+
222+
val currentSection = planLists.find { it.planTasks.contains(task) }
223+
currentSection?.let { updateSectionCompletionStatus(it) }
224+
193225
contentPanel.revalidate()
194226
contentPanel.repaint()
195227
}
196228

197229
markTodoItem.addActionListener {
198230
task.updateStatus(TaskStatus.TODO)
199231
updateTaskLabel(taskLabel, task)
232+
233+
val currentSection = planLists.find { it.planTasks.contains(task) }
234+
currentSection?.let { updateSectionCompletionStatus(it) }
235+
200236
contentPanel.revalidate()
201237
contentPanel.repaint()
202238
}
@@ -241,6 +277,16 @@ class PlanSketch(
241277
}
242278
}
243279

280+
// Helper method to update section completion status based on tasks
281+
private fun updateSectionCompletionStatus(planItem: PlanList) {
282+
// Use the new method instead of reflection
283+
planItem.updateCompletionStatus()
284+
285+
// Update the UI to reflect the new status
286+
contentPanel.revalidate()
287+
contentPanel.repaint()
288+
}
289+
244290
override fun getExtensionName(): String = "ThoughtPlan"
245291

246292
override fun getViewText(): String = content

core/src/main/kotlin/cc/unitmesh/devti/sketch/ui/plan/MarkdownPlanParser.kt

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cc.unitmesh.devti.sketch.ui.plan
22

33
import cc.unitmesh.devti.observer.agent.PlanList
44
import cc.unitmesh.devti.observer.agent.PlanTask
5+
import cc.unitmesh.devti.observer.agent.TaskStatus
56
import com.intellij.openapi.diagnostic.logger
67
import org.intellij.markdown.IElementType
78
import org.intellij.markdown.MarkdownElementTypes
@@ -95,6 +96,7 @@ object MarkdownPlanParser {
9596
var currentSectionTitle = ""
9697
var currentSectionItems = mutableListOf<PlanTask>()
9798
var currentSectionCompleted = false
99+
var currentSectionStatus = TaskStatus.TODO
98100

99101
node.accept(object : RecursiveVisitor() {
100102
override fun visitNode(node: ASTNode) {
@@ -111,26 +113,39 @@ object MarkdownPlanParser {
111113
listItemFullText
112114
}
113115

114-
// Extract the title and completion status
115-
val titleMatch = "^(\\d+)\\.\\s*(.+?)(?:\\s*$CHECKMARK)?$".toRegex().find(listItemFirstLine)
116-
117-
if (titleMatch != null) {
116+
// Check for section status marker like "1. Section Title [✓]"
117+
val sectionStatusMatch = "^(\\d+)\\.\\s*(.+?)(?:\\s*\\[(.)\\])?$".toRegex().find(listItemFirstLine)
118+
119+
if (sectionStatusMatch != null) {
118120
// Save previous section if exists
119121
if (currentSectionTitle.isNotEmpty()) {
120-
planLists.add(
121-
PlanList(
122-
currentSectionTitle,
123-
currentSectionItems.toList(),
124-
currentSectionCompleted
125-
)
122+
// Create new PlanList with stored data
123+
val newPlanList = PlanList(
124+
currentSectionTitle,
125+
currentSectionItems.toList(),
126+
currentSectionCompleted,
127+
currentSectionStatus
126128
)
129+
130+
// Update section completion status based on tasks
131+
newPlanList.updateCompletionStatus()
132+
133+
planLists.add(newPlanList)
127134
currentSectionItems = mutableListOf()
128135
}
129136

130-
// Extract the title without the checkmark
131-
currentSectionTitle = titleMatch.groupValues[2].trim()
132-
// Check if section is marked as completed
133-
currentSectionCompleted = listItemFirstLine.contains(CHECKMARK)
137+
// Extract the title without any status marker
138+
currentSectionTitle = sectionStatusMatch.groupValues[2].trim()
139+
140+
// Check for section status marker
141+
val statusMarker = sectionStatusMatch.groupValues.getOrNull(3)
142+
currentSectionCompleted = statusMarker == "" || statusMarker == "x" || statusMarker == "X"
143+
currentSectionStatus = when (statusMarker) {
144+
"", "x", "X" -> TaskStatus.COMPLETED
145+
"!" -> TaskStatus.FAILED
146+
"*" -> TaskStatus.IN_PROGRESS
147+
else -> TaskStatus.TODO
148+
}
134149

135150
// Process child nodes for tasks
136151
listItemNode.children.forEach { childNode ->
@@ -159,13 +174,18 @@ object MarkdownPlanParser {
159174

160175
// 添加最后一个章节(如果有)
161176
if (currentSectionTitle.isNotEmpty()) {
162-
planLists.add(
163-
PlanList(
164-
currentSectionTitle,
165-
currentSectionItems.toList(),
166-
currentSectionCompleted
167-
)
177+
// Create new PlanList with stored data
178+
val newPlanList = PlanList(
179+
currentSectionTitle,
180+
currentSectionItems.toList(),
181+
currentSectionCompleted,
182+
currentSectionStatus
168183
)
184+
185+
// Update section completion status based on tasks
186+
newPlanList.updateCompletionStatus()
187+
188+
planLists.add(newPlanList)
169189
}
170190
}
171191

@@ -217,7 +237,8 @@ object MarkdownPlanParser {
217237
// Process task text and retain the checkmark in the text (original behavior)
218238
val cleanTaskText = taskFirstLine.replace(Regex("^[\\-\\*]\\s+"), "").trim()
219239
if (cleanTaskText.isNotEmpty()) {
220-
itemsList.add(PlanTask.fromText(cleanTaskText))
240+
// If there's no explicit checkbox, treat as completed
241+
itemsList.add(PlanTask(cleanTaskText, true, TaskStatus.COMPLETED))
221242
}
222243
}
223244
}

0 commit comments

Comments
 (0)