fix(tasks): reset description checklist when a recurring task recurs (#2941)
This commit is contained in:
parent
adf031128e
commit
767ce3bc7e
|
|
@ -1747,6 +1747,20 @@ func setTaskDatesFromCurrentDateRepeat(oldTask, newTask *Task) {
|
|||
newTask.Done = false
|
||||
}
|
||||
|
||||
var (
|
||||
checklistTiptapCheckedRegex = regexp.MustCompile(`(data-checked=")true(")`)
|
||||
checklistInputCheckedRegex = regexp.MustCompile(`(<input[^>]*type=["']checkbox["'][^>]*?)\s+checked(?:=["'][^"']*["'])?`)
|
||||
)
|
||||
|
||||
// resetDescriptionChecklist unchecks every checklist item in a TipTap HTML description
|
||||
// (descriptions are always stored as HTML, never markdown) without touching other content,
|
||||
// so a recurring task's next occurrence does not inherit checked items.
|
||||
func resetDescriptionChecklist(description string) string {
|
||||
description = checklistTiptapCheckedRegex.ReplaceAllString(description, "${1}false${2}")
|
||||
description = checklistInputCheckedRegex.ReplaceAllString(description, "$1")
|
||||
return description
|
||||
}
|
||||
|
||||
// This helper function updates the reminders, doneAt, start, end and due dates of the *old* task
|
||||
// and saves the new values in the newTask object.
|
||||
// We make a few assumptions here:
|
||||
|
|
@ -1766,6 +1780,11 @@ func updateDone(oldTask *Task, newTask *Task) (updateDoneAt bool) {
|
|||
setTaskDatesDefault(oldTask, newTask)
|
||||
}
|
||||
|
||||
// A recurring task reopens for its next occurrence, so its checklist starts fresh.
|
||||
if oldTask.isRepeating() && !newTask.Done {
|
||||
newTask.Description = resetDescriptionChecklist(newTask.Description)
|
||||
}
|
||||
|
||||
newTask.DoneAt = time.Now()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -986,6 +986,45 @@ func TestUpdateDone(t *testing.T) {
|
|||
assert.False(t, newTask.Done)
|
||||
})
|
||||
})
|
||||
t.Run("reset checklist on recurrence", func(t *testing.T) {
|
||||
const checked = `before<ul data-type="taskList"><li data-checked="true" data-type="taskItem"><label><input type="checkbox" checked="checked"><span></span></label><div><p>Item</p></li></ul>after`
|
||||
const unchecked = `before<ul data-type="taskList"><li data-checked="false" data-type="taskItem"><label><input type="checkbox"><span></span></label><div><p>Item</p></li></ul>after`
|
||||
|
||||
oldTask := &Task{
|
||||
Done: false,
|
||||
RepeatAfter: 8600,
|
||||
DueDate: time.Unix(1550000000, 0),
|
||||
}
|
||||
newTask := &Task{
|
||||
Done: true,
|
||||
Description: checked,
|
||||
}
|
||||
|
||||
updateDone(oldTask, newTask)
|
||||
|
||||
assert.False(t, newTask.Done)
|
||||
assert.True(t, newTask.DueDate.After(oldTask.DueDate))
|
||||
assert.Equal(t, unchecked, newTask.Description)
|
||||
})
|
||||
t.Run("non-recurring description untouched", func(t *testing.T) {
|
||||
const checked = `before<ul data-type="taskList"><li data-checked="true" data-type="taskItem"><label><input type="checkbox" checked="checked"><span></span></label><div><p>Item</p></li></ul>after`
|
||||
|
||||
oldTask := &Task{
|
||||
Done: false,
|
||||
RepeatAfter: 0,
|
||||
RepeatMode: TaskRepeatModeDefault,
|
||||
DueDate: time.Unix(1550000000, 0),
|
||||
}
|
||||
newTask := &Task{
|
||||
Done: true,
|
||||
Description: checked,
|
||||
}
|
||||
|
||||
updateDone(oldTask, newTask)
|
||||
|
||||
assert.True(t, newTask.Done)
|
||||
assert.Equal(t, checked, newTask.Description)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue