feat: implement task group actions
- allow sorting specifc task groups - duplicate task group - delete all tasks in task group
This commit is contained in:
@ -19,6 +19,7 @@ type Querier interface {
|
||||
CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) (RefreshToken, error)
|
||||
CreateSystemOption(ctx context.Context, arg CreateSystemOptionParams) (SystemOption, error)
|
||||
CreateTask(ctx context.Context, arg CreateTaskParams) (Task, error)
|
||||
CreateTaskAll(ctx context.Context, arg CreateTaskAllParams) (Task, error)
|
||||
CreateTaskAssigned(ctx context.Context, arg CreateTaskAssignedParams) (TaskAssigned, error)
|
||||
CreateTaskChecklist(ctx context.Context, arg CreateTaskChecklistParams) (TaskChecklist, error)
|
||||
CreateTaskChecklistItem(ctx context.Context, arg CreateTaskChecklistItemParams) (TaskChecklistItem, error)
|
||||
@ -111,6 +112,7 @@ type Querier interface {
|
||||
UpdateTaskGroupLocation(ctx context.Context, arg UpdateTaskGroupLocationParams) (TaskGroup, error)
|
||||
UpdateTaskLocation(ctx context.Context, arg UpdateTaskLocationParams) (Task, error)
|
||||
UpdateTaskName(ctx context.Context, arg UpdateTaskNameParams) (Task, error)
|
||||
UpdateTaskPosition(ctx context.Context, arg UpdateTaskPositionParams) (Task, error)
|
||||
UpdateTeamMemberRole(ctx context.Context, arg UpdateTeamMemberRoleParams) (TeamMember, error)
|
||||
UpdateUserAccountProfileAvatarURL(ctx context.Context, arg UpdateUserAccountProfileAvatarURLParams) (UserAccount, error)
|
||||
UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (UserAccount, error)
|
||||
|
@ -2,6 +2,10 @@
|
||||
INSERT INTO task (task_group_id, created_at, name, position)
|
||||
VALUES($1, $2, $3, $4) RETURNING *;
|
||||
|
||||
-- name: CreateTaskAll :one
|
||||
INSERT INTO task (task_group_id, created_at, name, position, description, complete, due_date)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *;
|
||||
|
||||
-- name: UpdateTaskDescription :one
|
||||
UPDATE task SET description = $2 WHERE task_id = $1 RETURNING *;
|
||||
|
||||
@ -17,6 +21,9 @@ SELECT * FROM task;
|
||||
-- name: UpdateTaskLocation :one
|
||||
UPDATE task SET task_group_id = $2, position = $3 WHERE task_id = $1 RETURNING *;
|
||||
|
||||
-- name: UpdateTaskPosition :one
|
||||
UPDATE task SET position = $2 WHERE task_id = $1 RETURNING *;
|
||||
|
||||
-- name: DeleteTaskByID :exec
|
||||
DELETE FROM task WHERE task_id = $1;
|
||||
|
||||
|
@ -45,6 +45,46 @@ func (q *Queries) CreateTask(ctx context.Context, arg CreateTaskParams) (Task, e
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createTaskAll = `-- name: CreateTaskAll :one
|
||||
INSERT INTO task (task_group_id, created_at, name, position, description, complete, due_date)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING task_id, task_group_id, created_at, name, position, description, due_date, complete, completed_at
|
||||
`
|
||||
|
||||
type CreateTaskAllParams struct {
|
||||
TaskGroupID uuid.UUID `json:"task_group_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
Position float64 `json:"position"`
|
||||
Description sql.NullString `json:"description"`
|
||||
Complete bool `json:"complete"`
|
||||
DueDate sql.NullTime `json:"due_date"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateTaskAll(ctx context.Context, arg CreateTaskAllParams) (Task, error) {
|
||||
row := q.db.QueryRowContext(ctx, createTaskAll,
|
||||
arg.TaskGroupID,
|
||||
arg.CreatedAt,
|
||||
arg.Name,
|
||||
arg.Position,
|
||||
arg.Description,
|
||||
arg.Complete,
|
||||
arg.DueDate,
|
||||
)
|
||||
var i Task
|
||||
err := row.Scan(
|
||||
&i.TaskID,
|
||||
&i.TaskGroupID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
&i.Description,
|
||||
&i.DueDate,
|
||||
&i.Complete,
|
||||
&i.CompletedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteTaskByID = `-- name: DeleteTaskByID :exec
|
||||
DELETE FROM task WHERE task_id = $1
|
||||
`
|
||||
@ -305,3 +345,29 @@ func (q *Queries) UpdateTaskName(ctx context.Context, arg UpdateTaskNameParams)
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateTaskPosition = `-- name: UpdateTaskPosition :one
|
||||
UPDATE task SET position = $2 WHERE task_id = $1 RETURNING task_id, task_group_id, created_at, name, position, description, due_date, complete, completed_at
|
||||
`
|
||||
|
||||
type UpdateTaskPositionParams struct {
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
Position float64 `json:"position"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateTaskPosition(ctx context.Context, arg UpdateTaskPositionParams) (Task, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateTaskPosition, arg.TaskID, arg.Position)
|
||||
var i Task
|
||||
err := row.Scan(
|
||||
&i.TaskID,
|
||||
&i.TaskGroupID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
&i.Description,
|
||||
&i.DueDate,
|
||||
&i.Complete,
|
||||
&i.CompletedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -111,6 +111,15 @@ type DeleteTaskGroupPayload struct {
|
||||
TaskGroup *db.TaskGroup `json:"taskGroup"`
|
||||
}
|
||||
|
||||
type DeleteTaskGroupTasks struct {
|
||||
TaskGroupID uuid.UUID `json:"taskGroupID"`
|
||||
}
|
||||
|
||||
type DeleteTaskGroupTasksPayload struct {
|
||||
TaskGroupID uuid.UUID `json:"taskGroupID"`
|
||||
Tasks []uuid.UUID `json:"tasks"`
|
||||
}
|
||||
|
||||
type DeleteTaskInput struct {
|
||||
TaskID string `json:"taskID"`
|
||||
}
|
||||
@ -151,6 +160,17 @@ type DeleteUserAccountPayload struct {
|
||||
UserAccount *db.UserAccount `json:"userAccount"`
|
||||
}
|
||||
|
||||
type DuplicateTaskGroup struct {
|
||||
ProjectID uuid.UUID `json:"projectID"`
|
||||
TaskGroupID uuid.UUID `json:"taskGroupID"`
|
||||
Name string `json:"name"`
|
||||
Position float64 `json:"position"`
|
||||
}
|
||||
|
||||
type DuplicateTaskGroupPayload struct {
|
||||
TaskGroup *db.TaskGroup `json:"taskGroup"`
|
||||
}
|
||||
|
||||
type FindProject struct {
|
||||
ProjectID uuid.UUID `json:"projectID"`
|
||||
}
|
||||
@ -296,10 +316,25 @@ type SetTaskComplete struct {
|
||||
Complete bool `json:"complete"`
|
||||
}
|
||||
|
||||
type SortTaskGroup struct {
|
||||
TaskGroupID uuid.UUID `json:"taskGroupID"`
|
||||
Tasks []TaskPositionUpdate `json:"tasks"`
|
||||
}
|
||||
|
||||
type SortTaskGroupPayload struct {
|
||||
TaskGroupID uuid.UUID `json:"taskGroupID"`
|
||||
Tasks []db.Task `json:"tasks"`
|
||||
}
|
||||
|
||||
type TaskBadges struct {
|
||||
Checklist *ChecklistBadge `json:"checklist"`
|
||||
}
|
||||
|
||||
type TaskPositionUpdate struct {
|
||||
TaskID uuid.UUID `json:"taskID"`
|
||||
Position float64 `json:"position"`
|
||||
}
|
||||
|
||||
type TeamRole struct {
|
||||
TeamID uuid.UUID `json:"teamID"`
|
||||
RoleCode RoleCode `json:"roleCode"`
|
||||
|
@ -547,6 +547,47 @@ extend type Mutation {
|
||||
TaskGroup! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
deleteTaskGroup(input: DeleteTaskGroupInput!):
|
||||
DeleteTaskGroupPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
duplicateTaskGroup(input: DuplicateTaskGroup!):
|
||||
DuplicateTaskGroupPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
sortTaskGroup(input: SortTaskGroup!):
|
||||
SortTaskGroupPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
deleteTaskGroupTasks(input: DeleteTaskGroupTasks!):
|
||||
DeleteTaskGroupTasksPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
}
|
||||
|
||||
input DeleteTaskGroupTasks {
|
||||
taskGroupID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTaskGroupTasksPayload {
|
||||
taskGroupID: UUID!
|
||||
tasks: [UUID!]!
|
||||
}
|
||||
|
||||
input TaskPositionUpdate {
|
||||
taskID: UUID!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type SortTaskGroupPayload {
|
||||
taskGroupID: UUID!
|
||||
tasks: [Task!]!
|
||||
}
|
||||
|
||||
input SortTaskGroup {
|
||||
taskGroupID: UUID!
|
||||
tasks: [TaskPositionUpdate!]!
|
||||
}
|
||||
|
||||
input DuplicateTaskGroup {
|
||||
projectID: UUID!
|
||||
taskGroupID: UUID!
|
||||
name: String!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type DuplicateTaskGroupPayload {
|
||||
taskGroup: TaskGroup!
|
||||
}
|
||||
|
||||
input NewTaskGroupLocation {
|
||||
|
@ -438,6 +438,111 @@ func (r *mutationResolver) DeleteTaskGroup(ctx context.Context, input DeleteTask
|
||||
return &DeleteTaskGroupPayload{true, int(deletedTasks + deletedTaskGroups), &taskGroup}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DuplicateTaskGroup(ctx context.Context, input DuplicateTaskGroup) (*DuplicateTaskGroupPayload, error) {
|
||||
createdAt := time.Now().UTC()
|
||||
taskGroup, err := r.Repository.CreateTaskGroup(ctx, db.CreateTaskGroupParams{ProjectID: input.ProjectID, Position: input.Position, Name: input.Name, CreatedAt: createdAt})
|
||||
if err != nil {
|
||||
return &DuplicateTaskGroupPayload{}, err
|
||||
}
|
||||
|
||||
originalTasks, err := r.Repository.GetTasksForTaskGroupID(ctx, input.TaskGroupID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return &DuplicateTaskGroupPayload{}, err
|
||||
}
|
||||
for _, originalTask := range originalTasks {
|
||||
task, err := r.Repository.CreateTaskAll(ctx, db.CreateTaskAllParams{
|
||||
TaskGroupID: taskGroup.TaskGroupID, CreatedAt: createdAt, Name: originalTask.Name, Position: originalTask.Position,
|
||||
Complete: originalTask.Complete, DueDate: originalTask.DueDate, Description: originalTask.Description})
|
||||
if err != nil {
|
||||
return &DuplicateTaskGroupPayload{}, err
|
||||
}
|
||||
members, err := r.Repository.GetAssignedMembersForTask(ctx, originalTask.TaskID)
|
||||
if err != nil {
|
||||
return &DuplicateTaskGroupPayload{}, err
|
||||
}
|
||||
for _, member := range members {
|
||||
_, err := r.Repository.CreateTaskAssigned(ctx, db.CreateTaskAssignedParams{
|
||||
TaskID: task.TaskID, UserID: member.UserID, AssignedDate: member.AssignedDate})
|
||||
if err != nil {
|
||||
return &DuplicateTaskGroupPayload{}, err
|
||||
}
|
||||
}
|
||||
labels, err := r.Repository.GetTaskLabelsForTaskID(ctx, originalTask.TaskID)
|
||||
if err != nil {
|
||||
return &DuplicateTaskGroupPayload{}, err
|
||||
}
|
||||
for _, label := range labels {
|
||||
_, err := r.Repository.CreateTaskLabelForTask(ctx, db.CreateTaskLabelForTaskParams{
|
||||
TaskID: task.TaskID, ProjectLabelID: label.ProjectLabelID, AssignedDate: label.AssignedDate})
|
||||
if err != nil {
|
||||
return &DuplicateTaskGroupPayload{}, err
|
||||
}
|
||||
}
|
||||
checklists, err := r.Repository.GetTaskChecklistsForTask(ctx, originalTask.TaskID)
|
||||
if err != nil {
|
||||
return &DuplicateTaskGroupPayload{}, err
|
||||
}
|
||||
for _, checklist := range checklists {
|
||||
newChecklist, err := r.Repository.CreateTaskChecklist(ctx, db.CreateTaskChecklistParams{
|
||||
TaskID: task.TaskID, Name: checklist.Name, CreatedAt: createdAt, Position: checklist.Position})
|
||||
if err != nil {
|
||||
return &DuplicateTaskGroupPayload{}, err
|
||||
}
|
||||
checklistItems, err := r.Repository.GetTaskChecklistItemsForTaskChecklist(ctx, checklist.TaskChecklistID)
|
||||
if err != nil {
|
||||
return &DuplicateTaskGroupPayload{}, err
|
||||
}
|
||||
for _, checklistItem := range checklistItems {
|
||||
item, err := r.Repository.CreateTaskChecklistItem(ctx, db.CreateTaskChecklistItemParams{
|
||||
TaskChecklistID: newChecklist.TaskChecklistID,
|
||||
CreatedAt: createdAt,
|
||||
Name: checklistItem.Name,
|
||||
Position: checklist.Position,
|
||||
})
|
||||
if checklistItem.Complete {
|
||||
r.Repository.SetTaskChecklistItemComplete(ctx, db.SetTaskChecklistItemCompleteParams{TaskChecklistItemID: item.TaskChecklistItemID, Complete: true})
|
||||
}
|
||||
if err != nil {
|
||||
return &DuplicateTaskGroupPayload{}, err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return &DuplicateTaskGroupPayload{}, err
|
||||
}
|
||||
return &DuplicateTaskGroupPayload{TaskGroup: &taskGroup}, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) SortTaskGroup(ctx context.Context, input SortTaskGroup) (*SortTaskGroupPayload, error) {
|
||||
tasks := []db.Task{}
|
||||
for _, task := range input.Tasks {
|
||||
t, err := r.Repository.UpdateTaskPosition(ctx, db.UpdateTaskPositionParams{TaskID: task.TaskID, Position: task.Position})
|
||||
if err != nil {
|
||||
return &SortTaskGroupPayload{}, err
|
||||
}
|
||||
tasks = append(tasks, t)
|
||||
}
|
||||
return &SortTaskGroupPayload{Tasks: tasks, TaskGroupID: input.TaskGroupID}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteTaskGroupTasks(ctx context.Context, input DeleteTaskGroupTasks) (*DeleteTaskGroupTasksPayload, error) {
|
||||
tasks, err := r.Repository.GetTasksForTaskGroupID(ctx, input.TaskGroupID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return &DeleteTaskGroupTasksPayload{}, err
|
||||
}
|
||||
removedTasks := []uuid.UUID{}
|
||||
for _, task := range tasks {
|
||||
err = r.Repository.DeleteTaskByID(ctx, task.TaskID)
|
||||
if err != nil {
|
||||
return &DeleteTaskGroupTasksPayload{}, err
|
||||
}
|
||||
removedTasks = append(removedTasks, task.TaskID)
|
||||
}
|
||||
return &DeleteTaskGroupTasksPayload{TaskGroupID: input.TaskGroupID, Tasks: removedTasks}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) AddTaskLabel(ctx context.Context, input *AddTaskLabelInput) (*db.Task, error) {
|
||||
assignedDate := time.Now().UTC()
|
||||
_, err := r.Repository.CreateTaskLabelForTask(ctx, db.CreateTaskLabelForTaskParams{input.TaskID, input.ProjectLabelID, assignedDate})
|
||||
|
@ -7,6 +7,47 @@ extend type Mutation {
|
||||
TaskGroup! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
deleteTaskGroup(input: DeleteTaskGroupInput!):
|
||||
DeleteTaskGroupPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
duplicateTaskGroup(input: DuplicateTaskGroup!):
|
||||
DuplicateTaskGroupPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
sortTaskGroup(input: SortTaskGroup!):
|
||||
SortTaskGroupPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
deleteTaskGroupTasks(input: DeleteTaskGroupTasks!):
|
||||
DeleteTaskGroupTasksPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
}
|
||||
|
||||
input DeleteTaskGroupTasks {
|
||||
taskGroupID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTaskGroupTasksPayload {
|
||||
taskGroupID: UUID!
|
||||
tasks: [UUID!]!
|
||||
}
|
||||
|
||||
input TaskPositionUpdate {
|
||||
taskID: UUID!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type SortTaskGroupPayload {
|
||||
taskGroupID: UUID!
|
||||
tasks: [Task!]!
|
||||
}
|
||||
|
||||
input SortTaskGroup {
|
||||
taskGroupID: UUID!
|
||||
tasks: [TaskPositionUpdate!]!
|
||||
}
|
||||
|
||||
input DuplicateTaskGroup {
|
||||
projectID: UUID!
|
||||
taskGroupID: UUID!
|
||||
name: String!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type DuplicateTaskGroupPayload {
|
||||
taskGroup: TaskGroup!
|
||||
}
|
||||
|
||||
input NewTaskGroupLocation {
|
||||
|
Reference in New Issue
Block a user