feature: ability to delete task groups

This commit is contained in:
Jordan Knott 2020-04-11 14:24:45 -05:00
parent 063be79b89
commit c250ce574b
27 changed files with 824 additions and 221 deletions

View File

@ -50,6 +50,12 @@ type DirectiveRoot struct {
}
type ComplexityRoot struct {
DeleteTaskGroupPayload struct {
AffectedRows func(childComplexity int) int
Ok func(childComplexity int) int
TaskGroup func(childComplexity int) int
}
DeleteTaskPayload struct {
TaskID func(childComplexity int) int
}
@ -63,6 +69,7 @@ type ComplexityRoot struct {
CreateTeam func(childComplexity int, input NewTeam) int
CreateUserAccount func(childComplexity int, input NewUserAccount) int
DeleteTask func(childComplexity int, input DeleteTaskInput) int
DeleteTaskGroup func(childComplexity int, input DeleteTaskGroupInput) int
LogoutUser func(childComplexity int, input LogoutUser) int
UpdateTaskGroupLocation func(childComplexity int, input NewTaskGroupLocation) int
UpdateTaskLocation func(childComplexity int, input NewTaskLocation) int
@ -142,11 +149,12 @@ type MutationResolver interface {
CreateProject(ctx context.Context, input NewProject) (*pg.Project, error)
CreateTaskGroup(ctx context.Context, input NewTaskGroup) (*pg.TaskGroup, error)
UpdateTaskGroupLocation(ctx context.Context, input NewTaskGroupLocation) (*pg.TaskGroup, error)
DeleteTaskGroup(ctx context.Context, input DeleteTaskGroupInput) (*DeleteTaskGroupPayload, error)
CreateTask(ctx context.Context, input NewTask) (*pg.Task, error)
UpdateTaskLocation(ctx context.Context, input NewTaskLocation) (*pg.Task, error)
LogoutUser(ctx context.Context, input LogoutUser) (bool, error)
UpdateTaskName(ctx context.Context, input UpdateTaskName) (*pg.Task, error)
DeleteTask(ctx context.Context, input DeleteTaskInput) (*DeleteTaskPayload, error)
LogoutUser(ctx context.Context, input LogoutUser) (bool, error)
}
type OrganizationResolver interface {
Teams(ctx context.Context, obj *pg.Organization) ([]pg.Team, error)
@ -192,6 +200,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
_ = ec
switch typeName + "." + field {
case "DeleteTaskGroupPayload.affectedRows":
if e.complexity.DeleteTaskGroupPayload.AffectedRows == nil {
break
}
return e.complexity.DeleteTaskGroupPayload.AffectedRows(childComplexity), true
case "DeleteTaskGroupPayload.ok":
if e.complexity.DeleteTaskGroupPayload.Ok == nil {
break
}
return e.complexity.DeleteTaskGroupPayload.Ok(childComplexity), true
case "DeleteTaskGroupPayload.taskGroup":
if e.complexity.DeleteTaskGroupPayload.TaskGroup == nil {
break
}
return e.complexity.DeleteTaskGroupPayload.TaskGroup(childComplexity), true
case "DeleteTaskPayload.taskID":
if e.complexity.DeleteTaskPayload.TaskID == nil {
break
@ -295,6 +324,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.DeleteTask(childComplexity, args["input"].(DeleteTaskInput)), true
case "Mutation.deleteTaskGroup":
if e.complexity.Mutation.DeleteTaskGroup == nil {
break
}
args, err := ec.field_Mutation_deleteTaskGroup_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.DeleteTaskGroup(childComplexity, args["input"].(DeleteTaskGroupInput)), true
case "Mutation.logoutUser":
if e.complexity.Mutation.LogoutUser == nil {
break
@ -845,19 +886,37 @@ input NewTaskGroupLocation {
position: Float!
}
input DeleteTaskGroupInput {
taskGroupID: UUID!
}
type DeleteTaskGroupPayload {
ok: Boolean!
affectedRows: Int!
taskGroup: TaskGroup!
}
type Mutation {
createRefreshToken(input: NewRefreshToken!): RefreshToken!
createUserAccount(input: NewUserAccount!): UserAccount!
createOrganization(input: NewOrganization!): Organization!
createTeam(input: NewTeam!): Team!
createProject(input: NewProject!): Project!
createTaskGroup(input: NewTaskGroup!): TaskGroup!
updateTaskGroupLocation(input: NewTaskGroupLocation!): TaskGroup!
deleteTaskGroup(input: DeleteTaskGroupInput!): DeleteTaskGroupPayload!
createTask(input: NewTask!): Task!
updateTaskLocation(input: NewTaskLocation!): Task!
logoutUser(input: LogoutUser!): Boolean!
updateTaskName(input: UpdateTaskName!): Task!
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
logoutUser(input: LogoutUser!): Boolean!
}
`, BuiltIn: false},
}
@ -965,6 +1024,20 @@ func (ec *executionContext) field_Mutation_createUserAccount_args(ctx context.Co
return args, nil
}
func (ec *executionContext) field_Mutation_deleteTaskGroup_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 DeleteTaskGroupInput
if tmp, ok := rawArgs["input"]; ok {
arg0, err = ec.unmarshalNDeleteTaskGroupInput2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐDeleteTaskGroupInput(ctx, tmp)
if err != nil {
return nil, err
}
}
args["input"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_deleteTask_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
@ -1127,6 +1200,108 @@ func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArg
// region **************************** field.gotpl *****************************
func (ec *executionContext) _DeleteTaskGroupPayload_ok(ctx context.Context, field graphql.CollectedField, obj *DeleteTaskGroupPayload) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "DeleteTaskGroupPayload",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Ok, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(bool)
fc.Result = res
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
}
func (ec *executionContext) _DeleteTaskGroupPayload_affectedRows(ctx context.Context, field graphql.CollectedField, obj *DeleteTaskGroupPayload) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "DeleteTaskGroupPayload",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.AffectedRows, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(int)
fc.Result = res
return ec.marshalNInt2int(ctx, field.Selections, res)
}
func (ec *executionContext) _DeleteTaskGroupPayload_taskGroup(ctx context.Context, field graphql.CollectedField, obj *DeleteTaskGroupPayload) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "DeleteTaskGroupPayload",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.TaskGroup, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*pg.TaskGroup)
fc.Result = res
return ec.marshalNTaskGroup2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTaskGroup(ctx, field.Selections, res)
}
func (ec *executionContext) _DeleteTaskPayload_taskID(ctx context.Context, field graphql.CollectedField, obj *DeleteTaskPayload) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@ -1448,6 +1623,47 @@ func (ec *executionContext) _Mutation_updateTaskGroupLocation(ctx context.Contex
return ec.marshalNTaskGroup2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTaskGroup(ctx, field.Selections, res)
}
func (ec *executionContext) _Mutation_deleteTaskGroup(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "Mutation",
Field: field,
Args: nil,
IsMethod: true,
}
ctx = graphql.WithFieldContext(ctx, fc)
rawArgs := field.ArgumentMap(ec.Variables)
args, err := ec.field_Mutation_deleteTaskGroup_args(ctx, rawArgs)
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
fc.Args = args
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().DeleteTaskGroup(rctx, args["input"].(DeleteTaskGroupInput))
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*DeleteTaskGroupPayload)
fc.Result = res
return ec.marshalNDeleteTaskGroupPayload2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐDeleteTaskGroupPayload(ctx, field.Selections, res)
}
func (ec *executionContext) _Mutation_createTask(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@ -1530,47 +1746,6 @@ func (ec *executionContext) _Mutation_updateTaskLocation(ctx context.Context, fi
return ec.marshalNTask2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTask(ctx, field.Selections, res)
}
func (ec *executionContext) _Mutation_logoutUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "Mutation",
Field: field,
Args: nil,
IsMethod: true,
}
ctx = graphql.WithFieldContext(ctx, fc)
rawArgs := field.ArgumentMap(ec.Variables)
args, err := ec.field_Mutation_logoutUser_args(ctx, rawArgs)
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
fc.Args = args
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().LogoutUser(rctx, args["input"].(LogoutUser))
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(bool)
fc.Result = res
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
}
func (ec *executionContext) _Mutation_updateTaskName(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@ -1653,6 +1828,47 @@ func (ec *executionContext) _Mutation_deleteTask(ctx context.Context, field grap
return ec.marshalNDeleteTaskPayload2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐDeleteTaskPayload(ctx, field.Selections, res)
}
func (ec *executionContext) _Mutation_logoutUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "Mutation",
Field: field,
Args: nil,
IsMethod: true,
}
ctx = graphql.WithFieldContext(ctx, fc)
rawArgs := field.ArgumentMap(ec.Variables)
args, err := ec.field_Mutation_logoutUser_args(ctx, rawArgs)
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
fc.Args = args
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().LogoutUser(rctx, args["input"].(LogoutUser))
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(bool)
fc.Result = res
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
}
func (ec *executionContext) _Organization_organizationID(ctx context.Context, field graphql.CollectedField, obj *pg.Organization) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@ -4158,6 +4374,24 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co
// region **************************** input.gotpl *****************************
func (ec *executionContext) unmarshalInputDeleteTaskGroupInput(ctx context.Context, obj interface{}) (DeleteTaskGroupInput, error) {
var it DeleteTaskGroupInput
var asMap = obj.(map[string]interface{})
for k, v := range asMap {
switch k {
case "taskGroupID":
var err error
it.TaskGroupID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v)
if err != nil {
return it, err
}
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputDeleteTaskInput(ctx context.Context, obj interface{}) (DeleteTaskInput, error) {
var it DeleteTaskInput
var asMap = obj.(map[string]interface{})
@ -4514,6 +4748,43 @@ func (ec *executionContext) unmarshalInputUpdateTaskName(ctx context.Context, ob
// region **************************** object.gotpl ****************************
var deleteTaskGroupPayloadImplementors = []string{"DeleteTaskGroupPayload"}
func (ec *executionContext) _DeleteTaskGroupPayload(ctx context.Context, sel ast.SelectionSet, obj *DeleteTaskGroupPayload) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, deleteTaskGroupPayloadImplementors)
out := graphql.NewFieldSet(fields)
var invalids uint32
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("DeleteTaskGroupPayload")
case "ok":
out.Values[i] = ec._DeleteTaskGroupPayload_ok(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "affectedRows":
out.Values[i] = ec._DeleteTaskGroupPayload_affectedRows(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "taskGroup":
out.Values[i] = ec._DeleteTaskGroupPayload_taskGroup(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch()
if invalids > 0 {
return graphql.Null
}
return out
}
var deleteTaskPayloadImplementors = []string{"DeleteTaskPayload"}
func (ec *executionContext) _DeleteTaskPayload(ctx context.Context, sel ast.SelectionSet, obj *DeleteTaskPayload) graphql.Marshaler {
@ -4591,6 +4862,11 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
invalids++
}
case "deleteTaskGroup":
out.Values[i] = ec._Mutation_deleteTaskGroup(ctx, field)
if out.Values[i] == graphql.Null {
invalids++
}
case "createTask":
out.Values[i] = ec._Mutation_createTask(ctx, field)
if out.Values[i] == graphql.Null {
@ -4601,11 +4877,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
invalids++
}
case "logoutUser":
out.Values[i] = ec._Mutation_logoutUser(ctx, field)
if out.Values[i] == graphql.Null {
invalids++
}
case "updateTaskName":
out.Values[i] = ec._Mutation_updateTaskName(ctx, field)
if out.Values[i] == graphql.Null {
@ -4616,6 +4887,11 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
invalids++
}
case "logoutUser":
out.Values[i] = ec._Mutation_logoutUser(ctx, field)
if out.Values[i] == graphql.Null {
invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@ -5396,6 +5672,24 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se
return res
}
func (ec *executionContext) unmarshalNDeleteTaskGroupInput2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐDeleteTaskGroupInput(ctx context.Context, v interface{}) (DeleteTaskGroupInput, error) {
return ec.unmarshalInputDeleteTaskGroupInput(ctx, v)
}
func (ec *executionContext) marshalNDeleteTaskGroupPayload2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐDeleteTaskGroupPayload(ctx context.Context, sel ast.SelectionSet, v DeleteTaskGroupPayload) graphql.Marshaler {
return ec._DeleteTaskGroupPayload(ctx, sel, &v)
}
func (ec *executionContext) marshalNDeleteTaskGroupPayload2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐDeleteTaskGroupPayload(ctx context.Context, sel ast.SelectionSet, v *DeleteTaskGroupPayload) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
return ec._DeleteTaskGroupPayload(ctx, sel, v)
}
func (ec *executionContext) unmarshalNDeleteTaskInput2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐDeleteTaskInput(ctx context.Context, v interface{}) (DeleteTaskInput, error) {
return ec.unmarshalInputDeleteTaskInput(ctx, v)
}
@ -5450,6 +5744,20 @@ func (ec *executionContext) marshalNID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx c
return res
}
func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) {
return graphql.UnmarshalInt(v)
}
func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler {
res := graphql.MarshalInt(v)
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "must not be null")
}
}
return res
}
func (ec *executionContext) unmarshalNLogoutUser2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐLogoutUser(ctx context.Context, v interface{}) (LogoutUser, error) {
return ec.unmarshalInputLogoutUser(ctx, v)
}

View File

@ -4,8 +4,19 @@ package graph
import (
"github.com/google/uuid"
"github.com/jordanknott/project-citadel/api/pg"
)
type DeleteTaskGroupInput struct {
TaskGroupID uuid.UUID `json:"taskGroupID"`
}
type DeleteTaskGroupPayload struct {
Ok bool `json:"ok"`
AffectedRows int `json:"affectedRows"`
TaskGroup *pg.TaskGroup `json:"taskGroup"`
}
type DeleteTaskInput struct {
TaskID string `json:"taskID"`
}

View File

@ -141,17 +141,35 @@ input NewTaskGroupLocation {
position: Float!
}
input DeleteTaskGroupInput {
taskGroupID: UUID!
}
type DeleteTaskGroupPayload {
ok: Boolean!
affectedRows: Int!
taskGroup: TaskGroup!
}
type Mutation {
createRefreshToken(input: NewRefreshToken!): RefreshToken!
createUserAccount(input: NewUserAccount!): UserAccount!
createOrganization(input: NewOrganization!): Organization!
createTeam(input: NewTeam!): Team!
createProject(input: NewProject!): Project!
createTaskGroup(input: NewTaskGroup!): TaskGroup!
updateTaskGroupLocation(input: NewTaskGroupLocation!): TaskGroup!
deleteTaskGroup(input: DeleteTaskGroupInput!): DeleteTaskGroupPayload!
createTask(input: NewTask!): Task!
updateTaskLocation(input: NewTaskLocation!): Task!
logoutUser(input: LogoutUser!): Boolean!
updateTaskName(input: UpdateTaskName!): Task!
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
logoutUser(input: LogoutUser!): Boolean!
}

View File

@ -73,6 +73,22 @@ func (r *mutationResolver) UpdateTaskGroupLocation(ctx context.Context, input Ne
return &taskGroup, err
}
func (r *mutationResolver) DeleteTaskGroup(ctx context.Context, input DeleteTaskGroupInput) (*DeleteTaskGroupPayload, error) {
deletedTasks, err := r.Repository.DeleteTasksByTaskGroupID(ctx, input.TaskGroupID)
if err != nil {
return &DeleteTaskGroupPayload{}, err
}
taskGroup, err := r.Repository.GetTaskGroupByID(ctx, input.TaskGroupID)
if err != nil {
return &DeleteTaskGroupPayload{}, err
}
deletedTaskGroups, err := r.Repository.DeleteTaskGroupByID(ctx, input.TaskGroupID)
if err != nil {
return &DeleteTaskGroupPayload{}, err
}
return &DeleteTaskGroupPayload{true, int(deletedTasks + deletedTaskGroups), &taskGroup}, nil
}
func (r *mutationResolver) CreateTask(ctx context.Context, input NewTask) (*pg.Task, error) {
taskGroupID, err := uuid.Parse(input.TaskGroupID)
createdAt := time.Now().UTC()
@ -98,16 +114,6 @@ func (r *mutationResolver) UpdateTaskLocation(ctx context.Context, input NewTask
return &task, err
}
func (r *mutationResolver) LogoutUser(ctx context.Context, input LogoutUser) (bool, error) {
userID, err := uuid.Parse(input.UserID)
if err != nil {
return false, err
}
err = r.Repository.DeleteRefreshTokenByUserID(ctx, userID)
return true, err
}
func (r *mutationResolver) UpdateTaskName(ctx context.Context, input UpdateTaskName) (*pg.Task, error) {
taskID, err := uuid.Parse(input.TaskID)
if err != nil {
@ -133,6 +139,16 @@ func (r *mutationResolver) DeleteTask(ctx context.Context, input DeleteTaskInput
return &DeleteTaskPayload{taskID.String()}, nil
}
func (r *mutationResolver) LogoutUser(ctx context.Context, input LogoutUser) (bool, error) {
userID, err := uuid.Parse(input.UserID)
if err != nil {
return false, err
}
err = r.Repository.DeleteRefreshTokenByUserID(ctx, userID)
return true, err
}
func (r *organizationResolver) Teams(ctx context.Context, obj *pg.Organization) ([]pg.Team, error) {
teams, err := r.Repository.GetTeamsForOrganization(ctx, obj.OrganizationID)
return teams, err

View File

@ -11,26 +11,35 @@ type Repository interface {
DeleteTeamByID(ctx context.Context, teamID uuid.UUID) error
GetTeamByID(ctx context.Context, teamID uuid.UUID) (Team, error)
GetAllTeams(ctx context.Context) ([]Team, error)
CreateProject(ctx context.Context, arg CreateProjectParams) (Project, error)
GetAllProjects(ctx context.Context) ([]Project, error)
GetAllProjectsForTeam(ctx context.Context, teamID uuid.UUID) ([]Project, error)
GetProjectByID(ctx context.Context, projectID uuid.UUID) (Project, error)
GetAllUserAccounts(ctx context.Context) ([]UserAccount, error)
UpdateTaskGroupLocation(ctx context.Context, arg UpdateTaskGroupLocationParams) (TaskGroup, error)
GetUserAccountByID(ctx context.Context, userID uuid.UUID) (UserAccount, error)
CreateUserAccount(ctx context.Context, arg CreateUserAccountParams) (UserAccount, error)
GetUserAccountByID(ctx context.Context, userID uuid.UUID) (UserAccount, error)
GetUserAccountByUsername(ctx context.Context, username string) (UserAccount, error)
GetAllUserAccounts(ctx context.Context) ([]UserAccount, error)
CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) (RefreshToken, error)
GetRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) (RefreshToken, error)
DeleteRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) error
DeleteRefreshTokenByUserID(ctx context.Context, userID uuid.UUID) error
DeleteTaskGroupByID(ctx context.Context, taskGroupID uuid.UUID) (int64, error)
DeleteTasksByTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) (int64, error)
UpdateTaskGroupLocation(ctx context.Context, arg UpdateTaskGroupLocationParams) (TaskGroup, error)
CreateTaskGroup(ctx context.Context, arg CreateTaskGroupParams) (TaskGroup, error)
GetAllTaskGroups(ctx context.Context) ([]TaskGroup, error)
GetAllOrganizations(ctx context.Context) ([]Organization, error)
GetTaskGroupsForProject(ctx context.Context, projectID uuid.UUID) ([]TaskGroup, error)
GetTaskGroupByID(ctx context.Context, taskGroupID uuid.UUID) (TaskGroup, error)
GetAllOrganizations(ctx context.Context) ([]Organization, error)
CreateOrganization(ctx context.Context, arg CreateOrganizationParams) (Organization, error)
GetTeamsForOrganization(ctx context.Context, organizationID uuid.UUID) ([]Team, error)
CreateTask(ctx context.Context, arg CreateTaskParams) (Task, error)
GetAllTasks(ctx context.Context) ([]Task, error)
GetTasksForTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) ([]Task, error)

View File

@ -20,6 +20,8 @@ type Querier interface {
DeleteRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) error
DeleteRefreshTokenByUserID(ctx context.Context, userID uuid.UUID) error
DeleteTaskByID(ctx context.Context, taskID uuid.UUID) error
DeleteTaskGroupByID(ctx context.Context, taskGroupID uuid.UUID) (int64, error)
DeleteTasksByTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) (int64, error)
DeleteTeamByID(ctx context.Context, teamID uuid.UUID) error
GetAllOrganizations(ctx context.Context) ([]Organization, error)
GetAllProjects(ctx context.Context) ([]Project, error)

View File

@ -49,6 +49,18 @@ func (q *Queries) DeleteTaskByID(ctx context.Context, taskID uuid.UUID) error {
return err
}
const deleteTasksByTaskGroupID = `-- name: DeleteTasksByTaskGroupID :execrows
DELETE FROM task where task_group_id = $1
`
func (q *Queries) DeleteTasksByTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) (int64, error) {
result, err := q.db.ExecContext(ctx, deleteTasksByTaskGroupID, taskGroupID)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
const getAllTasks = `-- name: GetAllTasks :many
SELECT task_id, task_group_id, created_at, name, position FROM task
`

View File

@ -40,6 +40,18 @@ func (q *Queries) CreateTaskGroup(ctx context.Context, arg CreateTaskGroupParams
return i, err
}
const deleteTaskGroupByID = `-- name: DeleteTaskGroupByID :execrows
DELETE FROM task_group WHERE task_group_id = $1
`
func (q *Queries) DeleteTaskGroupByID(ctx context.Context, taskGroupID uuid.UUID) (int64, error) {
result, err := q.db.ExecContext(ctx, deleteTaskGroupByID, taskGroupID)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
const getAllTaskGroups = `-- name: GetAllTaskGroups :many
SELECT task_group_id, project_id, created_at, name, position FROM task_group
`

View File

@ -16,3 +16,6 @@ DELETE FROM task WHERE task_id = $1;
-- name: UpdateTaskName :one
UPDATE task SET name = $2 WHERE task_id = $1 RETURNING *;
-- name: DeleteTasksByTaskGroupID :execrows
DELETE FROM task where task_group_id = $1;

View File

@ -13,3 +13,6 @@ SELECT * FROM task_group WHERE task_group_id = $1;
-- name: UpdateTaskGroupLocation :one
UPDATE task_group SET position = $2 WHERE task_group_id = $1 RETURNING *;
-- name: DeleteTaskGroupByID :execrows
DELETE FROM task_group WHERE task_group_id = $1;

View File

@ -33,6 +33,7 @@
"react/jsx-filename-extension": [2, { "extensions": [".js", ".jsx", ".ts", ".tsx"] }],
"react/prop-types": 0,
"react/jsx-props-no-spreading": "off",
"no-param-reassign": "off",
"import/extensions": [
"error",
"ignorePackages",

View File

@ -39,6 +39,7 @@
"graphql": "^15.0.0",
"graphql-tag": "^2.10.3",
"history": "^4.10.1",
"immer": "^6.0.3",
"lodash": "^4.17.15",
"prop-types": "^15.7.2",
"react": "^16.12.0",

View File

@ -1,4 +1,5 @@
import React, { useState } from 'react';
import produce from 'immer';
import styled from 'styled-components/macro';
import { useParams } from 'react-router-dom';
import {
@ -9,6 +10,7 @@ import {
useUpdateTaskLocationMutation,
useUpdateTaskGroupLocationMutation,
useCreateTaskGroupMutation,
useDeleteTaskGroupMutation,
} from 'shared/generated/graphql';
import Navbar from 'App/Navbar';
@ -79,6 +81,26 @@ const Project = () => {
const [quickCardEditor, setQuickCardEditor] = useState(initialQuickCardEditorState);
const [updateTaskLocation] = useUpdateTaskLocationMutation();
const [updateTaskGroupLocation] = useUpdateTaskGroupLocationMutation();
const [deleteTaskGroup] = useDeleteTaskGroupMutation({
onCompleted: deletedTaskGroupData => {
const nextState = produce(listsData, (draftState: State) => {
delete draftState.columns[deletedTaskGroupData.deleteTaskGroup.taskGroup.taskGroupID];
const filteredTasks = Object.keys(listsData.tasks)
.filter(
taskID =>
listsData.tasks[taskID].taskGroup.taskGroupID !==
deletedTaskGroupData.deleteTaskGroup.taskGroup.taskGroupID,
)
.reduce((obj: TaskState, key: string) => {
obj[key] = listsData.tasks[key];
return obj;
}, {});
draftState.tasks = filteredTasks;
});
setListsData(nextState);
},
});
const [createTaskGroup] = useCreateTaskGroupMutation({
onCompleted: newTaskGroupData => {
const newListsData = {
@ -167,9 +189,14 @@ const Project = () => {
setListsData(newListsData);
},
});
const onCardDrop = (droppedTask: any) => {
const onCardDrop = (droppedTask: Task) => {
console.log(droppedTask);
updateTaskLocation({
variables: { taskID: droppedTask.taskID, taskGroupID: droppedTask.taskGroupID, position: droppedTask.position },
variables: {
taskID: droppedTask.taskID,
taskGroupID: droppedTask.taskGroup.taskGroupID,
position: droppedTask.position,
},
});
const newState = {
...listsData,
@ -229,6 +256,14 @@ const Project = () => {
</TitleWrapper>
<Board>
<Lists
onExtraMenuOpen={(taskGroupID, pos, size) => {
setPopupData({
isOpen: true,
left: pos.left,
top: pos.top + size.height + 5,
taskGroupID,
});
}}
onQuickEditorOpen={onQuickEditorOpen}
onCardCreate={onCardCreate}
{...listsData}
@ -271,7 +306,13 @@ const Project = () => {
onClose={() => setPopupData(initialPopupState)}
left={popupData.left}
>
<ListActions taskGroupID={popupData.taskGroupID} />
<ListActions
taskGroupID={popupData.taskGroupID}
onArchiveTaskGroup={taskGroupID => {
deleteTaskGroup({ variables: { taskGroupID } });
setPopupData(initialPopupState);
}}
/>
</PopupMenu>
)}
</>

View File

@ -1,3 +1,8 @@
interface DraggableElement {
id: string;
position: number;
}
type ContextMenuEvent = {
left: number;
top: number;

View File

@ -1,6 +1,8 @@
import styled, { css } from 'styled-components';
import TextareaAutosize from 'react-autosize-textarea/lib';
export const Container = styled.div``;
export const Wrapper = styled.div<{ editorOpen: boolean }>`
display: inline-block;
background-color: hsla(0, 0%, 100%, 0.24);

View File

@ -3,6 +3,7 @@ import { Plus, Cross } from 'shared/icons';
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
import {
Container,
Wrapper,
Placeholder,
AddIconWrapper,
@ -79,6 +80,7 @@ const AddList: React.FC<AddListProps> = ({ onSave }) => {
useOnOutsideClick($wrapperRef, editorOpen, onOutsideClick, null);
return (
<Container>
<Wrapper
ref={$wrapperRef}
editorOpen={editorOpen}
@ -99,6 +101,7 @@ const AddList: React.FC<AddListProps> = ({ onSave }) => {
</Placeholder>
)}
</Wrapper>
</Container>
);
};

View File

@ -1,4 +1,5 @@
import React from 'react';
import { action } from '@storybook/addon-actions';
import ListActions from '.';
export default {
@ -13,5 +14,5 @@ export default {
};
export const Default = () => {
return <ListActions taskGroupID="1" />;
return <ListActions taskGroupID="1" onArchiveTaskGroup={action('on archive task group')} />;
};

View File

@ -3,8 +3,10 @@ import { ListActionsWrapper, ListActionItemWrapper, ListActionItem, ListSeparato
type Props = {
taskGroupID: string;
onArchiveTaskGroup: (taskGroupID: string) => void;
};
const LabelManager = ({ taskGroupID }: Props) => {
const LabelManager: React.FC<Props> = ({ taskGroupID, onArchiveTaskGroup }) => {
return (
<>
<ListActionsWrapper>
@ -38,7 +40,7 @@ const LabelManager = ({ taskGroupID }: Props) => {
</ListActionsWrapper>
<ListSeparator />
<ListActionsWrapper>
<ListActionItemWrapper>
<ListActionItemWrapper onClick={() => onArchiveTaskGroup(taskGroupID)}>
<ListActionItem>Archive This List</ListActionItem>
</ListActionItemWrapper>
</ListActionsWrapper>

View File

@ -70,25 +70,28 @@ export const Default = () => {
...listsData,
tasks: {
...listsData.tasks,
[droppedTask.id]: droppedTask,
[droppedTask.taskGroupID]: droppedTask,
},
};
console.log(newState);
setListsData(newState);
};
const onListDrop = (droppedColumn: any) => {
console.log(droppedColumn);
const newState = {
...listsData,
columns: {
...listsData.columns,
[droppedColumn.id]: droppedColumn,
[droppedColumn.taskGroupID]: droppedColumn,
},
};
console.log(newState);
setListsData(newState);
};
return (
<Lists
{...listsData}
onExtraMenuOpen={action('extra menu open')}
onQuickEditorOpen={action('card composer open')}
onCardDrop={onCardDrop}
onListDrop={onListDrop}
@ -203,6 +206,7 @@ export const ListsWithManyList = () => {
onCardDrop={onCardDrop}
onListDrop={onListDrop}
onCreateList={action('create list')}
onExtraMenuOpen={action('extra menu open')}
/>
);
};

View File

@ -1,7 +1,6 @@
import styled from 'styled-components';
export const Container = styled.div`
flex-grow: 1;
user-select: none;
white-space: nowrap;
margin-bottom: 8px;
@ -10,4 +9,7 @@ export const Container = styled.div`
padding-bottom: 8px;
`;
export const BoardWrapper = styled.div`
display: flex;
`;
export default Container;

View File

@ -11,7 +11,7 @@ import {
getAfterDropDraggableList,
} from 'shared/utils/draggables';
import { Container } from './Styles';
import { Container, BoardWrapper } from './Styles';
interface Columns {
[key: string]: TaskGroup;
@ -23,25 +23,56 @@ interface Tasks {
type Props = {
columns: Columns;
tasks: Tasks;
onCardDrop: any;
onListDrop: any;
onCardDrop: (task: Task) => void;
onListDrop: (taskGroup: TaskGroup) => void;
onCardCreate: (taskGroupID: string, name: string) => void;
onQuickEditorOpen: (e: ContextMenuEvent) => void;
onCreateList: (listName: string) => void;
onExtraMenuOpen: (taskGroupID: string, pos: ElementPosition, size: ElementSize) => void;
};
const Lists = ({ columns, tasks, onCardDrop, onListDrop, onCardCreate, onQuickEditorOpen, onCreateList }: Props) => {
const Lists: React.FC<Props> = ({
columns,
tasks,
onCardDrop,
onListDrop,
onCardCreate,
onQuickEditorOpen,
onCreateList,
onExtraMenuOpen,
}) => {
const onDragEnd = ({ draggableId, source, destination, type }: DropResult) => {
if (typeof destination === 'undefined') return;
if (!isPositionChanged(source, destination)) return;
const isList = type === 'column';
const isSameList = destination.droppableId === source.droppableId;
const droppedDraggable = isList ? columns[draggableId] : tasks[draggableId];
const droppedDraggable: DraggableElement = isList
? {
id: draggableId,
position: columns[draggableId].position,
}
: {
id: draggableId,
position: tasks[draggableId].position,
};
const beforeDropDraggables = isList
? getSortedDraggables(Object.values(columns))
: getSortedDraggables(Object.values(tasks).filter((t: any) => t.taskGroupID === destination.droppableId));
? getSortedDraggables(
Object.values(columns).map(column => {
return { id: column.taskGroupID, position: column.position };
}),
)
: getSortedDraggables(
Object.values(tasks)
.filter((t: any) => t.taskGroup.taskGroupID === destination.droppableId)
.map(task => {
return { id: task.taskID, position: task.position };
}),
);
console.log(beforeDropDraggables);
console.log(destination);
console.log(droppedDraggable);
const afterDropDraggables = getAfterDropDraggableList(
beforeDropDraggables,
droppedDraggable,
@ -49,16 +80,19 @@ const Lists = ({ columns, tasks, onCardDrop, onListDrop, onCardCreate, onQuickEd
isSameList,
destination,
);
console.log(afterDropDraggables);
const newPosition = getNewDraggablePosition(afterDropDraggables, destination.index);
if (isList) {
const droppedList = columns[droppedDraggable.id];
onListDrop({
...droppedDraggable,
...droppedList,
position: newPosition,
});
} else {
const droppedCard = tasks[droppedDraggable.id];
const newCard = {
...droppedDraggable,
...droppedCard,
position: newPosition,
taskGroupID: destination.droppableId,
};
@ -66,18 +100,24 @@ const Lists = ({ columns, tasks, onCardDrop, onListDrop, onCardCreate, onQuickEd
}
};
const orderedColumns = getSortedDraggables(Object.values(columns));
const orderedColumns = getSortedDraggables(
Object.values(columns).map(column => {
return { id: column.taskGroupID, position: column.position };
}),
);
const [currentComposer, setCurrentComposer] = useState('');
return (
<BoardWrapper>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable direction="horizontal" type="column" droppableId="root">
{provided => (
<Container {...provided.droppableProps} ref={provided.innerRef}>
{orderedColumns.map((column: TaskGroup, index: number) => {
const columnCards = getSortedDraggables(
Object.values(tasks).filter((t: Task) => t.taskGroup.taskGroupID === column.taskGroupID),
);
{orderedColumns.map((columnDraggable, index: number) => {
const column = columns[columnDraggable.id];
const columnCards = Object.values(tasks)
.filter((t: Task) => t.taskGroup.taskGroupID === column.taskGroupID)
.sort((a, b) => a.position - b.position);
return (
<Draggable draggableId={column.taskGroupID} key={column.taskGroupID} index={index}>
{columnDragProvided => (
@ -93,7 +133,7 @@ const Lists = ({ columns, tasks, onCardDrop, onListDrop, onCardCreate, onQuickEd
ref={columnDragProvided.innerRef}
wrapperProps={columnDragProvided.draggableProps}
headerProps={columnDragProvided.dragHandleProps}
onExtraMenuOpen={(taskGroupID, pos, size) => console.log(taskGroupID, pos, size)}
onExtraMenuOpen={onExtraMenuOpen}
>
<Droppable type="tasks" droppableId={column.taskGroupID}>
{columnDropProvided => (
@ -144,11 +184,12 @@ const Lists = ({ columns, tasks, onCardDrop, onListDrop, onCardCreate, onQuickEd
);
})}
{provided.placeholder}
<AddList onSave={onCreateList} />
</Container>
)}
</Droppable>
</DragDropContext>
<AddList onSave={onCreateList} />
</BoardWrapper>
);
};

View File

@ -77,7 +77,7 @@ export const ListActionsPopup = () => {
onClose={() => setPopupData(initalState)}
left={popupData.left}
>
<ListActions taskGroupID="1" />
<ListActions taskGroupID="1" onArchiveTaskGroup={action('archive task group')} />
</PopupMenu>
)}
<button

View File

@ -180,6 +180,17 @@ export type NewTaskGroupLocation = {
position: Scalars['Float'];
};
export type DeleteTaskGroupInput = {
taskGroupID: Scalars['UUID'];
};
export type DeleteTaskGroupPayload = {
__typename?: 'DeleteTaskGroupPayload';
ok: Scalars['Boolean'];
affectedRows: Scalars['Int'];
taskGroup: TaskGroup;
};
export type Mutation = {
__typename?: 'Mutation';
createRefreshToken: RefreshToken;
@ -189,11 +200,12 @@ export type Mutation = {
createProject: Project;
createTaskGroup: TaskGroup;
updateTaskGroupLocation: TaskGroup;
deleteTaskGroup: DeleteTaskGroupPayload;
createTask: Task;
updateTaskLocation: Task;
logoutUser: Scalars['Boolean'];
updateTaskName: Task;
deleteTask: DeleteTaskPayload;
logoutUser: Scalars['Boolean'];
};
@ -232,6 +244,11 @@ export type MutationUpdateTaskGroupLocationArgs = {
};
export type MutationDeleteTaskGroupArgs = {
input: DeleteTaskGroupInput;
};
export type MutationCreateTaskArgs = {
input: NewTask;
};
@ -242,11 +259,6 @@ export type MutationUpdateTaskLocationArgs = {
};
export type MutationLogoutUserArgs = {
input: LogoutUser;
};
export type MutationUpdateTaskNameArgs = {
input: UpdateTaskName;
};
@ -256,6 +268,11 @@ export type MutationDeleteTaskArgs = {
input: DeleteTaskInput;
};
export type MutationLogoutUserArgs = {
input: LogoutUser;
};
export type CreateTaskMutationVariables = {
taskGroupID: Scalars['String'];
name: Scalars['String'];
@ -303,6 +320,27 @@ export type DeleteTaskMutation = (
) }
);
export type DeleteTaskGroupMutationVariables = {
taskGroupID: Scalars['UUID'];
};
export type DeleteTaskGroupMutation = (
{ __typename?: 'Mutation' }
& { deleteTaskGroup: (
{ __typename?: 'DeleteTaskGroupPayload' }
& Pick<DeleteTaskGroupPayload, 'ok' | 'affectedRows'>
& { taskGroup: (
{ __typename?: 'TaskGroup' }
& Pick<TaskGroup, 'taskGroupID'>
& { tasks: Array<(
{ __typename?: 'Task' }
& Pick<Task, 'taskID' | 'name'>
)> }
) }
) }
);
export type FindProjectQueryVariables = {
projectId: Scalars['String'];
};
@ -494,6 +532,46 @@ export function useDeleteTaskMutation(baseOptions?: ApolloReactHooks.MutationHoo
export type DeleteTaskMutationHookResult = ReturnType<typeof useDeleteTaskMutation>;
export type DeleteTaskMutationResult = ApolloReactCommon.MutationResult<DeleteTaskMutation>;
export type DeleteTaskMutationOptions = ApolloReactCommon.BaseMutationOptions<DeleteTaskMutation, DeleteTaskMutationVariables>;
export const DeleteTaskGroupDocument = gql`
mutation deleteTaskGroup($taskGroupID: UUID!) {
deleteTaskGroup(input: {taskGroupID: $taskGroupID}) {
ok
affectedRows
taskGroup {
taskGroupID
tasks {
taskID
name
}
}
}
}
`;
export type DeleteTaskGroupMutationFn = ApolloReactCommon.MutationFunction<DeleteTaskGroupMutation, DeleteTaskGroupMutationVariables>;
/**
* __useDeleteTaskGroupMutation__
*
* To run a mutation, you first call `useDeleteTaskGroupMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useDeleteTaskGroupMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [deleteTaskGroupMutation, { data, loading, error }] = useDeleteTaskGroupMutation({
* variables: {
* taskGroupID: // value for 'taskGroupID'
* },
* });
*/
export function useDeleteTaskGroupMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<DeleteTaskGroupMutation, DeleteTaskGroupMutationVariables>) {
return ApolloReactHooks.useMutation<DeleteTaskGroupMutation, DeleteTaskGroupMutationVariables>(DeleteTaskGroupDocument, baseOptions);
}
export type DeleteTaskGroupMutationHookResult = ReturnType<typeof useDeleteTaskGroupMutation>;
export type DeleteTaskGroupMutationResult = ApolloReactCommon.MutationResult<DeleteTaskGroupMutation>;
export type DeleteTaskGroupMutationOptions = ApolloReactCommon.BaseMutationOptions<DeleteTaskGroupMutation, DeleteTaskGroupMutationVariables>;
export const FindProjectDocument = gql`
query findProject($projectId: String!) {
findProject(input: {projectId: $projectId}) {

View File

@ -0,0 +1,13 @@
mutation deleteTaskGroup($taskGroupID: UUID!) {
deleteTaskGroup(input: { taskGroupID: $taskGroupID }) {
ok
affectedRows
taskGroup {
taskGroupID
tasks {
taskID
name
}
}
}
}

View File

@ -1,22 +0,0 @@
export const moveItemWithinArray = (arr: any, item: any, newIndex: number) => {
const arrClone = [...arr];
const oldIndex = arrClone.indexOf(item);
arrClone.splice(newIndex, 0, arrClone.splice(oldIndex, 1)[0]);
return arrClone;
};
export const insertItemIntoArray = (arr: any, item: any, index: number) => {
const arrClone = [...arr];
arrClone.splice(index, 0, item);
return arrClone;
};
export const updateArrayItemById = (arr: any, itemId: any, fields: any) => {
const arrClone = [...arr];
const item = arrClone.find(({ id }) => id === itemId);
if (item) {
const itemIndex = arrClone.indexOf(item);
arrClone.splice(itemIndex, 1, { ...item, ...fields });
}
return arrClone;
};

View File

@ -1,26 +1,58 @@
import { moveItemWithinArray, insertItemIntoArray } from 'shared/utils/arrays';
import { DraggableLocation } from 'react-beautiful-dnd';
export const getNewDraggablePosition = (afterDropDraggables: any, draggableIndex: any) => {
export const moveItemWithinArray = (arr: Array<DraggableElement>, item: DraggableElement, newIndex: number) => {
const arrClone = [...arr];
const oldIndex = arrClone.findIndex(i => i.id === item.id);
arrClone.splice(newIndex, 0, arrClone.splice(oldIndex, 1)[0]);
return arrClone;
};
export const insertItemIntoArray = (arr: Array<DraggableElement>, item: DraggableElement, index: number) => {
const arrClone = [...arr];
arrClone.splice(index, 0, item);
return arrClone;
};
export const updateArrayItemById = (arr: Array<DraggableElement>, itemId: string, fields: any) => {
const arrClone = [...arr];
const item = arrClone.find(({ id }) => id === itemId);
if (item) {
const itemIndex = arrClone.indexOf(item);
arrClone.splice(itemIndex, 1, { ...item, ...fields });
}
return arrClone;
};
export const getNewDraggablePosition = (afterDropDraggables: Array<DraggableElement>, draggableIndex: number) => {
const prevDraggable = afterDropDraggables[draggableIndex - 1];
const nextDraggable = afterDropDraggables[draggableIndex + 1];
if (!prevDraggable && !nextDraggable) {
return 1;
return 65535;
}
if (!prevDraggable) {
return nextDraggable.position - 1;
console.log(
`in front of list [n/a : ${nextDraggable.id}]: ${nextDraggable.position} / 2.0 = ${nextDraggable.position / 2.0}`,
);
return nextDraggable.position / 2.0;
}
if (!nextDraggable) {
return prevDraggable.position + 1;
console.log(
`end of list [${prevDraggable.id} : n/a] : ${prevDraggable.position} * 2.0 = ${prevDraggable.position * 2.0}`,
);
return prevDraggable.position * 2.0;
}
const newPos = (prevDraggable.position + nextDraggable.position) / 2.0;
console.log(
`middle of two cards [${prevDraggable.id} : ${nextDraggable.id}] : ${prevDraggable.position} + ${nextDraggable.position} / 2.0 = ${newPos}`,
);
return newPos;
};
export const getSortedDraggables = (draggables: any) => {
export const getSortedDraggables = (draggables: Array<DraggableElement>) => {
return draggables.sort((a: any, b: any) => a.position - b.position);
};
export const isPositionChanged = (source: any, destination: any) => {
export const isPositionChanged = (source: DraggableLocation, destination: DraggableLocation) => {
if (!destination) return false;
const isSameList = destination.droppableId === source.droppableId;
const isSamePosition = destination.index === source.index;
@ -28,11 +60,11 @@ export const isPositionChanged = (source: any, destination: any) => {
};
export const getAfterDropDraggableList = (
beforeDropDraggables: any,
droppedDraggable: any,
isList: any,
isSameList: any,
destination: any,
beforeDropDraggables: Array<DraggableElement>,
droppedDraggable: DraggableElement,
isList: boolean,
isSameList: boolean,
destination: DraggableLocation,
) => {
if (isList) {
return moveItemWithinArray(beforeDropDraggables, droppedDraggable, destination.index);

View File

@ -8748,6 +8748,11 @@ immer@1.10.0:
resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==
immer@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/immer/-/immer-6.0.3.tgz#94d5051cd724668160a900d66d85ec02816f29bd"
integrity sha512-12VvNrfSrXZdm/BJgi/KDW2soq5freVSf3I1+4CLunUM8mAGx2/0Njy0xBVzi5zewQZiwM7z1/1T+8VaI7NkmQ==
immutable@~3.7.6:
version "3.7.6"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b"