diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go
index 2298dea..e79a539 100644
--- a/backend/cmd/server/main.go
+++ b/backend/cmd/server/main.go
@@ -288,12 +288,12 @@ func main() {
api.HandleFunc("/spaces/{spaceId}/tasks/{taskId}/notes/{noteId}", taskHandler.UnlinkTaskNote).Methods("DELETE")
api.HandleFunc("/spaces/{spaceId}/notes/{noteId}/tasks", taskHandler.ListTasksByNote).Methods("GET")
- // Task status endpoints
- api.HandleFunc("/spaces/{spaceId}/task-statuses", taskHandler.ListStatuses).Methods("GET")
- api.HandleFunc("/spaces/{spaceId}/task-statuses", taskHandler.CreateStatus).Methods("POST")
- api.HandleFunc("/spaces/{spaceId}/task-statuses/reorder", taskHandler.ReorderStatuses).Methods("PUT")
- api.HandleFunc("/spaces/{spaceId}/task-statuses/{statusId}", taskHandler.UpdateStatus).Methods("PUT")
- api.HandleFunc("/spaces/{spaceId}/task-statuses/{statusId}", taskHandler.DeleteStatus).Methods("DELETE")
+ // Task status endpoints (scoped to task list)
+ api.HandleFunc("/spaces/{spaceId}/task-lists/{taskListId}/statuses", taskHandler.ListStatuses).Methods("GET")
+ api.HandleFunc("/spaces/{spaceId}/task-lists/{taskListId}/statuses", taskHandler.CreateStatus).Methods("POST")
+ api.HandleFunc("/spaces/{spaceId}/task-lists/{taskListId}/statuses/reorder", taskHandler.ReorderStatuses).Methods("PUT")
+ api.HandleFunc("/spaces/{spaceId}/task-lists/{taskListId}/statuses/{statusId}", taskHandler.UpdateStatus).Methods("PUT")
+ api.HandleFunc("/spaces/{spaceId}/task-lists/{taskListId}/statuses/{statusId}", taskHandler.DeleteStatus).Methods("DELETE")
// File explorer endpoints (space-scoped)
api.HandleFunc("/spaces/{spaceId}/files/list", fileHandler.ListFiles).Methods("GET")
diff --git a/backend/internal/application/dto/dto.go b/backend/internal/application/dto/dto.go
index 46afb45..ea30db8 100644
--- a/backend/internal/application/dto/dto.go
+++ b/backend/internal/application/dto/dto.go
@@ -530,13 +530,13 @@ type ReorderTaskStatusesRequest struct {
// TaskStatusDTO represents a task status in API responses.
type TaskStatusDTO struct {
- ID string `json:"id"`
- SpaceID string `json:"space_id"`
- Name string `json:"name"`
- Color string `json:"color,omitempty"`
- Order int `json:"order"`
- CreatedAt string `json:"created_at"`
- UpdatedAt string `json:"updated_at"`
+ ID string `json:"id"`
+ TaskListID string `json:"task_list_id"`
+ Name string `json:"name"`
+ Color string `json:"color,omitempty"`
+ Order int `json:"order"`
+ CreatedAt string `json:"created_at"`
+ UpdatedAt string `json:"updated_at"`
}
// CreateTaskListRequest represents task list creation input.
@@ -620,13 +620,13 @@ func NewTaskListDTO(taskList *entities.TaskList) *TaskListDTO {
// NewTaskStatusDTO creates a DTO from a task status entity.
func NewTaskStatusDTO(status *entities.TaskStatus) *TaskStatusDTO {
return &TaskStatusDTO{
- ID: status.ID.Hex(),
- SpaceID: status.SpaceID.Hex(),
- Name: status.Name,
- Color: status.Color,
- Order: status.Order,
- CreatedAt: status.CreatedAt.Format("2006-01-02T15:04:05Z"),
- UpdatedAt: status.UpdatedAt.Format("2006-01-02T15:04:05Z"),
+ ID: status.ID.Hex(),
+ TaskListID: status.TaskListID.Hex(),
+ Name: status.Name,
+ Color: status.Color,
+ Order: status.Order,
+ CreatedAt: status.CreatedAt.Format("2006-01-02T15:04:05Z"),
+ UpdatedAt: status.UpdatedAt.Format("2006-01-02T15:04:05Z"),
}
}
diff --git a/backend/internal/application/services/task_service.go b/backend/internal/application/services/task_service.go
index 19b0f13..af7ee3b 100644
--- a/backend/internal/application/services/task_service.go
+++ b/backend/internal/application/services/task_service.go
@@ -46,8 +46,8 @@ func NewTaskService(
}
}
-func (s *TaskService) ensureDefaultStatuses(ctx context.Context, spaceID bson.ObjectID) error {
- statuses, err := s.taskStatusRepo.ListStatuses(ctx, spaceID)
+func (s *TaskService) ensureDefaultStatuses(ctx context.Context, taskListID bson.ObjectID) error {
+ statuses, err := s.taskStatusRepo.ListStatuses(ctx, taskListID)
if err != nil {
return err
}
@@ -66,10 +66,10 @@ func (s *TaskService) ensureDefaultStatuses(ctx context.Context, spaceID bson.Ob
for idx, status := range defaults {
if err := s.taskStatusRepo.CreateStatus(ctx, &entities.TaskStatus{
- SpaceID: spaceID,
- Name: status.name,
- Color: status.color,
- Order: idx,
+ TaskListID: taskListID,
+ Name: status.name,
+ Color: status.color,
+ Order: idx,
}); err != nil {
return err
}
@@ -142,9 +142,9 @@ func (s *TaskService) validateNoteLinks(ctx context.Context, spaceID bson.Object
return nil
}
-func (s *TaskService) validateStatus(ctx context.Context, spaceID, statusID bson.ObjectID) (*entities.TaskStatus, error) {
+func (s *TaskService) validateStatus(ctx context.Context, taskListID, statusID bson.ObjectID) (*entities.TaskStatus, error) {
status, err := s.taskStatusRepo.GetStatusByID(ctx, statusID)
- if err != nil || status.SpaceID != spaceID {
+ if err != nil || status.TaskListID != taskListID {
return nil, errors.New("invalid task status")
}
return status, nil
@@ -165,11 +165,11 @@ func (s *TaskService) resolveDepthAndParent(ctx context.Context, spaceID bson.Ob
return depth, nil
}
-func (s *TaskService) isAdjacentStatusMove(ctx context.Context, spaceID, currentStatusID, requestedStatusID bson.ObjectID) (bool, error) {
+func (s *TaskService) isAdjacentStatusMove(ctx context.Context, taskListID, currentStatusID, requestedStatusID bson.ObjectID) (bool, error) {
if currentStatusID == requestedStatusID {
return true, nil
}
- statuses, err := s.taskStatusRepo.ListStatuses(ctx, spaceID)
+ statuses, err := s.taskStatusRepo.ListStatuses(ctx, taskListID)
if err != nil {
return false, err
}
@@ -205,10 +205,6 @@ func (s *TaskService) CreateTask(ctx context.Context, spaceID, userID bson.Objec
return nil, errors.New("insufficient permissions")
}
- if err := s.ensureDefaultStatuses(ctx, spaceID); err != nil {
- return nil, err
- }
-
parentTaskID, err := toObjectIDPtr(req.ParentTaskID)
if err != nil {
return nil, errors.New("invalid parent task")
@@ -226,6 +222,10 @@ func (s *TaskService) CreateTask(ctx context.Context, spaceID, userID bson.Objec
return nil, err
}
+ if err := s.ensureDefaultStatuses(ctx, taskListID); err != nil {
+ return nil, err
+ }
+
noteLinks, err := toObjectIDs(req.NoteLinks)
if err != nil {
return nil, err
@@ -234,7 +234,7 @@ func (s *TaskService) CreateTask(ctx context.Context, spaceID, userID bson.Objec
return nil, err
}
- statuses, err := s.taskStatusRepo.ListStatuses(ctx, spaceID)
+ statuses, err := s.taskStatusRepo.ListStatuses(ctx, taskListID)
if err != nil {
return nil, err
}
@@ -252,7 +252,7 @@ func (s *TaskService) CreateTask(ctx context.Context, spaceID, userID bson.Objec
if parseErr != nil {
return nil, errors.New("invalid task status")
}
- if _, validateErr := s.validateStatus(ctx, spaceID, parsedStatusID); validateErr != nil {
+ if _, validateErr := s.validateStatus(ctx, taskListID, parsedStatusID); validateErr != nil {
return nil, validateErr
}
statusID = parsedStatusID
@@ -299,7 +299,7 @@ func (s *TaskService) GetTaskByID(ctx context.Context, spaceID, taskID, userID b
return nil, errors.New("task not found")
}
- status, err := s.validateStatus(ctx, spaceID, task.StatusID)
+ status, err := s.validateStatus(ctx, task.TaskListID, task.StatusID)
if err != nil {
return nil, err
}
@@ -331,9 +331,6 @@ func (s *TaskService) ListTasks(
if err := s.requireSpaceAccess(ctx, userID, spaceID); err != nil {
return nil, err
}
- if err := s.ensureDefaultStatuses(ctx, spaceID); err != nil {
- return nil, err
- }
filters := map[string]any{}
if taskListID != nil && strings.TrimSpace(*taskListID) != "" {
@@ -403,23 +400,33 @@ func (s *TaskService) ListTasksLinkedToNote(ctx context.Context, spaceID, noteID
if _, err := s.noteRepo.GetNoteByID(ctx, noteID); err != nil {
return nil, errors.New("note not found")
}
- statuses, err := s.taskStatusRepo.ListStatuses(ctx, spaceID)
- if err != nil {
- return nil, err
- }
- statusByID := map[bson.ObjectID]*entities.TaskStatus{}
- for _, status := range statuses {
- statusByID[status.ID] = status
- }
tasks, err := s.taskRepo.ListTasks(ctx, spaceID, map[string]any{"note_links": noteID})
if err != nil {
return nil, err
}
+ // Collect statuses per task list
+ statusCache := map[bson.ObjectID]map[bson.ObjectID]*entities.TaskStatus{}
+ getStatus := func(taskListID, statusID bson.ObjectID) *entities.TaskStatus {
+ byID, ok := statusCache[taskListID]
+ if !ok {
+ statuses, err := s.taskStatusRepo.ListStatuses(ctx, taskListID)
+ if err != nil {
+ return nil
+ }
+ byID = make(map[bson.ObjectID]*entities.TaskStatus, len(statuses))
+ for _, st := range statuses {
+ byID[st.ID] = st
+ }
+ statusCache[taskListID] = byID
+ }
+ return byID[statusID]
+ }
+
result := make([]*dto.TaskWithStatusDTO, 0, len(tasks))
for _, task := range tasks {
- status := statusByID[task.StatusID]
+ status := getStatus(task.TaskListID, task.StatusID)
if status == nil {
continue
}
@@ -509,10 +516,10 @@ func (s *TaskService) UpdateTask(ctx context.Context, spaceID, taskID, userID bs
if parseErr != nil {
return nil, errors.New("invalid status")
}
- if _, err := s.validateStatus(ctx, spaceID, statusID); err != nil {
+ if _, err := s.validateStatus(ctx, task.TaskListID, statusID); err != nil {
return nil, err
}
- adjacent, err := s.isAdjacentStatusMove(ctx, spaceID, task.StatusID, statusID)
+ adjacent, err := s.isAdjacentStatusMove(ctx, task.TaskListID, task.StatusID, statusID)
if err != nil {
return nil, err
}
@@ -582,7 +589,7 @@ func (s *TaskService) TransitionTaskStatus(ctx context.Context, spaceID, taskID,
return nil, errors.New("task not found")
}
- statuses, err := s.taskStatusRepo.ListStatuses(ctx, spaceID)
+ statuses, err := s.taskStatusRepo.ListStatuses(ctx, task.TaskListID)
if err != nil {
return nil, err
}
@@ -816,17 +823,24 @@ func (s *TaskService) DeleteTaskList(ctx context.Context, spaceID, taskListID, u
return err
}
+ if err := s.taskStatusRepo.DeleteStatusesByTaskListID(ctx, taskListID); err != nil {
+ return err
+ }
+
return s.taskListRepo.DeleteTaskList(ctx, taskListID)
}
-func (s *TaskService) ListStatuses(ctx context.Context, spaceID, userID bson.ObjectID) ([]*dto.TaskStatusDTO, error) {
+func (s *TaskService) ListStatuses(ctx context.Context, spaceID, taskListID, userID bson.ObjectID) ([]*dto.TaskStatusDTO, error) {
if err := s.requireSpaceAccess(ctx, userID, spaceID); err != nil {
return nil, err
}
- if err := s.ensureDefaultStatuses(ctx, spaceID); err != nil {
+ if err := s.validateTaskList(ctx, spaceID, taskListID); err != nil {
return nil, err
}
- statuses, err := s.taskStatusRepo.ListStatuses(ctx, spaceID)
+ if err := s.ensureDefaultStatuses(ctx, taskListID); err != nil {
+ return nil, err
+ }
+ statuses, err := s.taskStatusRepo.ListStatuses(ctx, taskListID)
if err != nil {
return nil, err
}
@@ -837,7 +851,7 @@ func (s *TaskService) ListStatuses(ctx context.Context, spaceID, userID bson.Obj
return result, nil
}
-func (s *TaskService) CreateStatus(ctx context.Context, spaceID, userID bson.ObjectID, req *dto.CreateTaskStatusRequest) (*dto.TaskStatusDTO, error) {
+func (s *TaskService) CreateStatus(ctx context.Context, spaceID, taskListID, userID bson.ObjectID, req *dto.CreateTaskStatusRequest) (*dto.TaskStatusDTO, error) {
if err := s.requireSpaceAccess(ctx, userID, spaceID); err != nil {
return nil, err
}
@@ -848,16 +862,19 @@ func (s *TaskService) CreateStatus(ctx context.Context, spaceID, userID bson.Obj
if !hasPermission {
return nil, errors.New("insufficient permissions")
}
+ if err := s.validateTaskList(ctx, spaceID, taskListID); err != nil {
+ return nil, err
+ }
- statuses, err := s.taskStatusRepo.ListStatuses(ctx, spaceID)
+ statuses, err := s.taskStatusRepo.ListStatuses(ctx, taskListID)
if err != nil {
return nil, err
}
status := &entities.TaskStatus{
- SpaceID: spaceID,
- Name: strings.TrimSpace(req.Name),
- Color: strings.TrimSpace(req.Color),
- Order: len(statuses),
+ TaskListID: taskListID,
+ Name: strings.TrimSpace(req.Name),
+ Color: strings.TrimSpace(req.Color),
+ Order: len(statuses),
}
if status.Name == "" {
return nil, errors.New("status name is required")
@@ -868,7 +885,7 @@ func (s *TaskService) CreateStatus(ctx context.Context, spaceID, userID bson.Obj
return dto.NewTaskStatusDTO(status), nil
}
-func (s *TaskService) UpdateStatus(ctx context.Context, spaceID, statusID, userID bson.ObjectID, req *dto.UpdateTaskStatusRequest) (*dto.TaskStatusDTO, error) {
+func (s *TaskService) UpdateStatus(ctx context.Context, spaceID, taskListID, statusID, userID bson.ObjectID, req *dto.UpdateTaskStatusRequest) (*dto.TaskStatusDTO, error) {
if err := s.requireSpaceAccess(ctx, userID, spaceID); err != nil {
return nil, err
}
@@ -881,7 +898,7 @@ func (s *TaskService) UpdateStatus(ctx context.Context, spaceID, statusID, userI
}
status, err := s.taskStatusRepo.GetStatusByID(ctx, statusID)
- if err != nil || status.SpaceID != spaceID {
+ if err != nil || status.TaskListID != taskListID {
return nil, errors.New("task status not found")
}
@@ -896,7 +913,7 @@ func (s *TaskService) UpdateStatus(ctx context.Context, spaceID, statusID, userI
return dto.NewTaskStatusDTO(status), nil
}
-func (s *TaskService) DeleteStatus(ctx context.Context, spaceID, statusID, userID bson.ObjectID) error {
+func (s *TaskService) DeleteStatus(ctx context.Context, spaceID, taskListID, statusID, userID bson.ObjectID) error {
if err := s.requireSpaceAccess(ctx, userID, spaceID); err != nil {
return err
}
@@ -908,7 +925,7 @@ func (s *TaskService) DeleteStatus(ctx context.Context, spaceID, statusID, userI
return errors.New("insufficient permissions")
}
- statuses, err := s.taskStatusRepo.ListStatuses(ctx, spaceID)
+ statuses, err := s.taskStatusRepo.ListStatuses(ctx, taskListID)
if err != nil {
return err
}
@@ -928,10 +945,10 @@ func (s *TaskService) DeleteStatus(ctx context.Context, spaceID, statusID, userI
return err
}
- return s.normalizeStatusOrder(ctx, spaceID)
+ return s.normalizeStatusOrder(ctx, taskListID)
}
-func (s *TaskService) ReorderStatuses(ctx context.Context, spaceID, userID bson.ObjectID, orderedStatusIDs []string) ([]*dto.TaskStatusDTO, error) {
+func (s *TaskService) ReorderStatuses(ctx context.Context, spaceID, taskListID, userID bson.ObjectID, orderedStatusIDs []string) ([]*dto.TaskStatusDTO, error) {
if err := s.requireSpaceAccess(ctx, userID, spaceID); err != nil {
return nil, err
}
@@ -942,8 +959,11 @@ func (s *TaskService) ReorderStatuses(ctx context.Context, spaceID, userID bson.
if !hasPermission {
return nil, errors.New("insufficient permissions")
}
+ if err := s.validateTaskList(ctx, spaceID, taskListID); err != nil {
+ return nil, err
+ }
- statuses, err := s.taskStatusRepo.ListStatuses(ctx, spaceID)
+ statuses, err := s.taskStatusRepo.ListStatuses(ctx, taskListID)
if err != nil {
return nil, err
}
@@ -965,7 +985,7 @@ func (s *TaskService) ReorderStatuses(ctx context.Context, spaceID, userID bson.
}
status := statusByID[statusID]
if status == nil {
- return nil, errors.New("status id does not belong to this space")
+ return nil, errors.New("status id does not belong to this task list")
}
if _, exists := seen[statusID]; exists {
return nil, errors.New("duplicate status id in ordered_status_ids")
@@ -996,7 +1016,7 @@ func (s *TaskService) ReorderStatuses(ctx context.Context, spaceID, userID bson.
}
}
- updatedStatuses, err := s.taskStatusRepo.ListStatuses(ctx, spaceID)
+ updatedStatuses, err := s.taskStatusRepo.ListStatuses(ctx, taskListID)
if err != nil {
return nil, err
}
@@ -1008,8 +1028,8 @@ func (s *TaskService) ReorderStatuses(ctx context.Context, spaceID, userID bson.
return result, nil
}
-func (s *TaskService) normalizeStatusOrder(ctx context.Context, spaceID bson.ObjectID) error {
- statuses, err := s.taskStatusRepo.ListStatuses(ctx, spaceID)
+func (s *TaskService) normalizeStatusOrder(ctx context.Context, taskListID bson.ObjectID) error {
+ statuses, err := s.taskStatusRepo.ListStatuses(ctx, taskListID)
if err != nil {
return err
}
diff --git a/backend/internal/domain/entities/task.go b/backend/internal/domain/entities/task.go
index 12d68b3..5fcff0e 100644
--- a/backend/internal/domain/entities/task.go
+++ b/backend/internal/domain/entities/task.go
@@ -25,15 +25,15 @@ type Task struct {
UpdatedAt time.Time `bson:"updated_at"`
}
-// TaskStatus defines the ordered linear status progression for a space.
+// TaskStatus defines the ordered linear status progression for a task list.
type TaskStatus struct {
- ID bson.ObjectID `bson:"_id,omitempty"`
- SpaceID bson.ObjectID `bson:"space_id"`
- Name string `bson:"name"`
- Color string `bson:"color,omitempty"`
- Order int `bson:"order"`
- CreatedAt time.Time `bson:"created_at"`
- UpdatedAt time.Time `bson:"updated_at"`
+ ID bson.ObjectID `bson:"_id,omitempty"`
+ TaskListID bson.ObjectID `bson:"task_list_id"`
+ Name string `bson:"name"`
+ Color string `bson:"color,omitempty"`
+ Order int `bson:"order"`
+ CreatedAt time.Time `bson:"created_at"`
+ UpdatedAt time.Time `bson:"updated_at"`
}
// TaskList groups tasks under a named list that can be attached to a category.
diff --git a/backend/internal/domain/repositories/interfaces.go b/backend/internal/domain/repositories/interfaces.go
index dc2a467..001fb74 100644
--- a/backend/internal/domain/repositories/interfaces.go
+++ b/backend/internal/domain/repositories/interfaces.go
@@ -245,7 +245,8 @@ type TaskListRepository interface {
type TaskStatusRepository interface {
CreateStatus(ctx context.Context, status *entities.TaskStatus) error
GetStatusByID(ctx context.Context, id bson.ObjectID) (*entities.TaskStatus, error)
- ListStatuses(ctx context.Context, spaceID bson.ObjectID) ([]*entities.TaskStatus, error)
+ ListStatuses(ctx context.Context, taskListID bson.ObjectID) ([]*entities.TaskStatus, error)
UpdateStatus(ctx context.Context, status *entities.TaskStatus) error
DeleteStatus(ctx context.Context, id bson.ObjectID) error
+ DeleteStatusesByTaskListID(ctx context.Context, taskListID bson.ObjectID) error
}
diff --git a/backend/internal/infrastructure/database/task_repository.go b/backend/internal/infrastructure/database/task_repository.go
index 199e092..34bd335 100644
--- a/backend/internal/infrastructure/database/task_repository.go
+++ b/backend/internal/infrastructure/database/task_repository.go
@@ -232,8 +232,8 @@ func (r *TaskStatusRepository) GetStatusByID(ctx context.Context, id bson.Object
return &status, nil
}
-func (r *TaskStatusRepository) ListStatuses(ctx context.Context, spaceID bson.ObjectID) ([]*entities.TaskStatus, error) {
- cursor, err := r.collection.Find(ctx, bson.M{"space_id": spaceID}, options.Find().SetSort(bson.D{{Key: "order", Value: 1}}))
+func (r *TaskStatusRepository) ListStatuses(ctx context.Context, taskListID bson.ObjectID) ([]*entities.TaskStatus, error) {
+ cursor, err := r.collection.Find(ctx, bson.M{"task_list_id": taskListID}, options.Find().SetSort(bson.D{{Key: "order", Value: 1}}))
if err != nil {
return nil, err
}
@@ -257,14 +257,19 @@ func (r *TaskStatusRepository) DeleteStatus(ctx context.Context, id bson.ObjectI
return err
}
+func (r *TaskStatusRepository) DeleteStatusesByTaskListID(ctx context.Context, taskListID bson.ObjectID) error {
+ _, err := r.collection.DeleteMany(ctx, bson.M{"task_list_id": taskListID})
+ return err
+}
+
func (r *TaskStatusRepository) EnsureIndexes(ctx context.Context) error {
_, err := r.collection.Indexes().CreateMany(ctx, []mongo.IndexModel{
{
- Keys: bson.D{{Key: "space_id", Value: 1}, {Key: "name", Value: 1}},
+ Keys: bson.D{{Key: "task_list_id", Value: 1}, {Key: "name", Value: 1}},
Options: options.Index().SetUnique(true),
},
{
- Keys: bson.D{{Key: "space_id", Value: 1}, {Key: "order", Value: 1}},
+ Keys: bson.D{{Key: "task_list_id", Value: 1}, {Key: "order", Value: 1}},
Options: options.Index().SetUnique(true),
},
})
diff --git a/backend/internal/interfaces/handlers/task_handler.go b/backend/internal/interfaces/handlers/task_handler.go
index a1d28ca..d83a690 100644
--- a/backend/internal/interfaces/handlers/task_handler.go
+++ b/backend/internal/interfaces/handlers/task_handler.go
@@ -380,8 +380,13 @@ func (h *TaskHandler) ListStatuses(w http.ResponseWriter, r *http.Request) {
http.Error(w, "invalid request", http.StatusBadRequest)
return
}
+ taskListID, err := bson.ObjectIDFromHex(mux.Vars(r)["taskListId"])
+ if err != nil {
+ http.Error(w, "invalid task list id", http.StatusBadRequest)
+ return
+ }
- statuses, err := h.taskService.ListStatuses(r.Context(), spaceID, userID)
+ statuses, err := h.taskService.ListStatuses(r.Context(), spaceID, taskListID, userID)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
@@ -397,6 +402,11 @@ func (h *TaskHandler) CreateStatus(w http.ResponseWriter, r *http.Request) {
http.Error(w, "invalid request", http.StatusBadRequest)
return
}
+ taskListID, err := bson.ObjectIDFromHex(mux.Vars(r)["taskListId"])
+ if err != nil {
+ http.Error(w, "invalid task list id", http.StatusBadRequest)
+ return
+ }
var req dto.CreateTaskStatusRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -404,7 +414,7 @@ func (h *TaskHandler) CreateStatus(w http.ResponseWriter, r *http.Request) {
return
}
- status, err := h.taskService.CreateStatus(r.Context(), spaceID, userID, &req)
+ status, err := h.taskService.CreateStatus(r.Context(), spaceID, taskListID, userID, &req)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
@@ -421,6 +431,11 @@ func (h *TaskHandler) UpdateStatus(w http.ResponseWriter, r *http.Request) {
http.Error(w, "invalid request", http.StatusBadRequest)
return
}
+ taskListID, err := bson.ObjectIDFromHex(mux.Vars(r)["taskListId"])
+ if err != nil {
+ http.Error(w, "invalid task list id", http.StatusBadRequest)
+ return
+ }
statusID, err := bson.ObjectIDFromHex(mux.Vars(r)["statusId"])
if err != nil {
http.Error(w, "invalid status id", http.StatusBadRequest)
@@ -433,7 +448,7 @@ func (h *TaskHandler) UpdateStatus(w http.ResponseWriter, r *http.Request) {
return
}
- status, err := h.taskService.UpdateStatus(r.Context(), spaceID, statusID, userID, &req)
+ status, err := h.taskService.UpdateStatus(r.Context(), spaceID, taskListID, statusID, userID, &req)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
@@ -449,13 +464,18 @@ func (h *TaskHandler) DeleteStatus(w http.ResponseWriter, r *http.Request) {
http.Error(w, "invalid request", http.StatusBadRequest)
return
}
+ taskListID, err := bson.ObjectIDFromHex(mux.Vars(r)["taskListId"])
+ if err != nil {
+ http.Error(w, "invalid task list id", http.StatusBadRequest)
+ return
+ }
statusID, err := bson.ObjectIDFromHex(mux.Vars(r)["statusId"])
if err != nil {
http.Error(w, "invalid status id", http.StatusBadRequest)
return
}
- if err := h.taskService.DeleteStatus(r.Context(), spaceID, statusID, userID); err != nil {
+ if err := h.taskService.DeleteStatus(r.Context(), spaceID, taskListID, statusID, userID); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
@@ -468,6 +488,11 @@ func (h *TaskHandler) ReorderStatuses(w http.ResponseWriter, r *http.Request) {
http.Error(w, "invalid request", http.StatusBadRequest)
return
}
+ taskListID, err := bson.ObjectIDFromHex(mux.Vars(r)["taskListId"])
+ if err != nil {
+ http.Error(w, "invalid task list id", http.StatusBadRequest)
+ return
+ }
var req dto.ReorderTaskStatusesRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -475,7 +500,7 @@ func (h *TaskHandler) ReorderStatuses(w http.ResponseWriter, r *http.Request) {
return
}
- statuses, err := h.taskService.ReorderStatuses(r.Context(), spaceID, userID, req.OrderedStatusIDs)
+ statuses, err := h.taskService.ReorderStatuses(r.Context(), spaceID, taskListID, userID, req.OrderedStatusIDs)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
diff --git a/frontend/src/components/EditTaskListModal.vue b/frontend/src/components/EditTaskListModal.vue
new file mode 100644
index 0000000..1df543a
--- /dev/null
+++ b/frontend/src/components/EditTaskListModal.vue
@@ -0,0 +1,317 @@
+
+
Track work with ordered statuses.
+