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 {
|
type ComplexityRoot struct {
|
||||||
|
DeleteTaskGroupPayload struct {
|
||||||
|
AffectedRows func(childComplexity int) int
|
||||||
|
Ok func(childComplexity int) int
|
||||||
|
TaskGroup func(childComplexity int) int
|
||||||
|
}
|
||||||
|
|
||||||
DeleteTaskPayload struct {
|
DeleteTaskPayload struct {
|
||||||
TaskID func(childComplexity int) int
|
TaskID func(childComplexity int) int
|
||||||
}
|
}
|
||||||
@ -63,6 +69,7 @@ type ComplexityRoot struct {
|
|||||||
CreateTeam func(childComplexity int, input NewTeam) int
|
CreateTeam func(childComplexity int, input NewTeam) int
|
||||||
CreateUserAccount func(childComplexity int, input NewUserAccount) int
|
CreateUserAccount func(childComplexity int, input NewUserAccount) int
|
||||||
DeleteTask func(childComplexity int, input DeleteTaskInput) int
|
DeleteTask func(childComplexity int, input DeleteTaskInput) int
|
||||||
|
DeleteTaskGroup func(childComplexity int, input DeleteTaskGroupInput) int
|
||||||
LogoutUser func(childComplexity int, input LogoutUser) int
|
LogoutUser func(childComplexity int, input LogoutUser) int
|
||||||
UpdateTaskGroupLocation func(childComplexity int, input NewTaskGroupLocation) int
|
UpdateTaskGroupLocation func(childComplexity int, input NewTaskGroupLocation) int
|
||||||
UpdateTaskLocation func(childComplexity int, input NewTaskLocation) int
|
UpdateTaskLocation func(childComplexity int, input NewTaskLocation) int
|
||||||
@ -142,11 +149,12 @@ type MutationResolver interface {
|
|||||||
CreateProject(ctx context.Context, input NewProject) (*pg.Project, error)
|
CreateProject(ctx context.Context, input NewProject) (*pg.Project, error)
|
||||||
CreateTaskGroup(ctx context.Context, input NewTaskGroup) (*pg.TaskGroup, error)
|
CreateTaskGroup(ctx context.Context, input NewTaskGroup) (*pg.TaskGroup, error)
|
||||||
UpdateTaskGroupLocation(ctx context.Context, input NewTaskGroupLocation) (*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)
|
CreateTask(ctx context.Context, input NewTask) (*pg.Task, error)
|
||||||
UpdateTaskLocation(ctx context.Context, input NewTaskLocation) (*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)
|
UpdateTaskName(ctx context.Context, input UpdateTaskName) (*pg.Task, error)
|
||||||
DeleteTask(ctx context.Context, input DeleteTaskInput) (*DeleteTaskPayload, error)
|
DeleteTask(ctx context.Context, input DeleteTaskInput) (*DeleteTaskPayload, error)
|
||||||
|
LogoutUser(ctx context.Context, input LogoutUser) (bool, error)
|
||||||
}
|
}
|
||||||
type OrganizationResolver interface {
|
type OrganizationResolver interface {
|
||||||
Teams(ctx context.Context, obj *pg.Organization) ([]pg.Team, error)
|
Teams(ctx context.Context, obj *pg.Organization) ([]pg.Team, error)
|
||||||
@ -192,6 +200,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
_ = ec
|
_ = ec
|
||||||
switch typeName + "." + field {
|
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":
|
case "DeleteTaskPayload.taskID":
|
||||||
if e.complexity.DeleteTaskPayload.TaskID == nil {
|
if e.complexity.DeleteTaskPayload.TaskID == nil {
|
||||||
break
|
break
|
||||||
@ -295,6 +324,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Mutation.DeleteTask(childComplexity, args["input"].(DeleteTaskInput)), true
|
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":
|
case "Mutation.logoutUser":
|
||||||
if e.complexity.Mutation.LogoutUser == nil {
|
if e.complexity.Mutation.LogoutUser == nil {
|
||||||
break
|
break
|
||||||
@ -845,19 +886,37 @@ input NewTaskGroupLocation {
|
|||||||
position: Float!
|
position: Float!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input DeleteTaskGroupInput {
|
||||||
|
taskGroupID: UUID!
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeleteTaskGroupPayload {
|
||||||
|
ok: Boolean!
|
||||||
|
affectedRows: Int!
|
||||||
|
taskGroup: TaskGroup!
|
||||||
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
createRefreshToken(input: NewRefreshToken!): RefreshToken!
|
createRefreshToken(input: NewRefreshToken!): RefreshToken!
|
||||||
|
|
||||||
createUserAccount(input: NewUserAccount!): UserAccount!
|
createUserAccount(input: NewUserAccount!): UserAccount!
|
||||||
|
|
||||||
createOrganization(input: NewOrganization!): Organization!
|
createOrganization(input: NewOrganization!): Organization!
|
||||||
|
|
||||||
createTeam(input: NewTeam!): Team!
|
createTeam(input: NewTeam!): Team!
|
||||||
|
|
||||||
createProject(input: NewProject!): Project!
|
createProject(input: NewProject!): Project!
|
||||||
|
|
||||||
createTaskGroup(input: NewTaskGroup!): TaskGroup!
|
createTaskGroup(input: NewTaskGroup!): TaskGroup!
|
||||||
updateTaskGroupLocation(input: NewTaskGroupLocation!): TaskGroup!
|
updateTaskGroupLocation(input: NewTaskGroupLocation!): TaskGroup!
|
||||||
|
deleteTaskGroup(input: DeleteTaskGroupInput!): DeleteTaskGroupPayload!
|
||||||
|
|
||||||
createTask(input: NewTask!): Task!
|
createTask(input: NewTask!): Task!
|
||||||
updateTaskLocation(input: NewTaskLocation!): Task!
|
updateTaskLocation(input: NewTaskLocation!): Task!
|
||||||
logoutUser(input: LogoutUser!): Boolean!
|
|
||||||
updateTaskName(input: UpdateTaskName!): Task!
|
updateTaskName(input: UpdateTaskName!): Task!
|
||||||
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
|
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
|
||||||
|
|
||||||
|
logoutUser(input: LogoutUser!): Boolean!
|
||||||
}
|
}
|
||||||
`, BuiltIn: false},
|
`, BuiltIn: false},
|
||||||
}
|
}
|
||||||
@ -965,6 +1024,20 @@ func (ec *executionContext) field_Mutation_createUserAccount_args(ctx context.Co
|
|||||||
return args, nil
|
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) {
|
func (ec *executionContext) field_Mutation_deleteTask_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]interface{}{}
|
args := map[string]interface{}{}
|
||||||
@ -1127,6 +1200,108 @@ func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArg
|
|||||||
|
|
||||||
// region **************************** field.gotpl *****************************
|
// 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) {
|
func (ec *executionContext) _DeleteTaskPayload_taskID(ctx context.Context, field graphql.CollectedField, obj *DeleteTaskPayload) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
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)
|
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) {
|
func (ec *executionContext) _Mutation_createTask(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
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)
|
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) {
|
func (ec *executionContext) _Mutation_updateTaskName(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
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)
|
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) {
|
func (ec *executionContext) _Organization_organizationID(ctx context.Context, field graphql.CollectedField, obj *pg.Organization) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -4158,6 +4374,24 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co
|
|||||||
|
|
||||||
// region **************************** input.gotpl *****************************
|
// 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) {
|
func (ec *executionContext) unmarshalInputDeleteTaskInput(ctx context.Context, obj interface{}) (DeleteTaskInput, error) {
|
||||||
var it DeleteTaskInput
|
var it DeleteTaskInput
|
||||||
var asMap = obj.(map[string]interface{})
|
var asMap = obj.(map[string]interface{})
|
||||||
@ -4514,6 +4748,43 @@ func (ec *executionContext) unmarshalInputUpdateTaskName(ctx context.Context, ob
|
|||||||
|
|
||||||
// region **************************** object.gotpl ****************************
|
// 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"}
|
var deleteTaskPayloadImplementors = []string{"DeleteTaskPayload"}
|
||||||
|
|
||||||
func (ec *executionContext) _DeleteTaskPayload(ctx context.Context, sel ast.SelectionSet, obj *DeleteTaskPayload) graphql.Marshaler {
|
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 {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
case "deleteTaskGroup":
|
||||||
|
out.Values[i] = ec._Mutation_deleteTaskGroup(ctx, field)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
case "createTask":
|
case "createTask":
|
||||||
out.Values[i] = ec._Mutation_createTask(ctx, field)
|
out.Values[i] = ec._Mutation_createTask(ctx, field)
|
||||||
if out.Values[i] == graphql.Null {
|
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 {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
case "logoutUser":
|
|
||||||
out.Values[i] = ec._Mutation_logoutUser(ctx, field)
|
|
||||||
if out.Values[i] == graphql.Null {
|
|
||||||
invalids++
|
|
||||||
}
|
|
||||||
case "updateTaskName":
|
case "updateTaskName":
|
||||||
out.Values[i] = ec._Mutation_updateTaskName(ctx, field)
|
out.Values[i] = ec._Mutation_updateTaskName(ctx, field)
|
||||||
if out.Values[i] == graphql.Null {
|
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 {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
|
case "logoutUser":
|
||||||
|
out.Values[i] = ec._Mutation_logoutUser(ctx, field)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
invalids++
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
}
|
}
|
||||||
@ -5396,6 +5672,24 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se
|
|||||||
return res
|
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) {
|
func (ec *executionContext) unmarshalNDeleteTaskInput2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐDeleteTaskInput(ctx context.Context, v interface{}) (DeleteTaskInput, error) {
|
||||||
return ec.unmarshalInputDeleteTaskInput(ctx, v)
|
return ec.unmarshalInputDeleteTaskInput(ctx, v)
|
||||||
}
|
}
|
||||||
@ -5450,6 +5744,20 @@ func (ec *executionContext) marshalNID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx c
|
|||||||
return res
|
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) {
|
func (ec *executionContext) unmarshalNLogoutUser2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐLogoutUser(ctx context.Context, v interface{}) (LogoutUser, error) {
|
||||||
return ec.unmarshalInputLogoutUser(ctx, v)
|
return ec.unmarshalInputLogoutUser(ctx, v)
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,19 @@ package graph
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/google/uuid"
|
"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 {
|
type DeleteTaskInput struct {
|
||||||
TaskID string `json:"taskID"`
|
TaskID string `json:"taskID"`
|
||||||
}
|
}
|
||||||
|
@ -141,17 +141,35 @@ input NewTaskGroupLocation {
|
|||||||
position: Float!
|
position: Float!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input DeleteTaskGroupInput {
|
||||||
|
taskGroupID: UUID!
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeleteTaskGroupPayload {
|
||||||
|
ok: Boolean!
|
||||||
|
affectedRows: Int!
|
||||||
|
taskGroup: TaskGroup!
|
||||||
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
createRefreshToken(input: NewRefreshToken!): RefreshToken!
|
createRefreshToken(input: NewRefreshToken!): RefreshToken!
|
||||||
|
|
||||||
createUserAccount(input: NewUserAccount!): UserAccount!
|
createUserAccount(input: NewUserAccount!): UserAccount!
|
||||||
|
|
||||||
createOrganization(input: NewOrganization!): Organization!
|
createOrganization(input: NewOrganization!): Organization!
|
||||||
|
|
||||||
createTeam(input: NewTeam!): Team!
|
createTeam(input: NewTeam!): Team!
|
||||||
|
|
||||||
createProject(input: NewProject!): Project!
|
createProject(input: NewProject!): Project!
|
||||||
|
|
||||||
createTaskGroup(input: NewTaskGroup!): TaskGroup!
|
createTaskGroup(input: NewTaskGroup!): TaskGroup!
|
||||||
updateTaskGroupLocation(input: NewTaskGroupLocation!): TaskGroup!
|
updateTaskGroupLocation(input: NewTaskGroupLocation!): TaskGroup!
|
||||||
|
deleteTaskGroup(input: DeleteTaskGroupInput!): DeleteTaskGroupPayload!
|
||||||
|
|
||||||
createTask(input: NewTask!): Task!
|
createTask(input: NewTask!): Task!
|
||||||
updateTaskLocation(input: NewTaskLocation!): Task!
|
updateTaskLocation(input: NewTaskLocation!): Task!
|
||||||
logoutUser(input: LogoutUser!): Boolean!
|
|
||||||
updateTaskName(input: UpdateTaskName!): Task!
|
updateTaskName(input: UpdateTaskName!): Task!
|
||||||
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
|
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
|
||||||
|
|
||||||
|
logoutUser(input: LogoutUser!): Boolean!
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,22 @@ func (r *mutationResolver) UpdateTaskGroupLocation(ctx context.Context, input Ne
|
|||||||
return &taskGroup, err
|
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) {
|
func (r *mutationResolver) CreateTask(ctx context.Context, input NewTask) (*pg.Task, error) {
|
||||||
taskGroupID, err := uuid.Parse(input.TaskGroupID)
|
taskGroupID, err := uuid.Parse(input.TaskGroupID)
|
||||||
createdAt := time.Now().UTC()
|
createdAt := time.Now().UTC()
|
||||||
@ -98,16 +114,6 @@ func (r *mutationResolver) UpdateTaskLocation(ctx context.Context, input NewTask
|
|||||||
return &task, err
|
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) {
|
func (r *mutationResolver) UpdateTaskName(ctx context.Context, input UpdateTaskName) (*pg.Task, error) {
|
||||||
taskID, err := uuid.Parse(input.TaskID)
|
taskID, err := uuid.Parse(input.TaskID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -133,6 +139,16 @@ func (r *mutationResolver) DeleteTask(ctx context.Context, input DeleteTaskInput
|
|||||||
return &DeleteTaskPayload{taskID.String()}, nil
|
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) {
|
func (r *organizationResolver) Teams(ctx context.Context, obj *pg.Organization) ([]pg.Team, error) {
|
||||||
teams, err := r.Repository.GetTeamsForOrganization(ctx, obj.OrganizationID)
|
teams, err := r.Repository.GetTeamsForOrganization(ctx, obj.OrganizationID)
|
||||||
return teams, err
|
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
|
DeleteTeamByID(ctx context.Context, teamID uuid.UUID) error
|
||||||
GetTeamByID(ctx context.Context, teamID uuid.UUID) (Team, error)
|
GetTeamByID(ctx context.Context, teamID uuid.UUID) (Team, error)
|
||||||
GetAllTeams(ctx context.Context) ([]Team, error)
|
GetAllTeams(ctx context.Context) ([]Team, error)
|
||||||
|
|
||||||
CreateProject(ctx context.Context, arg CreateProjectParams) (Project, error)
|
CreateProject(ctx context.Context, arg CreateProjectParams) (Project, error)
|
||||||
GetAllProjects(ctx context.Context) ([]Project, error)
|
GetAllProjects(ctx context.Context) ([]Project, error)
|
||||||
GetAllProjectsForTeam(ctx context.Context, teamID uuid.UUID) ([]Project, error)
|
GetAllProjectsForTeam(ctx context.Context, teamID uuid.UUID) ([]Project, error)
|
||||||
GetProjectByID(ctx context.Context, projectID 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)
|
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)
|
GetUserAccountByUsername(ctx context.Context, username string) (UserAccount, error)
|
||||||
|
GetAllUserAccounts(ctx context.Context) ([]UserAccount, error)
|
||||||
|
|
||||||
CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) (RefreshToken, error)
|
CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) (RefreshToken, error)
|
||||||
GetRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) (RefreshToken, error)
|
GetRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) (RefreshToken, error)
|
||||||
DeleteRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) error
|
DeleteRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) error
|
||||||
DeleteRefreshTokenByUserID(ctx context.Context, userID 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)
|
CreateTaskGroup(ctx context.Context, arg CreateTaskGroupParams) (TaskGroup, error)
|
||||||
GetAllTaskGroups(ctx context.Context) ([]TaskGroup, error)
|
GetAllTaskGroups(ctx context.Context) ([]TaskGroup, error)
|
||||||
GetAllOrganizations(ctx context.Context) ([]Organization, error)
|
|
||||||
GetTaskGroupsForProject(ctx context.Context, projectID uuid.UUID) ([]TaskGroup, error)
|
GetTaskGroupsForProject(ctx context.Context, projectID uuid.UUID) ([]TaskGroup, error)
|
||||||
GetTaskGroupByID(ctx context.Context, taskGroupID 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)
|
CreateOrganization(ctx context.Context, arg CreateOrganizationParams) (Organization, error)
|
||||||
|
|
||||||
GetTeamsForOrganization(ctx context.Context, organizationID uuid.UUID) ([]Team, error)
|
GetTeamsForOrganization(ctx context.Context, organizationID uuid.UUID) ([]Team, error)
|
||||||
|
|
||||||
CreateTask(ctx context.Context, arg CreateTaskParams) (Task, error)
|
CreateTask(ctx context.Context, arg CreateTaskParams) (Task, error)
|
||||||
GetAllTasks(ctx context.Context) ([]Task, error)
|
GetAllTasks(ctx context.Context) ([]Task, error)
|
||||||
GetTasksForTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) ([]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
|
DeleteRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) error
|
||||||
DeleteRefreshTokenByUserID(ctx context.Context, userID uuid.UUID) error
|
DeleteRefreshTokenByUserID(ctx context.Context, userID uuid.UUID) error
|
||||||
DeleteTaskByID(ctx context.Context, taskID 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
|
DeleteTeamByID(ctx context.Context, teamID uuid.UUID) error
|
||||||
GetAllOrganizations(ctx context.Context) ([]Organization, error)
|
GetAllOrganizations(ctx context.Context) ([]Organization, error)
|
||||||
GetAllProjects(ctx context.Context) ([]Project, error)
|
GetAllProjects(ctx context.Context) ([]Project, error)
|
||||||
|
@ -49,6 +49,18 @@ func (q *Queries) DeleteTaskByID(ctx context.Context, taskID uuid.UUID) error {
|
|||||||
return err
|
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
|
const getAllTasks = `-- name: GetAllTasks :many
|
||||||
SELECT task_id, task_group_id, created_at, name, position FROM task
|
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
|
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
|
const getAllTaskGroups = `-- name: GetAllTaskGroups :many
|
||||||
SELECT task_group_id, project_id, created_at, name, position FROM task_group
|
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
|
-- name: UpdateTaskName :one
|
||||||
UPDATE task SET name = $2 WHERE task_id = $1 RETURNING *;
|
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
|
-- name: UpdateTaskGroupLocation :one
|
||||||
UPDATE task_group SET position = $2 WHERE task_group_id = $1 RETURNING *;
|
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/jsx-filename-extension": [2, { "extensions": [".js", ".jsx", ".ts", ".tsx"] }],
|
||||||
"react/prop-types": 0,
|
"react/prop-types": 0,
|
||||||
"react/jsx-props-no-spreading": "off",
|
"react/jsx-props-no-spreading": "off",
|
||||||
|
"no-param-reassign": "off",
|
||||||
"import/extensions": [
|
"import/extensions": [
|
||||||
"error",
|
"error",
|
||||||
"ignorePackages",
|
"ignorePackages",
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
"graphql": "^15.0.0",
|
"graphql": "^15.0.0",
|
||||||
"graphql-tag": "^2.10.3",
|
"graphql-tag": "^2.10.3",
|
||||||
"history": "^4.10.1",
|
"history": "^4.10.1",
|
||||||
|
"immer": "^6.0.3",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react": "^16.12.0",
|
"react": "^16.12.0",
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import produce from 'immer';
|
||||||
import styled from 'styled-components/macro';
|
import styled from 'styled-components/macro';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
@ -9,6 +10,7 @@ import {
|
|||||||
useUpdateTaskLocationMutation,
|
useUpdateTaskLocationMutation,
|
||||||
useUpdateTaskGroupLocationMutation,
|
useUpdateTaskGroupLocationMutation,
|
||||||
useCreateTaskGroupMutation,
|
useCreateTaskGroupMutation,
|
||||||
|
useDeleteTaskGroupMutation,
|
||||||
} from 'shared/generated/graphql';
|
} from 'shared/generated/graphql';
|
||||||
|
|
||||||
import Navbar from 'App/Navbar';
|
import Navbar from 'App/Navbar';
|
||||||
@ -79,6 +81,26 @@ const Project = () => {
|
|||||||
const [quickCardEditor, setQuickCardEditor] = useState(initialQuickCardEditorState);
|
const [quickCardEditor, setQuickCardEditor] = useState(initialQuickCardEditorState);
|
||||||
const [updateTaskLocation] = useUpdateTaskLocationMutation();
|
const [updateTaskLocation] = useUpdateTaskLocationMutation();
|
||||||
const [updateTaskGroupLocation] = useUpdateTaskGroupLocationMutation();
|
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({
|
const [createTaskGroup] = useCreateTaskGroupMutation({
|
||||||
onCompleted: newTaskGroupData => {
|
onCompleted: newTaskGroupData => {
|
||||||
const newListsData = {
|
const newListsData = {
|
||||||
@ -167,9 +189,14 @@ const Project = () => {
|
|||||||
setListsData(newListsData);
|
setListsData(newListsData);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const onCardDrop = (droppedTask: any) => {
|
const onCardDrop = (droppedTask: Task) => {
|
||||||
|
console.log(droppedTask);
|
||||||
updateTaskLocation({
|
updateTaskLocation({
|
||||||
variables: { taskID: droppedTask.taskID, taskGroupID: droppedTask.taskGroupID, position: droppedTask.position },
|
variables: {
|
||||||
|
taskID: droppedTask.taskID,
|
||||||
|
taskGroupID: droppedTask.taskGroup.taskGroupID,
|
||||||
|
position: droppedTask.position,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const newState = {
|
const newState = {
|
||||||
...listsData,
|
...listsData,
|
||||||
@ -229,6 +256,14 @@ const Project = () => {
|
|||||||
</TitleWrapper>
|
</TitleWrapper>
|
||||||
<Board>
|
<Board>
|
||||||
<Lists
|
<Lists
|
||||||
|
onExtraMenuOpen={(taskGroupID, pos, size) => {
|
||||||
|
setPopupData({
|
||||||
|
isOpen: true,
|
||||||
|
left: pos.left,
|
||||||
|
top: pos.top + size.height + 5,
|
||||||
|
taskGroupID,
|
||||||
|
});
|
||||||
|
}}
|
||||||
onQuickEditorOpen={onQuickEditorOpen}
|
onQuickEditorOpen={onQuickEditorOpen}
|
||||||
onCardCreate={onCardCreate}
|
onCardCreate={onCardCreate}
|
||||||
{...listsData}
|
{...listsData}
|
||||||
@ -271,7 +306,13 @@ const Project = () => {
|
|||||||
onClose={() => setPopupData(initialPopupState)}
|
onClose={() => setPopupData(initialPopupState)}
|
||||||
left={popupData.left}
|
left={popupData.left}
|
||||||
>
|
>
|
||||||
<ListActions taskGroupID={popupData.taskGroupID} />
|
<ListActions
|
||||||
|
taskGroupID={popupData.taskGroupID}
|
||||||
|
onArchiveTaskGroup={taskGroupID => {
|
||||||
|
deleteTaskGroup({ variables: { taskGroupID } });
|
||||||
|
setPopupData(initialPopupState);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</PopupMenu>
|
</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 = {
|
type ContextMenuEvent = {
|
||||||
left: number;
|
left: number;
|
||||||
top: number;
|
top: number;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import styled, { css } from 'styled-components';
|
import styled, { css } from 'styled-components';
|
||||||
import TextareaAutosize from 'react-autosize-textarea/lib';
|
import TextareaAutosize from 'react-autosize-textarea/lib';
|
||||||
|
|
||||||
|
export const Container = styled.div``;
|
||||||
|
|
||||||
export const Wrapper = styled.div<{ editorOpen: boolean }>`
|
export const Wrapper = styled.div<{ editorOpen: boolean }>`
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background-color: hsla(0, 0%, 100%, 0.24);
|
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 useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
Container,
|
||||||
Wrapper,
|
Wrapper,
|
||||||
Placeholder,
|
Placeholder,
|
||||||
AddIconWrapper,
|
AddIconWrapper,
|
||||||
@ -79,6 +80,7 @@ const AddList: React.FC<AddListProps> = ({ onSave }) => {
|
|||||||
useOnOutsideClick($wrapperRef, editorOpen, onOutsideClick, null);
|
useOnOutsideClick($wrapperRef, editorOpen, onOutsideClick, null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Container>
|
||||||
<Wrapper
|
<Wrapper
|
||||||
ref={$wrapperRef}
|
ref={$wrapperRef}
|
||||||
editorOpen={editorOpen}
|
editorOpen={editorOpen}
|
||||||
@ -99,6 +101,7 @@ const AddList: React.FC<AddListProps> = ({ onSave }) => {
|
|||||||
</Placeholder>
|
</Placeholder>
|
||||||
)}
|
)}
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { action } from '@storybook/addon-actions';
|
||||||
import ListActions from '.';
|
import ListActions from '.';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -13,5 +14,5 @@ export default {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const 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 = {
|
type Props = {
|
||||||
taskGroupID: string;
|
taskGroupID: string;
|
||||||
|
|
||||||
|
onArchiveTaskGroup: (taskGroupID: string) => void;
|
||||||
};
|
};
|
||||||
const LabelManager = ({ taskGroupID }: Props) => {
|
const LabelManager: React.FC<Props> = ({ taskGroupID, onArchiveTaskGroup }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ListActionsWrapper>
|
<ListActionsWrapper>
|
||||||
@ -38,7 +40,7 @@ const LabelManager = ({ taskGroupID }: Props) => {
|
|||||||
</ListActionsWrapper>
|
</ListActionsWrapper>
|
||||||
<ListSeparator />
|
<ListSeparator />
|
||||||
<ListActionsWrapper>
|
<ListActionsWrapper>
|
||||||
<ListActionItemWrapper>
|
<ListActionItemWrapper onClick={() => onArchiveTaskGroup(taskGroupID)}>
|
||||||
<ListActionItem>Archive This List</ListActionItem>
|
<ListActionItem>Archive This List</ListActionItem>
|
||||||
</ListActionItemWrapper>
|
</ListActionItemWrapper>
|
||||||
</ListActionsWrapper>
|
</ListActionsWrapper>
|
||||||
|
@ -70,25 +70,28 @@ export const Default = () => {
|
|||||||
...listsData,
|
...listsData,
|
||||||
tasks: {
|
tasks: {
|
||||||
...listsData.tasks,
|
...listsData.tasks,
|
||||||
[droppedTask.id]: droppedTask,
|
[droppedTask.taskGroupID]: droppedTask,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
console.log(newState);
|
console.log(newState);
|
||||||
setListsData(newState);
|
setListsData(newState);
|
||||||
};
|
};
|
||||||
const onListDrop = (droppedColumn: any) => {
|
const onListDrop = (droppedColumn: any) => {
|
||||||
|
console.log(droppedColumn);
|
||||||
const newState = {
|
const newState = {
|
||||||
...listsData,
|
...listsData,
|
||||||
columns: {
|
columns: {
|
||||||
...listsData.columns,
|
...listsData.columns,
|
||||||
[droppedColumn.id]: droppedColumn,
|
[droppedColumn.taskGroupID]: droppedColumn,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
console.log(newState);
|
||||||
setListsData(newState);
|
setListsData(newState);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Lists
|
<Lists
|
||||||
{...listsData}
|
{...listsData}
|
||||||
|
onExtraMenuOpen={action('extra menu open')}
|
||||||
onQuickEditorOpen={action('card composer open')}
|
onQuickEditorOpen={action('card composer open')}
|
||||||
onCardDrop={onCardDrop}
|
onCardDrop={onCardDrop}
|
||||||
onListDrop={onListDrop}
|
onListDrop={onListDrop}
|
||||||
@ -203,6 +206,7 @@ export const ListsWithManyList = () => {
|
|||||||
onCardDrop={onCardDrop}
|
onCardDrop={onCardDrop}
|
||||||
onListDrop={onListDrop}
|
onListDrop={onListDrop}
|
||||||
onCreateList={action('create list')}
|
onCreateList={action('create list')}
|
||||||
|
onExtraMenuOpen={action('extra menu open')}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const Container = styled.div`
|
export const Container = styled.div`
|
||||||
flex-grow: 1;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
@ -10,4 +9,7 @@ export const Container = styled.div`
|
|||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const BoardWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
`;
|
||||||
export default Container;
|
export default Container;
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
getAfterDropDraggableList,
|
getAfterDropDraggableList,
|
||||||
} from 'shared/utils/draggables';
|
} from 'shared/utils/draggables';
|
||||||
|
|
||||||
import { Container } from './Styles';
|
import { Container, BoardWrapper } from './Styles';
|
||||||
|
|
||||||
interface Columns {
|
interface Columns {
|
||||||
[key: string]: TaskGroup;
|
[key: string]: TaskGroup;
|
||||||
@ -23,25 +23,56 @@ interface Tasks {
|
|||||||
type Props = {
|
type Props = {
|
||||||
columns: Columns;
|
columns: Columns;
|
||||||
tasks: Tasks;
|
tasks: Tasks;
|
||||||
onCardDrop: any;
|
onCardDrop: (task: Task) => void;
|
||||||
onListDrop: any;
|
onListDrop: (taskGroup: TaskGroup) => void;
|
||||||
onCardCreate: (taskGroupID: string, name: string) => void;
|
onCardCreate: (taskGroupID: string, name: string) => void;
|
||||||
onQuickEditorOpen: (e: ContextMenuEvent) => void;
|
onQuickEditorOpen: (e: ContextMenuEvent) => void;
|
||||||
onCreateList: (listName: string) => 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) => {
|
const onDragEnd = ({ draggableId, source, destination, type }: DropResult) => {
|
||||||
if (typeof destination === 'undefined') return;
|
if (typeof destination === 'undefined') return;
|
||||||
if (!isPositionChanged(source, destination)) return;
|
if (!isPositionChanged(source, destination)) return;
|
||||||
|
|
||||||
const isList = type === 'column';
|
const isList = type === 'column';
|
||||||
const isSameList = destination.droppableId === source.droppableId;
|
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
|
const beforeDropDraggables = isList
|
||||||
? getSortedDraggables(Object.values(columns))
|
? getSortedDraggables(
|
||||||
: getSortedDraggables(Object.values(tasks).filter((t: any) => t.taskGroupID === destination.droppableId));
|
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(
|
const afterDropDraggables = getAfterDropDraggableList(
|
||||||
beforeDropDraggables,
|
beforeDropDraggables,
|
||||||
droppedDraggable,
|
droppedDraggable,
|
||||||
@ -49,16 +80,19 @@ const Lists = ({ columns, tasks, onCardDrop, onListDrop, onCardCreate, onQuickEd
|
|||||||
isSameList,
|
isSameList,
|
||||||
destination,
|
destination,
|
||||||
);
|
);
|
||||||
|
console.log(afterDropDraggables);
|
||||||
const newPosition = getNewDraggablePosition(afterDropDraggables, destination.index);
|
const newPosition = getNewDraggablePosition(afterDropDraggables, destination.index);
|
||||||
|
|
||||||
if (isList) {
|
if (isList) {
|
||||||
|
const droppedList = columns[droppedDraggable.id];
|
||||||
onListDrop({
|
onListDrop({
|
||||||
...droppedDraggable,
|
...droppedList,
|
||||||
position: newPosition,
|
position: newPosition,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
const droppedCard = tasks[droppedDraggable.id];
|
||||||
const newCard = {
|
const newCard = {
|
||||||
...droppedDraggable,
|
...droppedCard,
|
||||||
position: newPosition,
|
position: newPosition,
|
||||||
taskGroupID: destination.droppableId,
|
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('');
|
const [currentComposer, setCurrentComposer] = useState('');
|
||||||
return (
|
return (
|
||||||
|
<BoardWrapper>
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
<Droppable direction="horizontal" type="column" droppableId="root">
|
<Droppable direction="horizontal" type="column" droppableId="root">
|
||||||
{provided => (
|
{provided => (
|
||||||
<Container {...provided.droppableProps} ref={provided.innerRef}>
|
<Container {...provided.droppableProps} ref={provided.innerRef}>
|
||||||
{orderedColumns.map((column: TaskGroup, index: number) => {
|
{orderedColumns.map((columnDraggable, index: number) => {
|
||||||
const columnCards = getSortedDraggables(
|
const column = columns[columnDraggable.id];
|
||||||
Object.values(tasks).filter((t: Task) => t.taskGroup.taskGroupID === column.taskGroupID),
|
const columnCards = Object.values(tasks)
|
||||||
);
|
.filter((t: Task) => t.taskGroup.taskGroupID === column.taskGroupID)
|
||||||
|
.sort((a, b) => a.position - b.position);
|
||||||
return (
|
return (
|
||||||
<Draggable draggableId={column.taskGroupID} key={column.taskGroupID} index={index}>
|
<Draggable draggableId={column.taskGroupID} key={column.taskGroupID} index={index}>
|
||||||
{columnDragProvided => (
|
{columnDragProvided => (
|
||||||
@ -93,7 +133,7 @@ const Lists = ({ columns, tasks, onCardDrop, onListDrop, onCardCreate, onQuickEd
|
|||||||
ref={columnDragProvided.innerRef}
|
ref={columnDragProvided.innerRef}
|
||||||
wrapperProps={columnDragProvided.draggableProps}
|
wrapperProps={columnDragProvided.draggableProps}
|
||||||
headerProps={columnDragProvided.dragHandleProps}
|
headerProps={columnDragProvided.dragHandleProps}
|
||||||
onExtraMenuOpen={(taskGroupID, pos, size) => console.log(taskGroupID, pos, size)}
|
onExtraMenuOpen={onExtraMenuOpen}
|
||||||
>
|
>
|
||||||
<Droppable type="tasks" droppableId={column.taskGroupID}>
|
<Droppable type="tasks" droppableId={column.taskGroupID}>
|
||||||
{columnDropProvided => (
|
{columnDropProvided => (
|
||||||
@ -144,11 +184,12 @@ const Lists = ({ columns, tasks, onCardDrop, onListDrop, onCardCreate, onQuickEd
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{provided.placeholder}
|
{provided.placeholder}
|
||||||
<AddList onSave={onCreateList} />
|
|
||||||
</Container>
|
</Container>
|
||||||
)}
|
)}
|
||||||
</Droppable>
|
</Droppable>
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
|
<AddList onSave={onCreateList} />
|
||||||
|
</BoardWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ export const ListActionsPopup = () => {
|
|||||||
onClose={() => setPopupData(initalState)}
|
onClose={() => setPopupData(initalState)}
|
||||||
left={popupData.left}
|
left={popupData.left}
|
||||||
>
|
>
|
||||||
<ListActions taskGroupID="1" />
|
<ListActions taskGroupID="1" onArchiveTaskGroup={action('archive task group')} />
|
||||||
</PopupMenu>
|
</PopupMenu>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
|
@ -180,6 +180,17 @@ export type NewTaskGroupLocation = {
|
|||||||
position: Scalars['Float'];
|
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 = {
|
export type Mutation = {
|
||||||
__typename?: 'Mutation';
|
__typename?: 'Mutation';
|
||||||
createRefreshToken: RefreshToken;
|
createRefreshToken: RefreshToken;
|
||||||
@ -189,11 +200,12 @@ export type Mutation = {
|
|||||||
createProject: Project;
|
createProject: Project;
|
||||||
createTaskGroup: TaskGroup;
|
createTaskGroup: TaskGroup;
|
||||||
updateTaskGroupLocation: TaskGroup;
|
updateTaskGroupLocation: TaskGroup;
|
||||||
|
deleteTaskGroup: DeleteTaskGroupPayload;
|
||||||
createTask: Task;
|
createTask: Task;
|
||||||
updateTaskLocation: Task;
|
updateTaskLocation: Task;
|
||||||
logoutUser: Scalars['Boolean'];
|
|
||||||
updateTaskName: Task;
|
updateTaskName: Task;
|
||||||
deleteTask: DeleteTaskPayload;
|
deleteTask: DeleteTaskPayload;
|
||||||
|
logoutUser: Scalars['Boolean'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -232,6 +244,11 @@ export type MutationUpdateTaskGroupLocationArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationDeleteTaskGroupArgs = {
|
||||||
|
input: DeleteTaskGroupInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationCreateTaskArgs = {
|
export type MutationCreateTaskArgs = {
|
||||||
input: NewTask;
|
input: NewTask;
|
||||||
};
|
};
|
||||||
@ -242,11 +259,6 @@ export type MutationUpdateTaskLocationArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationLogoutUserArgs = {
|
|
||||||
input: LogoutUser;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export type MutationUpdateTaskNameArgs = {
|
export type MutationUpdateTaskNameArgs = {
|
||||||
input: UpdateTaskName;
|
input: UpdateTaskName;
|
||||||
};
|
};
|
||||||
@ -256,6 +268,11 @@ export type MutationDeleteTaskArgs = {
|
|||||||
input: DeleteTaskInput;
|
input: DeleteTaskInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationLogoutUserArgs = {
|
||||||
|
input: LogoutUser;
|
||||||
|
};
|
||||||
|
|
||||||
export type CreateTaskMutationVariables = {
|
export type CreateTaskMutationVariables = {
|
||||||
taskGroupID: Scalars['String'];
|
taskGroupID: Scalars['String'];
|
||||||
name: 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 = {
|
export type FindProjectQueryVariables = {
|
||||||
projectId: Scalars['String'];
|
projectId: Scalars['String'];
|
||||||
};
|
};
|
||||||
@ -494,6 +532,46 @@ export function useDeleteTaskMutation(baseOptions?: ApolloReactHooks.MutationHoo
|
|||||||
export type DeleteTaskMutationHookResult = ReturnType<typeof useDeleteTaskMutation>;
|
export type DeleteTaskMutationHookResult = ReturnType<typeof useDeleteTaskMutation>;
|
||||||
export type DeleteTaskMutationResult = ApolloReactCommon.MutationResult<DeleteTaskMutation>;
|
export type DeleteTaskMutationResult = ApolloReactCommon.MutationResult<DeleteTaskMutation>;
|
||||||
export type DeleteTaskMutationOptions = ApolloReactCommon.BaseMutationOptions<DeleteTaskMutation, DeleteTaskMutationVariables>;
|
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`
|
export const FindProjectDocument = gql`
|
||||||
query findProject($projectId: String!) {
|
query findProject($projectId: String!) {
|
||||||
findProject(input: {projectId: $projectId}) {
|
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 prevDraggable = afterDropDraggables[draggableIndex - 1];
|
||||||
const nextDraggable = afterDropDraggables[draggableIndex + 1];
|
const nextDraggable = afterDropDraggables[draggableIndex + 1];
|
||||||
if (!prevDraggable && !nextDraggable) {
|
if (!prevDraggable && !nextDraggable) {
|
||||||
return 1;
|
return 65535;
|
||||||
}
|
}
|
||||||
if (!prevDraggable) {
|
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) {
|
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;
|
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;
|
return newPos;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getSortedDraggables = (draggables: any) => {
|
export const getSortedDraggables = (draggables: Array<DraggableElement>) => {
|
||||||
return draggables.sort((a: any, b: any) => a.position - b.position);
|
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;
|
if (!destination) return false;
|
||||||
const isSameList = destination.droppableId === source.droppableId;
|
const isSameList = destination.droppableId === source.droppableId;
|
||||||
const isSamePosition = destination.index === source.index;
|
const isSamePosition = destination.index === source.index;
|
||||||
@ -28,11 +60,11 @@ export const isPositionChanged = (source: any, destination: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getAfterDropDraggableList = (
|
export const getAfterDropDraggableList = (
|
||||||
beforeDropDraggables: any,
|
beforeDropDraggables: Array<DraggableElement>,
|
||||||
droppedDraggable: any,
|
droppedDraggable: DraggableElement,
|
||||||
isList: any,
|
isList: boolean,
|
||||||
isSameList: any,
|
isSameList: boolean,
|
||||||
destination: any,
|
destination: DraggableLocation,
|
||||||
) => {
|
) => {
|
||||||
if (isList) {
|
if (isList) {
|
||||||
return moveItemWithinArray(beforeDropDraggables, droppedDraggable, destination.index);
|
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"
|
resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
|
||||||
integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==
|
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:
|
immutable@~3.7.6:
|
||||||
version "3.7.6"
|
version "3.7.6"
|
||||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b"
|
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b"
|
||||||
|
Loading…
Reference in New Issue
Block a user