feature: ability to delete task groups
This commit is contained in:
parent
063be79b89
commit
c250ce574b
@ -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)
|
||||
}
|
||||
|
@ -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"`
|
||||
}
|
||||
|
@ -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!
|
||||
}
|
||||
|
@ -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
|
||||
|
17
api/pg/pg.go
17
api/pg/pg.go
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
`
|
||||
|
@ -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
|
||||
`
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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>
|
||||
)}
|
||||
</>
|
||||
|
5
web/src/citadel.d.ts
vendored
5
web/src/citadel.d.ts
vendored
@ -1,3 +1,8 @@
|
||||
interface DraggableElement {
|
||||
id: string;
|
||||
position: number;
|
||||
}
|
||||
|
||||
type ContextMenuEvent = {
|
||||
left: number;
|
||||
top: number;
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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')} />;
|
||||
};
|
||||
|
@ -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>
|
||||
|
@ -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')}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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}) {
|
||||
|
13
web/src/shared/graphql/deleteTaskGroup.graphqls
Normal file
13
web/src/shared/graphql/deleteTaskGroup.graphqls
Normal file
@ -0,0 +1,13 @@
|
||||
mutation deleteTaskGroup($taskGroupID: UUID!) {
|
||||
deleteTaskGroup(input: { taskGroupID: $taskGroupID }) {
|
||||
ok
|
||||
affectedRows
|
||||
taskGroup {
|
||||
taskGroupID
|
||||
tasks {
|
||||
taskID
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
@ -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);
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user