5.10.1: Не сбрасывать подзадачи при быстрой прогрессии
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m22s

This commit is contained in:
poignatov
2026-03-04 15:11:11 +03:00
parent 81dc23b501
commit 98427f5d0e
4 changed files with 64 additions and 44 deletions

View File

@@ -1 +1 @@
5.10.0 5.10.1

View File

@@ -435,8 +435,8 @@ type PostponeTaskRequest struct {
type SaveDraftRequest struct { type SaveDraftRequest struct {
ProgressionValue *float64 `json:"progression_value,omitempty"` ProgressionValue *float64 `json:"progression_value,omitempty"`
ChildrenTaskIDs []int `json:"children_task_ids,omitempty"` // только checked подзадачи ChildrenTaskIDs *[]int `json:"children_task_ids,omitempty"` // только checked подзадачи, nil = не менять
AutoComplete bool `json:"auto_complete"` AutoComplete *bool `json:"auto_complete,omitempty"` // nil = не менять
} }
type TaskDraft struct { type TaskDraft struct {
@@ -9412,11 +9412,15 @@ func (a *App) saveTaskDraftHandler(w http.ResponseWriter, r *http.Request) {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
// Создаем новый драфт // Создаем новый драфт
autoComplete := false
if req.AutoComplete != nil {
autoComplete = *req.AutoComplete
}
err = tx.QueryRow(` err = tx.QueryRow(`
INSERT INTO task_drafts (task_id, user_id, progression_value, auto_complete, created_at, updated_at) INSERT INTO task_drafts (task_id, user_id, progression_value, auto_complete, created_at, updated_at)
VALUES ($1, $2, $3, $4, NOW(), NOW()) VALUES ($1, $2, $3, $4, NOW(), NOW())
RETURNING id RETURNING id
`, taskID, userID, progressionValue, req.AutoComplete).Scan(&draftID) `, taskID, userID, progressionValue, autoComplete).Scan(&draftID)
if err != nil { if err != nil {
log.Printf("Error creating draft: %v", err) log.Printf("Error creating draft: %v", err)
@@ -9429,36 +9433,50 @@ func (a *App) saveTaskDraftHandler(w http.ResponseWriter, r *http.Request) {
return return
} else { } else {
// Обновляем существующий драфт // Обновляем существующий драфт
// При обновлении очищаем auto_complete если параметр false // Обновляем только те поля, которые переданы
autoComplete := req.AutoComplete if req.ProgressionValue != nil || req.AutoComplete != nil {
_, err = tx.Exec(` if req.AutoComplete != nil {
UPDATE task_drafts // Обновляем оба поля
SET progression_value = $1, auto_complete = $2, updated_at = NOW() _, err = tx.Exec(`
WHERE id = $3 UPDATE task_drafts
`, progressionValue, autoComplete, draftID) SET progression_value = COALESCE($1, progression_value), auto_complete = $2, updated_at = NOW()
WHERE id = $3
`, progressionValue, *req.AutoComplete, draftID)
} else {
// Обновляем только progression_value
_, err = tx.Exec(`
UPDATE task_drafts
SET progression_value = $1, updated_at = NOW()
WHERE id = $2
`, progressionValue, draftID)
}
if err != nil { if err != nil {
log.Printf("Error updating draft: %v", err) log.Printf("Error updating draft: %v", err)
sendErrorWithCORS(w, fmt.Sprintf("Error updating draft: %v", err), http.StatusInternalServerError) sendErrorWithCORS(w, fmt.Sprintf("Error updating draft: %v", err), http.StatusInternalServerError)
return return
}
} }
// Удаляем все старые записи подзадач // Удаляем и обновляем записи подзадач только если они были переданы
_, err = tx.Exec("DELETE FROM task_draft_subtasks WHERE task_draft_id = $1", draftID) if req.ChildrenTaskIDs != nil {
if err != nil { _, err = tx.Exec("DELETE FROM task_draft_subtasks WHERE task_draft_id = $1", draftID)
log.Printf("Error deleting old draft subtasks: %v", err) if err != nil {
sendErrorWithCORS(w, fmt.Sprintf("Error deleting old draft subtasks: %v", err), http.StatusInternalServerError) log.Printf("Error deleting old draft subtasks: %v", err)
return sendErrorWithCORS(w, fmt.Sprintf("Error deleting old draft subtasks: %v", err), http.StatusInternalServerError)
return
}
} }
} }
// Вставляем новые записи подзадач (только checked подзадачи) // Вставляем новые записи подзадач (только checked подзадачи)
if len(req.ChildrenTaskIDs) > 0 { if req.ChildrenTaskIDs != nil && len(*req.ChildrenTaskIDs) > 0 {
childrenIDs := *req.ChildrenTaskIDs
// Проверяем, что все подзадачи принадлежат этой задаче // Проверяем, что все подзадачи принадлежат этой задаче
placeholders := make([]string, len(req.ChildrenTaskIDs)) placeholders := make([]string, len(childrenIDs))
args := make([]interface{}, len(req.ChildrenTaskIDs)+1) args := make([]interface{}, len(childrenIDs)+1)
args[0] = taskID args[0] = taskID
for i, id := range req.ChildrenTaskIDs { for i, id := range childrenIDs {
placeholders[i] = fmt.Sprintf("$%d", i+2) placeholders[i] = fmt.Sprintf("$%d", i+2)
args[i+1] = id args[i+1] = id
} }
@@ -9485,7 +9503,7 @@ func (a *App) saveTaskDraftHandler(w http.ResponseWriter, r *http.Request) {
} }
// Вставляем только валидные подзадачи // Вставляем только валидные подзадачи
for _, subtaskID := range req.ChildrenTaskIDs { for _, subtaskID := range childrenIDs {
if validSubtaskIDs[subtaskID] { if validSubtaskIDs[subtaskID] {
_, err = tx.Exec(` _, err = tx.Exec(`
INSERT INTO task_draft_subtasks (task_draft_id, subtask_id) INSERT INTO task_draft_subtasks (task_draft_id, subtask_id)
@@ -10019,7 +10037,8 @@ func (a *App) completeTaskAtEndOfDayHandler(w http.ResponseWriter, r *http.Reque
} }
// Устанавливаем auto_complete = true // Устанавливаем auto_complete = true
req.AutoComplete = true autoCompleteTrue := true
req.AutoComplete = &autoCompleteTrue
// Используем ту же логику что и saveTaskDraftHandler // Используем ту же логику что и saveTaskDraftHandler
// Начинаем транзакцию // Начинаем транзакцию
@@ -10046,7 +10065,7 @@ func (a *App) completeTaskAtEndOfDayHandler(w http.ResponseWriter, r *http.Reque
INSERT INTO task_drafts (task_id, user_id, progression_value, auto_complete, created_at, updated_at) INSERT INTO task_drafts (task_id, user_id, progression_value, auto_complete, created_at, updated_at)
VALUES ($1, $2, $3, $4, NOW(), NOW()) VALUES ($1, $2, $3, $4, NOW(), NOW())
RETURNING id RETURNING id
`, taskID, userID, progressionValue, req.AutoComplete).Scan(&draftID) `, taskID, userID, progressionValue, *req.AutoComplete).Scan(&draftID)
if err != nil { if err != nil {
log.Printf("Error creating draft: %v", err) log.Printf("Error creating draft: %v", err)
@@ -10063,7 +10082,7 @@ func (a *App) completeTaskAtEndOfDayHandler(w http.ResponseWriter, r *http.Reque
UPDATE task_drafts UPDATE task_drafts
SET progression_value = $1, auto_complete = $2, updated_at = NOW() SET progression_value = $1, auto_complete = $2, updated_at = NOW()
WHERE id = $3 WHERE id = $3
`, progressionValue, req.AutoComplete, draftID) `, progressionValue, *req.AutoComplete, draftID)
if err != nil { if err != nil {
log.Printf("Error updating draft: %v", err) log.Printf("Error updating draft: %v", err)
@@ -10071,22 +10090,25 @@ func (a *App) completeTaskAtEndOfDayHandler(w http.ResponseWriter, r *http.Reque
return return
} }
// Удаляем все старые записи подзадач // Удаляем все старые записи подзадач только если они были переданы
_, err = tx.Exec("DELETE FROM task_draft_subtasks WHERE task_draft_id = $1", draftID) if req.ChildrenTaskIDs != nil {
if err != nil { _, err = tx.Exec("DELETE FROM task_draft_subtasks WHERE task_draft_id = $1", draftID)
log.Printf("Error deleting old draft subtasks: %v", err) if err != nil {
sendErrorWithCORS(w, fmt.Sprintf("Error deleting old draft subtasks: %v", err), http.StatusInternalServerError) log.Printf("Error deleting old draft subtasks: %v", err)
return sendErrorWithCORS(w, fmt.Sprintf("Error deleting old draft subtasks: %v", err), http.StatusInternalServerError)
return
}
} }
} }
// Вставляем новые записи подзадач (только checked подзадачи) // Вставляем новые записи подзадач (только checked подзадачи)
if len(req.ChildrenTaskIDs) > 0 { if req.ChildrenTaskIDs != nil && len(*req.ChildrenTaskIDs) > 0 {
childrenIDs := *req.ChildrenTaskIDs
// Проверяем, что все подзадачи принадлежат этой задаче // Проверяем, что все подзадачи принадлежат этой задаче
placeholders := make([]string, len(req.ChildrenTaskIDs)) placeholders := make([]string, len(childrenIDs))
args := make([]interface{}, len(req.ChildrenTaskIDs)+1) args := make([]interface{}, len(childrenIDs)+1)
args[0] = taskID args[0] = taskID
for i, id := range req.ChildrenTaskIDs { for i, id := range childrenIDs {
placeholders[i] = fmt.Sprintf("$%d", i+2) placeholders[i] = fmt.Sprintf("$%d", i+2)
args[i+1] = id args[i+1] = id
} }
@@ -10113,7 +10135,7 @@ func (a *App) completeTaskAtEndOfDayHandler(w http.ResponseWriter, r *http.Reque
} }
// Вставляем только валидные подзадачи // Вставляем только валидные подзадачи
for _, subtaskID := range req.ChildrenTaskIDs { for _, subtaskID := range childrenIDs {
if validSubtaskIDs[subtaskID] { if validSubtaskIDs[subtaskID] {
_, err = tx.Exec(` _, err = tx.Exec(`
INSERT INTO task_draft_subtasks (task_draft_id, subtask_id) INSERT INTO task_draft_subtasks (task_draft_id, subtask_id)

View File

@@ -1,6 +1,6 @@
{ {
"name": "play-life-web", "name": "play-life-web",
"version": "5.10.0", "version": "5.10.1",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -566,9 +566,7 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, error, onRetry
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ body: JSON.stringify({
progression_value: newValue, progression_value: newValue
auto_complete: false,
children_task_ids: []
}), }),
}) })