feat(tasks): support subtasks with inline creation, checklist and title progress bar
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 54s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 54s
This commit is contained in:
1 parent
537b916533
commit
0ec1a8b7f7
7 files changed
+388
-58
No files matched your search
+24
-13
@@ -108,6 +108,7 @@ func (s *Store) migrate() error {
|
||||
kanban_status TEXT NOT NULL DEFAULT 'todo',
|
||||
notes TEXT NOT NULL DEFAULT '',
|
||||
alarm_sent INTEGER NOT NULL DEFAULT 0,
|
||||
subtasks TEXT NOT NULL DEFAULT '[]',
|
||||
created_at TEXT NOT NULL,
|
||||
triaged_at TEXT DEFAULT '',
|
||||
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
@@ -263,6 +264,7 @@ func (s *Store) migrate() error {
|
||||
"ALTER TABLE thoughts ADD COLUMN kanban_status TEXT NOT NULL DEFAULT 'todo';",
|
||||
"ALTER TABLE thoughts ADD COLUMN notes TEXT NOT NULL DEFAULT '';",
|
||||
"ALTER TABLE thoughts ADD COLUMN alarm_sent INTEGER NOT NULL DEFAULT 0;",
|
||||
"ALTER TABLE thoughts ADD COLUMN subtasks TEXT NOT NULL DEFAULT '[]';",
|
||||
|
||||
"ALTER TABLE documents ADD COLUMN folder_path TEXT NOT NULL DEFAULT '';",
|
||||
}
|
||||
@@ -645,13 +647,14 @@ func (s *Store) CreateThoughtWithDetails(userID, content, priority, source, dueD
|
||||
}
|
||||
|
||||
_, err := s.db.Exec(
|
||||
`INSERT INTO thoughts (id, user_id, content, tags, priority, source, status, is_completed, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, 0, ?)`,
|
||||
`INSERT INTO thoughts (id, user_id, content, tags, priority, source, status, is_completed, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, subtasks)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, 0, ?, '[]')`,
|
||||
t.ID, t.UserID, t.Content, string(tagsJSON), t.Priority, t.Source, string(t.Status), t.DueDate, t.TaskListID, t.KanbanStatus, t.Notes, t.CreatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.Subtasks = []domain.SubTask{}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
@@ -659,13 +662,13 @@ func scanThought(rows interface {
|
||||
Scan(dest ...any) error
|
||||
}) (*domain.Thought, error) {
|
||||
t := &domain.Thought{}
|
||||
var tagsStr, statusStr string
|
||||
var tagsStr, subtasksStr, statusStr string
|
||||
var isCompleted, alarmSent int
|
||||
err := rows.Scan(
|
||||
&t.ID, &t.UserID, &t.Content, &tagsStr, &t.Priority, &t.Source,
|
||||
&statusStr, &isCompleted, &t.ConvertedType, &t.ConvertedRefID,
|
||||
&t.DueDate, &t.TaskListID, &t.KanbanStatus, &t.Notes, &alarmSent,
|
||||
&t.CreatedAt, &t.TriagedAt,
|
||||
&t.CreatedAt, &t.TriagedAt, &subtasksStr,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -682,12 +685,16 @@ func scanThought(rows interface {
|
||||
}
|
||||
t.Tags = []string{}
|
||||
_ = json.Unmarshal([]byte(tagsStr), &t.Tags)
|
||||
t.Subtasks = []domain.SubTask{}
|
||||
if subtasksStr != "" && subtasksStr != "null" {
|
||||
_ = json.Unmarshal([]byte(subtasksStr), &t.Subtasks)
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetThoughtByID(userID, thoughtID string) (*domain.Thought, error) {
|
||||
row := s.db.QueryRow(
|
||||
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at
|
||||
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at, subtasks
|
||||
FROM thoughts WHERE id = ? AND (user_id = ? OR task_list_id IN (SELECT id FROM task_lists WHERE space_id IN (SELECT space_id FROM space_members WHERE user_id = ?)))`,
|
||||
thoughtID, userID, userID,
|
||||
)
|
||||
@@ -703,14 +710,14 @@ func (s *Store) GetThoughts(userID, statusFilter string, limit int) ([]domain.Th
|
||||
|
||||
if statusFilter != "" && statusFilter != "all" {
|
||||
rows, err = s.db.Query(
|
||||
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at
|
||||
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at, subtasks
|
||||
FROM thoughts WHERE user_id = ? AND status = ?
|
||||
ORDER BY CASE priority WHEN 'urgent' THEN 1 WHEN 'high' THEN 2 WHEN 'normal' THEN 3 ELSE 4 END, created_at DESC LIMIT ?`,
|
||||
userID, statusFilter, limit,
|
||||
)
|
||||
} else {
|
||||
rows, err = s.db.Query(
|
||||
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at
|
||||
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at, subtasks
|
||||
FROM thoughts WHERE user_id = ?
|
||||
ORDER BY created_at DESC LIMIT ?`,
|
||||
userID, limit,
|
||||
@@ -736,7 +743,7 @@ func (s *Store) GetTasks(userID string, taskListID string) ([]domain.Thought, er
|
||||
var err error
|
||||
if taskListID != "" {
|
||||
rows, err = s.db.Query(
|
||||
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at
|
||||
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at, subtasks
|
||||
FROM thoughts
|
||||
WHERE (user_id = ? OR task_list_id IN (SELECT id FROM task_lists WHERE space_id IN (SELECT space_id FROM space_members WHERE user_id = ?)))
|
||||
AND task_list_id = ?
|
||||
@@ -746,7 +753,7 @@ func (s *Store) GetTasks(userID string, taskListID string) ([]domain.Thought, er
|
||||
)
|
||||
} else {
|
||||
rows, err = s.db.Query(
|
||||
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at
|
||||
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at, subtasks
|
||||
FROM thoughts
|
||||
WHERE (user_id = ? OR task_list_id IN (SELECT id FROM task_lists WHERE space_id IN (SELECT space_id FROM space_members WHERE user_id = ?)))
|
||||
AND (status = 'kept' OR (status = 'converted' AND converted_type = 'task'))
|
||||
@@ -839,7 +846,7 @@ func (s *Store) UpdateThoughtTriage(userID, thoughtID, action, convertTo, target
|
||||
return s.GetThoughtByID(userID, thoughtID)
|
||||
}
|
||||
|
||||
func (s *Store) UpdateThoughtDetails(userID, thoughtID string, content *string, isCompleted *bool, dueDate *string, priority *string, taskListID *string, kanbanStatus *string, notes *string) (*domain.Thought, error) {
|
||||
func (s *Store) UpdateThoughtDetails(userID, thoughtID string, content *string, isCompleted *bool, dueDate *string, priority *string, taskListID *string, kanbanStatus *string, notes *string, subtasks *[]domain.SubTask) (*domain.Thought, error) {
|
||||
thought, err := s.GetThoughtByID(userID, thoughtID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -877,16 +884,20 @@ func (s *Store) UpdateThoughtDetails(userID, thoughtID string, content *string,
|
||||
if notes != nil {
|
||||
thought.Notes = *notes
|
||||
}
|
||||
if subtasks != nil {
|
||||
thought.Subtasks = *subtasks
|
||||
}
|
||||
|
||||
tagsJSON, _ := json.Marshal(thought.Tags)
|
||||
subtasksJSON, _ := json.Marshal(thought.Subtasks)
|
||||
completedInt := 0
|
||||
if thought.IsCompleted {
|
||||
completedInt = 1
|
||||
}
|
||||
|
||||
_, err = s.db.Exec(
|
||||
`UPDATE thoughts SET content = ?, tags = ?, is_completed = ?, due_date = ?, priority = ?, task_list_id = ?, kanban_status = ?, notes = ? WHERE id = ? AND user_id = ?`,
|
||||
thought.Content, string(tagsJSON), completedInt, thought.DueDate, thought.Priority, thought.TaskListID, thought.KanbanStatus, thought.Notes, thoughtID, userID,
|
||||
`UPDATE thoughts SET content = ?, tags = ?, is_completed = ?, due_date = ?, priority = ?, task_list_id = ?, kanban_status = ?, notes = ?, subtasks = ? WHERE id = ? AND user_id = ?`,
|
||||
thought.Content, string(tagsJSON), completedInt, thought.DueDate, thought.Priority, thought.TaskListID, thought.KanbanStatus, thought.Notes, string(subtasksJSON), thoughtID, userID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1574,7 +1585,7 @@ func (s *Store) SearchAll(userID, query string) ([]domain.Thought, []domain.Docu
|
||||
q := "%" + strings.ToLower(strings.TrimSpace(query)) + "%"
|
||||
|
||||
tRows, err := s.db.Query(
|
||||
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at
|
||||
`SELECT id, user_id, content, tags, priority, source, status, is_completed, converted_type, converted_ref_id, due_date, task_list_id, kanban_status, notes, alarm_sent, created_at, triaged_at, subtasks
|
||||
FROM thoughts WHERE user_id = ? AND LOWER(content) LIKE ? ORDER BY created_at DESC LIMIT 30`,
|
||||
userID, q,
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user