feature: add project labels
This commit is contained in:
parent
fba4de631f
commit
cbcd8c5f82
@ -1,16 +1,55 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/jordanknott/project-citadel/api/router"
|
"io/ioutil"
|
||||||
"time"
|
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"github.com/jordanknott/project-citadel/api/pg"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
// "github.com/jordanknott/project-citadel/api/router"
|
||||||
|
// "time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type color struct {
|
||||||
|
Name string
|
||||||
|
Color string
|
||||||
|
Position int
|
||||||
|
}
|
||||||
|
|
||||||
|
type colors struct {
|
||||||
|
Color []color
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
dur := time.Hour * 24 * 7 * 30
|
// dur := time.Hour * 24 * 7 * 30
|
||||||
token, err := router.NewAccessTokenCustomExpiration("21345076-6423-4a00-a6bd-cd9f830e2764", dur)
|
// token, err := router.NewAccessTokenCustomExpiration("21345076-6423-4a00-a6bd-cd9f830e2764", dur)
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
// fmt.Println(token)
|
||||||
|
|
||||||
|
fmt.Println("seeding database...")
|
||||||
|
|
||||||
|
dat, err := ioutil.ReadFile("data/colors.toml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
fmt.Println(token)
|
|
||||||
|
var labelColors colors
|
||||||
|
_, err = toml.Decode(string(dat), &labelColors)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
db, err := sqlx.Connect("postgres", "user=postgres password=test host=0.0.0.0 dbname=citadel sslmode=disable")
|
||||||
|
repository := pg.NewRepository(db)
|
||||||
|
for _, color := range labelColors.Color {
|
||||||
|
fmt.Printf("%v\n", color)
|
||||||
|
repository.CreateLabelColor(context.Background(), pg.CreateLabelColorParams{color.Name, color.Color, float64(color.Position)})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
49
api/data/colors.toml
Normal file
49
api/data/colors.toml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
[[color]]
|
||||||
|
name = 'green'
|
||||||
|
color = '#61bd4f'
|
||||||
|
position = 1
|
||||||
|
|
||||||
|
[[color]]
|
||||||
|
name = 'yellow'
|
||||||
|
color = '#f2d600'
|
||||||
|
position = 2
|
||||||
|
|
||||||
|
[[color]]
|
||||||
|
name = 'orange'
|
||||||
|
color = '#ff9f1a'
|
||||||
|
position = 3
|
||||||
|
|
||||||
|
[[color]]
|
||||||
|
name = 'red'
|
||||||
|
color = '#eb5a46'
|
||||||
|
position = 4
|
||||||
|
|
||||||
|
[[color]]
|
||||||
|
name = 'purple'
|
||||||
|
position = 5
|
||||||
|
color = '#c377e0'
|
||||||
|
|
||||||
|
[[color]]
|
||||||
|
name = 'blue'
|
||||||
|
position = 6
|
||||||
|
color = '#0079bf'
|
||||||
|
|
||||||
|
[[color]]
|
||||||
|
name = 'sky'
|
||||||
|
position = 7
|
||||||
|
color = '#00c2e0'
|
||||||
|
|
||||||
|
[[color]]
|
||||||
|
name = 'lime'
|
||||||
|
position = 8
|
||||||
|
color = '#51e898'
|
||||||
|
|
||||||
|
[[color]]
|
||||||
|
name = 'pink'
|
||||||
|
position = 9
|
||||||
|
color = '#ff78cb'
|
||||||
|
|
||||||
|
[[color]]
|
||||||
|
name = 'black'
|
||||||
|
position = 10
|
||||||
|
color = '#344563'
|
@ -4,6 +4,7 @@ go 1.13
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/99designs/gqlgen v0.11.3
|
github.com/99designs/gqlgen v0.11.3
|
||||||
|
github.com/BurntSushi/toml v0.3.1
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
github.com/go-chi/chi v3.3.2+incompatible
|
github.com/go-chi/chi v3.3.2+incompatible
|
||||||
github.com/go-chi/cors v1.0.0
|
github.com/go-chi/cors v1.0.0
|
||||||
@ -11,6 +12,7 @@ require (
|
|||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
github.com/jmoiron/sqlx v1.2.0
|
github.com/jmoiron/sqlx v1.2.0
|
||||||
github.com/lib/pq v1.0.0
|
github.com/lib/pq v1.0.0
|
||||||
|
github.com/pelletier/go-toml v1.8.0
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/pkg/errors v0.8.1
|
||||||
github.com/sirupsen/logrus v1.4.2
|
github.com/sirupsen/logrus v1.4.2
|
||||||
github.com/urfave/cli v1.20.0 // indirect
|
github.com/urfave/cli v1.20.0 // indirect
|
||||||
|
@ -2,6 +2,7 @@ github.com/99designs/gqlgen v0.11.1 h1:QoSL8/AAJ2T3UOeQbdnBR32JcG4pO08+P/g5jdbFk
|
|||||||
github.com/99designs/gqlgen v0.11.1/go.mod h1:vjFOyBZ7NwDl+GdSD4PFn7BQn5Fy7ohJwXn7Vk8zz+c=
|
github.com/99designs/gqlgen v0.11.1/go.mod h1:vjFOyBZ7NwDl+GdSD4PFn7BQn5Fy7ohJwXn7Vk8zz+c=
|
||||||
github.com/99designs/gqlgen v0.11.3 h1:oFSxl1DFS9X///uHV3y6CEfpcXWrDUxVblR4Xib2bs4=
|
github.com/99designs/gqlgen v0.11.3 h1:oFSxl1DFS9X///uHV3y6CEfpcXWrDUxVblR4Xib2bs4=
|
||||||
github.com/99designs/gqlgen v0.11.3/go.mod h1:RgX5GRRdDWNkh4pBrdzNpNPFVsdoUFY2+adM6nb1N+4=
|
github.com/99designs/gqlgen v0.11.3/go.mod h1:RgX5GRRdDWNkh4pBrdzNpNPFVsdoUFY2+adM6nb1N+4=
|
||||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||||
github.com/agnivade/levenshtein v1.0.3 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0=
|
github.com/agnivade/levenshtein v1.0.3 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0=
|
||||||
@ -56,6 +57,8 @@ github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047 h1:zCoDWFD5
|
|||||||
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
|
github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw=
|
||||||
|
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
@ -112,5 +115,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||||
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=
|
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=
|
||||||
|
@ -37,6 +37,7 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ResolverRoot interface {
|
type ResolverRoot interface {
|
||||||
|
LabelColor() LabelColorResolver
|
||||||
Mutation() MutationResolver
|
Mutation() MutationResolver
|
||||||
Project() ProjectResolver
|
Project() ProjectResolver
|
||||||
ProjectLabel() ProjectLabelResolver
|
ProjectLabel() ProjectLabelResolver
|
||||||
@ -63,6 +64,13 @@ type ComplexityRoot struct {
|
|||||||
TaskID func(childComplexity int) int
|
TaskID func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LabelColor struct {
|
||||||
|
ColorHex func(childComplexity int) int
|
||||||
|
ID func(childComplexity int) int
|
||||||
|
Name func(childComplexity int) int
|
||||||
|
Position func(childComplexity int) int
|
||||||
|
}
|
||||||
|
|
||||||
Mutation struct {
|
Mutation struct {
|
||||||
AddTaskLabel func(childComplexity int, input *AddTaskLabelInput) int
|
AddTaskLabel func(childComplexity int, input *AddTaskLabelInput) int
|
||||||
AssignTask func(childComplexity int, input *AssignTaskInput) int
|
AssignTask func(childComplexity int, input *AssignTaskInput) int
|
||||||
@ -102,9 +110,9 @@ type ComplexityRoot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProjectLabel struct {
|
ProjectLabel struct {
|
||||||
ColorHex func(childComplexity int) int
|
|
||||||
CreatedDate func(childComplexity int) int
|
CreatedDate func(childComplexity int) int
|
||||||
ID func(childComplexity int) int
|
ID func(childComplexity int) int
|
||||||
|
LabelColor func(childComplexity int) int
|
||||||
Name func(childComplexity int) int
|
Name func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +127,7 @@ type ComplexityRoot struct {
|
|||||||
FindProject func(childComplexity int, input FindProject) int
|
FindProject func(childComplexity int, input FindProject) int
|
||||||
FindTask func(childComplexity int, input FindTask) int
|
FindTask func(childComplexity int, input FindTask) int
|
||||||
FindUser func(childComplexity int, input FindUser) int
|
FindUser func(childComplexity int, input FindUser) int
|
||||||
|
LabelColors func(childComplexity int) int
|
||||||
Me func(childComplexity int) int
|
Me func(childComplexity int) int
|
||||||
Projects func(childComplexity int, input *ProjectsFilter) int
|
Projects func(childComplexity int, input *ProjectsFilter) int
|
||||||
TaskGroups func(childComplexity int) int
|
TaskGroups func(childComplexity int) int
|
||||||
@ -177,6 +186,9 @@ type ComplexityRoot struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LabelColorResolver interface {
|
||||||
|
ID(ctx context.Context, obj *pg.LabelColor) (uuid.UUID, error)
|
||||||
|
}
|
||||||
type MutationResolver interface {
|
type MutationResolver interface {
|
||||||
CreateRefreshToken(ctx context.Context, input NewRefreshToken) (*pg.RefreshToken, error)
|
CreateRefreshToken(ctx context.Context, input NewRefreshToken) (*pg.RefreshToken, error)
|
||||||
CreateUserAccount(ctx context.Context, input NewUserAccount) (*pg.UserAccount, error)
|
CreateUserAccount(ctx context.Context, input NewUserAccount) (*pg.UserAccount, error)
|
||||||
@ -209,7 +221,7 @@ type ProjectResolver interface {
|
|||||||
type ProjectLabelResolver interface {
|
type ProjectLabelResolver interface {
|
||||||
ID(ctx context.Context, obj *pg.ProjectLabel) (uuid.UUID, error)
|
ID(ctx context.Context, obj *pg.ProjectLabel) (uuid.UUID, error)
|
||||||
|
|
||||||
ColorHex(ctx context.Context, obj *pg.ProjectLabel) (string, error)
|
LabelColor(ctx context.Context, obj *pg.ProjectLabel) (*pg.LabelColor, error)
|
||||||
Name(ctx context.Context, obj *pg.ProjectLabel) (*string, error)
|
Name(ctx context.Context, obj *pg.ProjectLabel) (*string, error)
|
||||||
}
|
}
|
||||||
type QueryResolver interface {
|
type QueryResolver interface {
|
||||||
@ -218,6 +230,7 @@ type QueryResolver interface {
|
|||||||
FindProject(ctx context.Context, input FindProject) (*pg.Project, error)
|
FindProject(ctx context.Context, input FindProject) (*pg.Project, error)
|
||||||
FindTask(ctx context.Context, input FindTask) (*pg.Task, error)
|
FindTask(ctx context.Context, input FindTask) (*pg.Task, error)
|
||||||
Projects(ctx context.Context, input *ProjectsFilter) ([]pg.Project, error)
|
Projects(ctx context.Context, input *ProjectsFilter) ([]pg.Project, error)
|
||||||
|
LabelColors(ctx context.Context) ([]pg.LabelColor, error)
|
||||||
TaskGroups(ctx context.Context) ([]pg.TaskGroup, error)
|
TaskGroups(ctx context.Context) ([]pg.TaskGroup, error)
|
||||||
Me(ctx context.Context) (*pg.UserAccount, error)
|
Me(ctx context.Context) (*pg.UserAccount, error)
|
||||||
}
|
}
|
||||||
@ -296,6 +309,34 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.DeleteTaskPayload.TaskID(childComplexity), true
|
return e.complexity.DeleteTaskPayload.TaskID(childComplexity), true
|
||||||
|
|
||||||
|
case "LabelColor.colorHex":
|
||||||
|
if e.complexity.LabelColor.ColorHex == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.LabelColor.ColorHex(childComplexity), true
|
||||||
|
|
||||||
|
case "LabelColor.id":
|
||||||
|
if e.complexity.LabelColor.ID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.LabelColor.ID(childComplexity), true
|
||||||
|
|
||||||
|
case "LabelColor.name":
|
||||||
|
if e.complexity.LabelColor.Name == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.LabelColor.Name(childComplexity), true
|
||||||
|
|
||||||
|
case "LabelColor.position":
|
||||||
|
if e.complexity.LabelColor.Position == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.LabelColor.Position(childComplexity), true
|
||||||
|
|
||||||
case "Mutation.addTaskLabel":
|
case "Mutation.addTaskLabel":
|
||||||
if e.complexity.Mutation.AddTaskLabel == nil {
|
if e.complexity.Mutation.AddTaskLabel == nil {
|
||||||
break
|
break
|
||||||
@ -589,13 +630,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Project.Team(childComplexity), true
|
return e.complexity.Project.Team(childComplexity), true
|
||||||
|
|
||||||
case "ProjectLabel.colorHex":
|
|
||||||
if e.complexity.ProjectLabel.ColorHex == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.ProjectLabel.ColorHex(childComplexity), true
|
|
||||||
|
|
||||||
case "ProjectLabel.createdDate":
|
case "ProjectLabel.createdDate":
|
||||||
if e.complexity.ProjectLabel.CreatedDate == nil {
|
if e.complexity.ProjectLabel.CreatedDate == nil {
|
||||||
break
|
break
|
||||||
@ -610,6 +644,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.ProjectLabel.ID(childComplexity), true
|
return e.complexity.ProjectLabel.ID(childComplexity), true
|
||||||
|
|
||||||
|
case "ProjectLabel.labelColor":
|
||||||
|
if e.complexity.ProjectLabel.LabelColor == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.ProjectLabel.LabelColor(childComplexity), true
|
||||||
|
|
||||||
case "ProjectLabel.name":
|
case "ProjectLabel.name":
|
||||||
if e.complexity.ProjectLabel.Name == nil {
|
if e.complexity.ProjectLabel.Name == nil {
|
||||||
break
|
break
|
||||||
@ -681,6 +722,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Query.FindUser(childComplexity, args["input"].(FindUser)), true
|
return e.complexity.Query.FindUser(childComplexity, args["input"].(FindUser)), true
|
||||||
|
|
||||||
|
case "Query.labelColors":
|
||||||
|
if e.complexity.Query.LabelColors == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Query.LabelColors(childComplexity), true
|
||||||
|
|
||||||
case "Query.me":
|
case "Query.me":
|
||||||
if e.complexity.Query.Me == nil {
|
if e.complexity.Query.Me == nil {
|
||||||
break
|
break
|
||||||
@ -1015,10 +1063,17 @@ scalar UUID
|
|||||||
type ProjectLabel {
|
type ProjectLabel {
|
||||||
id: ID!
|
id: ID!
|
||||||
createdDate: Time!
|
createdDate: Time!
|
||||||
colorHex: String!
|
labelColor: LabelColor!
|
||||||
name: String
|
name: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LabelColor {
|
||||||
|
id: ID!
|
||||||
|
name: String!
|
||||||
|
position: Float!
|
||||||
|
colorHex: String!
|
||||||
|
}
|
||||||
|
|
||||||
type TaskLabel {
|
type TaskLabel {
|
||||||
id: ID!
|
id: ID!
|
||||||
projectLabelID: UUID!
|
projectLabelID: UUID!
|
||||||
@ -1116,6 +1171,7 @@ type Query {
|
|||||||
findProject(input: FindProject!): Project!
|
findProject(input: FindProject!): Project!
|
||||||
findTask(input: FindTask!): Task!
|
findTask(input: FindTask!): Task!
|
||||||
projects(input: ProjectsFilter): [Project!]!
|
projects(input: ProjectsFilter): [Project!]!
|
||||||
|
labelColors: [LabelColor!]!
|
||||||
taskGroups: [TaskGroup!]!
|
taskGroups: [TaskGroup!]!
|
||||||
me: UserAccount!
|
me: UserAccount!
|
||||||
}
|
}
|
||||||
@ -1750,6 +1806,142 @@ func (ec *executionContext) _DeleteTaskPayload_taskID(ctx context.Context, field
|
|||||||
return ec.marshalNString2string(ctx, field.Selections, res)
|
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _LabelColor_id(ctx context.Context, field graphql.CollectedField, obj *pg.LabelColor) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "LabelColor",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ec.resolvers.LabelColor().ID(rctx, obj)
|
||||||
|
})
|
||||||
|
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.(uuid.UUID)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _LabelColor_name(ctx context.Context, field graphql.CollectedField, obj *pg.LabelColor) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "LabelColor",
|
||||||
|
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.Name, 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.(string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _LabelColor_position(ctx context.Context, field graphql.CollectedField, obj *pg.LabelColor) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "LabelColor",
|
||||||
|
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.Position, 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.(float64)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNFloat2float64(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _LabelColor_colorHex(ctx context.Context, field graphql.CollectedField, obj *pg.LabelColor) (ret graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: "LabelColor",
|
||||||
|
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.ColorHex, 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.(string)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation_createRefreshToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Mutation_createRefreshToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -2921,7 +3113,7 @@ func (ec *executionContext) _ProjectLabel_createdDate(ctx context.Context, field
|
|||||||
return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res)
|
return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _ProjectLabel_colorHex(ctx context.Context, field graphql.CollectedField, obj *pg.ProjectLabel) (ret graphql.Marshaler) {
|
func (ec *executionContext) _ProjectLabel_labelColor(ctx context.Context, field graphql.CollectedField, obj *pg.ProjectLabel) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
@ -2938,7 +3130,7 @@ func (ec *executionContext) _ProjectLabel_colorHex(ctx context.Context, field gr
|
|||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return ec.resolvers.ProjectLabel().ColorHex(rctx, obj)
|
return ec.resolvers.ProjectLabel().LabelColor(rctx, obj)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@ -2950,9 +3142,9 @@ func (ec *executionContext) _ProjectLabel_colorHex(ctx context.Context, field gr
|
|||||||
}
|
}
|
||||||
return graphql.Null
|
return graphql.Null
|
||||||
}
|
}
|
||||||
res := resTmp.(string)
|
res := resTmp.(*pg.LabelColor)
|
||||||
fc.Result = res
|
fc.Result = res
|
||||||
return ec.marshalNString2string(ctx, field.Selections, res)
|
return ec.marshalNLabelColor2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐLabelColor(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _ProjectLabel_name(ctx context.Context, field graphql.CollectedField, obj *pg.ProjectLabel) (ret graphql.Marshaler) {
|
func (ec *executionContext) _ProjectLabel_name(ctx context.Context, field graphql.CollectedField, obj *pg.ProjectLabel) (ret graphql.Marshaler) {
|
||||||
@ -3320,6 +3512,40 @@ func (ec *executionContext) _Query_projects(ctx context.Context, field graphql.C
|
|||||||
return ec.marshalNProject2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐProjectᚄ(ctx, field.Selections, res)
|
return ec.marshalNProject2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐProjectᚄ(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Query_labelColors(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: "Query",
|
||||||
|
Field: field,
|
||||||
|
Args: nil,
|
||||||
|
IsMethod: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ec.resolvers.Query().LabelColors(rctx)
|
||||||
|
})
|
||||||
|
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.LabelColor)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNLabelColor2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐLabelColorᚄ(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Query_taskGroups(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Query_taskGroups(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -6228,6 +6454,57 @@ func (ec *executionContext) _DeleteTaskPayload(ctx context.Context, sel ast.Sele
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var labelColorImplementors = []string{"LabelColor"}
|
||||||
|
|
||||||
|
func (ec *executionContext) _LabelColor(ctx context.Context, sel ast.SelectionSet, obj *pg.LabelColor) graphql.Marshaler {
|
||||||
|
fields := graphql.CollectFields(ec.OperationContext, sel, labelColorImplementors)
|
||||||
|
|
||||||
|
out := graphql.NewFieldSet(fields)
|
||||||
|
var invalids uint32
|
||||||
|
for i, field := range fields {
|
||||||
|
switch field.Name {
|
||||||
|
case "__typename":
|
||||||
|
out.Values[i] = graphql.MarshalString("LabelColor")
|
||||||
|
case "id":
|
||||||
|
field := field
|
||||||
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
res = ec._LabelColor_id(ctx, field, obj)
|
||||||
|
if res == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
case "name":
|
||||||
|
out.Values[i] = ec._LabelColor_name(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
case "position":
|
||||||
|
out.Values[i] = ec._LabelColor_position(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
case "colorHex":
|
||||||
|
out.Values[i] = ec._LabelColor_colorHex(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Dispatch()
|
||||||
|
if invalids > 0 {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
var mutationImplementors = []string{"Mutation"}
|
var mutationImplementors = []string{"Mutation"}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler {
|
func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler {
|
||||||
@ -6518,7 +6795,7 @@ func (ec *executionContext) _ProjectLabel(ctx context.Context, sel ast.Selection
|
|||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
atomic.AddUint32(&invalids, 1)
|
atomic.AddUint32(&invalids, 1)
|
||||||
}
|
}
|
||||||
case "colorHex":
|
case "labelColor":
|
||||||
field := field
|
field := field
|
||||||
out.Concurrently(i, func() (res graphql.Marshaler) {
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -6526,7 +6803,7 @@ func (ec *executionContext) _ProjectLabel(ctx context.Context, sel ast.Selection
|
|||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
res = ec._ProjectLabel_colorHex(ctx, field, obj)
|
res = ec._ProjectLabel_labelColor(ctx, field, obj)
|
||||||
if res == graphql.Null {
|
if res == graphql.Null {
|
||||||
atomic.AddUint32(&invalids, 1)
|
atomic.AddUint32(&invalids, 1)
|
||||||
}
|
}
|
||||||
@ -6681,6 +6958,20 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
|
|||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
|
case "labelColors":
|
||||||
|
field := field
|
||||||
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
res = ec._Query_labelColors(ctx, field)
|
||||||
|
if res == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
case "taskGroups":
|
case "taskGroups":
|
||||||
field := field
|
field := field
|
||||||
out.Concurrently(i, func() (res graphql.Marshaler) {
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
@ -7499,6 +7790,57 @@ func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.Selecti
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNLabelColor2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐLabelColor(ctx context.Context, sel ast.SelectionSet, v pg.LabelColor) graphql.Marshaler {
|
||||||
|
return ec._LabelColor(ctx, sel, &v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNLabelColor2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐLabelColorᚄ(ctx context.Context, sel ast.SelectionSet, v []pg.LabelColor) graphql.Marshaler {
|
||||||
|
ret := make(graphql.Array, len(v))
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
isLen1 := len(v) == 1
|
||||||
|
if !isLen1 {
|
||||||
|
wg.Add(len(v))
|
||||||
|
}
|
||||||
|
for i := range v {
|
||||||
|
i := i
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Index: &i,
|
||||||
|
Result: &v[i],
|
||||||
|
}
|
||||||
|
ctx := graphql.WithFieldContext(ctx, fc)
|
||||||
|
f := func(i int) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = nil
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if !isLen1 {
|
||||||
|
defer wg.Done()
|
||||||
|
}
|
||||||
|
ret[i] = ec.marshalNLabelColor2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐLabelColor(ctx, sel, v[i])
|
||||||
|
}
|
||||||
|
if isLen1 {
|
||||||
|
f(i)
|
||||||
|
} else {
|
||||||
|
go f(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNLabelColor2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐLabelColor(ctx context.Context, sel ast.SelectionSet, v *pg.LabelColor) graphql.Marshaler {
|
||||||
|
if v == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return ec._LabelColor(ctx, sel, v)
|
||||||
|
}
|
||||||
|
|
||||||
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,10 +4,17 @@ scalar UUID
|
|||||||
type ProjectLabel {
|
type ProjectLabel {
|
||||||
id: ID!
|
id: ID!
|
||||||
createdDate: Time!
|
createdDate: Time!
|
||||||
colorHex: String!
|
labelColor: LabelColor!
|
||||||
name: String
|
name: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LabelColor {
|
||||||
|
id: ID!
|
||||||
|
name: String!
|
||||||
|
position: Float!
|
||||||
|
colorHex: String!
|
||||||
|
}
|
||||||
|
|
||||||
type TaskLabel {
|
type TaskLabel {
|
||||||
id: ID!
|
id: ID!
|
||||||
projectLabelID: UUID!
|
projectLabelID: UUID!
|
||||||
@ -105,6 +112,7 @@ type Query {
|
|||||||
findProject(input: FindProject!): Project!
|
findProject(input: FindProject!): Project!
|
||||||
findTask(input: FindTask!): Task!
|
findTask(input: FindTask!): Task!
|
||||||
projects(input: ProjectsFilter): [Project!]!
|
projects(input: ProjectsFilter): [Project!]!
|
||||||
|
labelColors: [LabelColor!]!
|
||||||
taskGroups: [TaskGroup!]!
|
taskGroups: [TaskGroup!]!
|
||||||
me: UserAccount!
|
me: UserAccount!
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,10 @@ import (
|
|||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (r *labelColorResolver) ID(ctx context.Context, obj *pg.LabelColor) (uuid.UUID, error) {
|
||||||
|
return obj.LabelColorID, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) CreateRefreshToken(ctx context.Context, input NewRefreshToken) (*pg.RefreshToken, error) {
|
func (r *mutationResolver) CreateRefreshToken(ctx context.Context, input NewRefreshToken) (*pg.RefreshToken, error) {
|
||||||
userID := uuid.MustParse("0183d9ab-d0ed-4c9b-a3df-77a0cdd93dca")
|
userID := uuid.MustParse("0183d9ab-d0ed-4c9b-a3df-77a0cdd93dca")
|
||||||
refreshCreatedAt := time.Now().UTC()
|
refreshCreatedAt := time.Now().UTC()
|
||||||
@ -46,7 +50,23 @@ func (r *mutationResolver) CreateProject(ctx context.Context, input NewProject)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) CreateProjectLabel(ctx context.Context, input NewProjectLabel) (*pg.ProjectLabel, error) {
|
func (r *mutationResolver) CreateProjectLabel(ctx context.Context, input NewProjectLabel) (*pg.ProjectLabel, error) {
|
||||||
panic(fmt.Errorf("not implemented"))
|
createdAt := time.Now().UTC()
|
||||||
|
|
||||||
|
var name sql.NullString
|
||||||
|
if input.Name != nil {
|
||||||
|
name = sql.NullString{
|
||||||
|
*input.Name,
|
||||||
|
true,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
name = sql.NullString{
|
||||||
|
"",
|
||||||
|
false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
projectLabel, err := r.Repository.CreateProjectLabel(ctx, pg.CreateProjectLabelParams{input.ProjectID,
|
||||||
|
input.LabelColorID, createdAt, name})
|
||||||
|
return &projectLabel, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) CreateTaskGroup(ctx context.Context, input NewTaskGroup) (*pg.TaskGroup, error) {
|
func (r *mutationResolver) CreateTaskGroup(ctx context.Context, input NewTaskGroup) (*pg.TaskGroup, error) {
|
||||||
@ -234,12 +254,12 @@ func (r *projectLabelResolver) ID(ctx context.Context, obj *pg.ProjectLabel) (uu
|
|||||||
return obj.ProjectLabelID, nil
|
return obj.ProjectLabelID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *projectLabelResolver) ColorHex(ctx context.Context, obj *pg.ProjectLabel) (string, error) {
|
func (r *projectLabelResolver) LabelColor(ctx context.Context, obj *pg.ProjectLabel) (*pg.LabelColor, error) {
|
||||||
labelColor, err := r.Repository.GetLabelColorByID(ctx, obj.LabelColorID)
|
labelColor, err := r.Repository.GetLabelColorByID(ctx, obj.LabelColorID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return &pg.LabelColor{}, err
|
||||||
}
|
}
|
||||||
return labelColor.ColorHex, nil
|
return &labelColor, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *projectLabelResolver) Name(ctx context.Context, obj *pg.ProjectLabel) (*string, error) {
|
func (r *projectLabelResolver) Name(ctx context.Context, obj *pg.ProjectLabel) (*string, error) {
|
||||||
@ -304,6 +324,10 @@ func (r *queryResolver) Projects(ctx context.Context, input *ProjectsFilter) ([]
|
|||||||
return r.Repository.GetAllProjects(ctx)
|
return r.Repository.GetAllProjects(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *queryResolver) LabelColors(ctx context.Context) ([]pg.LabelColor, error) {
|
||||||
|
return r.Repository.GetLabelColors(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *queryResolver) TaskGroups(ctx context.Context) ([]pg.TaskGroup, error) {
|
func (r *queryResolver) TaskGroups(ctx context.Context) ([]pg.TaskGroup, error) {
|
||||||
return r.Repository.GetAllTaskGroups(ctx)
|
return r.Repository.GetAllTaskGroups(ctx)
|
||||||
}
|
}
|
||||||
@ -424,6 +448,9 @@ func (r *userAccountResolver) ProfileIcon(ctx context.Context, obj *pg.UserAccou
|
|||||||
return profileIcon, nil
|
return profileIcon, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LabelColor returns LabelColorResolver implementation.
|
||||||
|
func (r *Resolver) LabelColor() LabelColorResolver { return &labelColorResolver{r} }
|
||||||
|
|
||||||
// Mutation returns MutationResolver implementation.
|
// Mutation returns MutationResolver implementation.
|
||||||
func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }
|
func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }
|
||||||
|
|
||||||
@ -454,6 +481,7 @@ func (r *Resolver) Team() TeamResolver { return &teamResolver{r} }
|
|||||||
// UserAccount returns UserAccountResolver implementation.
|
// UserAccount returns UserAccountResolver implementation.
|
||||||
func (r *Resolver) UserAccount() UserAccountResolver { return &userAccountResolver{r} }
|
func (r *Resolver) UserAccount() UserAccountResolver { return &userAccountResolver{r} }
|
||||||
|
|
||||||
|
type labelColorResolver struct{ *Resolver }
|
||||||
type mutationResolver struct{ *Resolver }
|
type mutationResolver struct{ *Resolver }
|
||||||
type projectResolver struct{ *Resolver }
|
type projectResolver struct{ *Resolver }
|
||||||
type projectLabelResolver struct{ *Resolver }
|
type projectLabelResolver struct{ *Resolver }
|
||||||
@ -464,3 +492,17 @@ type taskGroupResolver struct{ *Resolver }
|
|||||||
type taskLabelResolver struct{ *Resolver }
|
type taskLabelResolver struct{ *Resolver }
|
||||||
type teamResolver struct{ *Resolver }
|
type teamResolver struct{ *Resolver }
|
||||||
type userAccountResolver struct{ *Resolver }
|
type userAccountResolver struct{ *Resolver }
|
||||||
|
|
||||||
|
// !!! WARNING !!!
|
||||||
|
// The code below was going to be deleted when updating resolvers. It has been copied here so you have
|
||||||
|
// one last chance to move it out of harms way if you want. There are two reasons this happens:
|
||||||
|
// - When renaming or deleting a resolver the old code will be put in here. You can safely delete
|
||||||
|
// it when you're done.
|
||||||
|
// - You have helper methods in this file. Move them out to keep these resolver files clean.
|
||||||
|
func (r *projectLabelResolver) ColorHex(ctx context.Context, obj *pg.ProjectLabel) (string, error) {
|
||||||
|
labelColor, err := r.Repository.GetLabelColorByID(ctx, obj.LabelColorID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return labelColor.ColorHex, nil
|
||||||
|
}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE label_color ADD COLUMN name TEXT NOT NULL DEFAULT 'needs name';
|
@ -9,13 +9,73 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const createLabelColor = `-- name: CreateLabelColor :one
|
||||||
|
INSERT INTO label_color (name, color_hex, position) VALUES ($1, $2, $3)
|
||||||
|
RETURNING label_color_id, color_hex, position, name
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateLabelColorParams struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
ColorHex string `json:"color_hex"`
|
||||||
|
Position float64 `json:"position"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateLabelColor(ctx context.Context, arg CreateLabelColorParams) (LabelColor, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, createLabelColor, arg.Name, arg.ColorHex, arg.Position)
|
||||||
|
var i LabelColor
|
||||||
|
err := row.Scan(
|
||||||
|
&i.LabelColorID,
|
||||||
|
&i.ColorHex,
|
||||||
|
&i.Position,
|
||||||
|
&i.Name,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
const getLabelColorByID = `-- name: GetLabelColorByID :one
|
const getLabelColorByID = `-- name: GetLabelColorByID :one
|
||||||
SELECT label_color_id, color_hex, position FROM label_color WHERE label_color_id = $1
|
SELECT label_color_id, color_hex, position, name FROM label_color WHERE label_color_id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetLabelColorByID(ctx context.Context, labelColorID uuid.UUID) (LabelColor, error) {
|
func (q *Queries) GetLabelColorByID(ctx context.Context, labelColorID uuid.UUID) (LabelColor, error) {
|
||||||
row := q.db.QueryRowContext(ctx, getLabelColorByID, labelColorID)
|
row := q.db.QueryRowContext(ctx, getLabelColorByID, labelColorID)
|
||||||
var i LabelColor
|
var i LabelColor
|
||||||
err := row.Scan(&i.LabelColorID, &i.ColorHex, &i.Position)
|
err := row.Scan(
|
||||||
|
&i.LabelColorID,
|
||||||
|
&i.ColorHex,
|
||||||
|
&i.Position,
|
||||||
|
&i.Name,
|
||||||
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getLabelColors = `-- name: GetLabelColors :many
|
||||||
|
SELECT label_color_id, color_hex, position, name FROM label_color
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetLabelColors(ctx context.Context) ([]LabelColor, error) {
|
||||||
|
rows, err := q.db.QueryContext(ctx, getLabelColors)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []LabelColor
|
||||||
|
for rows.Next() {
|
||||||
|
var i LabelColor
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.LabelColorID,
|
||||||
|
&i.ColorHex,
|
||||||
|
&i.Position,
|
||||||
|
&i.Name,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
@ -13,6 +13,7 @@ type LabelColor struct {
|
|||||||
LabelColorID uuid.UUID `json:"label_color_id"`
|
LabelColorID uuid.UUID `json:"label_color_id"`
|
||||||
ColorHex string `json:"color_hex"`
|
ColorHex string `json:"color_hex"`
|
||||||
Position float64 `json:"position"`
|
Position float64 `json:"position"`
|
||||||
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Organization struct {
|
type Organization struct {
|
||||||
|
@ -26,6 +26,9 @@ type Repository interface {
|
|||||||
GetProjectLabelsForProject(ctx context.Context, projectID uuid.UUID) ([]ProjectLabel, error)
|
GetProjectLabelsForProject(ctx context.Context, projectID uuid.UUID) ([]ProjectLabel, error)
|
||||||
GetProjectLabelByID(ctx context.Context, projectLabelID uuid.UUID) (ProjectLabel, error)
|
GetProjectLabelByID(ctx context.Context, projectLabelID uuid.UUID) (ProjectLabel, error)
|
||||||
|
|
||||||
|
GetLabelColors(ctx context.Context) ([]LabelColor, error)
|
||||||
|
CreateLabelColor(ctx context.Context, arg CreateLabelColorParams) (LabelColor, 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
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Querier interface {
|
type Querier interface {
|
||||||
|
CreateLabelColor(ctx context.Context, arg CreateLabelColorParams) (LabelColor, error)
|
||||||
CreateOrganization(ctx context.Context, arg CreateOrganizationParams) (Organization, error)
|
CreateOrganization(ctx context.Context, arg CreateOrganizationParams) (Organization, error)
|
||||||
CreateProject(ctx context.Context, arg CreateProjectParams) (Project, error)
|
CreateProject(ctx context.Context, arg CreateProjectParams) (Project, error)
|
||||||
CreateProjectLabel(ctx context.Context, arg CreateProjectLabelParams) (ProjectLabel, error)
|
CreateProjectLabel(ctx context.Context, arg CreateProjectLabelParams) (ProjectLabel, error)
|
||||||
@ -36,6 +37,7 @@ type Querier interface {
|
|||||||
GetAllUserAccounts(ctx context.Context) ([]UserAccount, error)
|
GetAllUserAccounts(ctx context.Context) ([]UserAccount, error)
|
||||||
GetAssignedMembersForTask(ctx context.Context, taskID uuid.UUID) ([]TaskAssigned, error)
|
GetAssignedMembersForTask(ctx context.Context, taskID uuid.UUID) ([]TaskAssigned, error)
|
||||||
GetLabelColorByID(ctx context.Context, labelColorID uuid.UUID) (LabelColor, error)
|
GetLabelColorByID(ctx context.Context, labelColorID uuid.UUID) (LabelColor, error)
|
||||||
|
GetLabelColors(ctx context.Context) ([]LabelColor, error)
|
||||||
GetProjectByID(ctx context.Context, projectID uuid.UUID) (Project, error)
|
GetProjectByID(ctx context.Context, projectID uuid.UUID) (Project, error)
|
||||||
GetProjectLabelByID(ctx context.Context, projectLabelID uuid.UUID) (ProjectLabel, error)
|
GetProjectLabelByID(ctx context.Context, projectLabelID uuid.UUID) (ProjectLabel, error)
|
||||||
GetProjectLabelsForProject(ctx context.Context, projectID uuid.UUID) ([]ProjectLabel, error)
|
GetProjectLabelsForProject(ctx context.Context, projectID uuid.UUID) ([]ProjectLabel, error)
|
||||||
|
@ -1,2 +1,9 @@
|
|||||||
-- name: GetLabelColorByID :one
|
-- name: GetLabelColorByID :one
|
||||||
SELECT * FROM label_color WHERE label_color_id = $1;
|
SELECT * FROM label_color WHERE label_color_id = $1;
|
||||||
|
|
||||||
|
-- name: GetLabelColors :many
|
||||||
|
SELECT * FROM label_color;
|
||||||
|
|
||||||
|
-- name: CreateLabelColor :one
|
||||||
|
INSERT INTO label_color (name, color_hex, position) VALUES ($1, $2, $3)
|
||||||
|
RETURNING *;
|
||||||
|
@ -7,8 +7,9 @@ import { useMeQuery } from 'shared/generated/graphql';
|
|||||||
|
|
||||||
type GlobalTopNavbarProps = {
|
type GlobalTopNavbarProps = {
|
||||||
name: string;
|
name: string;
|
||||||
|
projectMembers?: null | Array<TaskUser>;
|
||||||
};
|
};
|
||||||
const GlobalTopNavbar: React.FC<GlobalTopNavbarProps> = ({ name }) => {
|
const GlobalTopNavbar: React.FC<GlobalTopNavbarProps> = ({ name, projectMembers }) => {
|
||||||
const { loading, data } = useMeQuery();
|
const { loading, data } = useMeQuery();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { userID, setUserID } = useContext(UserIDContext);
|
const { userID, setUserID } = useContext(UserIDContext);
|
||||||
@ -50,6 +51,7 @@ const GlobalTopNavbar: React.FC<GlobalTopNavbarProps> = ({ name }) => {
|
|||||||
lastName={data ? data.me.lastName : ''}
|
lastName={data ? data.me.lastName : ''}
|
||||||
initials={!data ? '' : data.me.profileIcon.initials ?? ''}
|
initials={!data ? '' : data.me.profileIcon.initials ?? ''}
|
||||||
onNotificationClick={() => console.log('beep')}
|
onNotificationClick={() => console.log('beep')}
|
||||||
|
projectMembers={projectMembers}
|
||||||
onProfileClick={onProfileClick}
|
onProfileClick={onProfileClick}
|
||||||
/>
|
/>
|
||||||
{menu.isOpen && (
|
{menu.isOpen && (
|
||||||
|
@ -12,6 +12,7 @@ type KanbanBoardProps = {
|
|||||||
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;
|
||||||
|
onCardMemberClick: OnCardMemberClick;
|
||||||
};
|
};
|
||||||
|
|
||||||
const KanbanBoard: React.FC<KanbanBoardProps> = ({
|
const KanbanBoard: React.FC<KanbanBoardProps> = ({
|
||||||
@ -22,6 +23,7 @@ const KanbanBoard: React.FC<KanbanBoardProps> = ({
|
|||||||
onCardDrop,
|
onCardDrop,
|
||||||
onListDrop,
|
onListDrop,
|
||||||
onCreateList,
|
onCreateList,
|
||||||
|
onCardMemberClick,
|
||||||
}) => {
|
}) => {
|
||||||
const match = useRouteMatch();
|
const match = useRouteMatch();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
@ -40,6 +42,7 @@ const KanbanBoard: React.FC<KanbanBoardProps> = ({
|
|||||||
onListDrop={onListDrop}
|
onListDrop={onListDrop}
|
||||||
{...listsData}
|
{...listsData}
|
||||||
onCreateList={onCreateList}
|
onCreateList={onCreateList}
|
||||||
|
onCardMemberClick={onCardMemberClick}
|
||||||
/>
|
/>
|
||||||
</Board>
|
</Board>
|
||||||
);
|
);
|
||||||
|
@ -18,8 +18,10 @@ import {
|
|||||||
useAssignTaskMutation,
|
useAssignTaskMutation,
|
||||||
DeleteTaskDocument,
|
DeleteTaskDocument,
|
||||||
FindProjectDocument,
|
FindProjectDocument,
|
||||||
|
useCreateProjectLabelMutation,
|
||||||
} from 'shared/generated/graphql';
|
} from 'shared/generated/graphql';
|
||||||
|
|
||||||
|
import TaskAssignee from 'shared/components/TaskAssignee';
|
||||||
import QuickCardEditor from 'shared/components/QuickCardEditor';
|
import QuickCardEditor from 'shared/components/QuickCardEditor';
|
||||||
import ListActions from 'shared/components/ListActions';
|
import ListActions from 'shared/components/ListActions';
|
||||||
import MemberManager from 'shared/components/MemberManager';
|
import MemberManager from 'shared/components/MemberManager';
|
||||||
@ -30,6 +32,7 @@ import LabelManager from 'shared/components/PopupMenu/LabelManager';
|
|||||||
import LabelEditor from 'shared/components/PopupMenu/LabelEditor';
|
import LabelEditor from 'shared/components/PopupMenu/LabelEditor';
|
||||||
import produce from 'immer';
|
import produce from 'immer';
|
||||||
import Details from './Details';
|
import Details from './Details';
|
||||||
|
import MiniProfile from 'shared/components/MiniProfile';
|
||||||
|
|
||||||
type TaskRouteProps = {
|
type TaskRouteProps = {
|
||||||
taskID: string;
|
taskID: string;
|
||||||
@ -52,14 +55,23 @@ const Title = styled.span`
|
|||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
`;
|
`;
|
||||||
|
const ProjectMembers = styled.div`
|
||||||
|
display: flex;
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-top: 4px;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
type LabelManagerEditorProps = {
|
type LabelManagerEditorProps = {
|
||||||
labels: Array<Label>;
|
labels: Array<Label>;
|
||||||
|
projectID: string;
|
||||||
|
labelColors: Array<LabelColor>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const LabelManagerEditor: React.FC<LabelManagerEditorProps> = ({ labels: initialLabels }) => {
|
const LabelManagerEditor: React.FC<LabelManagerEditorProps> = ({ labels: initialLabels, projectID, labelColors }) => {
|
||||||
const [labels, setLabels] = useState<Array<Label>>(initialLabels);
|
const [labels, setLabels] = useState<Array<Label>>(initialLabels);
|
||||||
const [currentLabel, setCurrentLabel] = useState('');
|
const [currentLabel, setCurrentLabel] = useState('');
|
||||||
|
const [createProjectLabel] = useCreateProjectLabelMutation();
|
||||||
const { setTab } = usePopup();
|
const { setTab } = usePopup();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -74,26 +86,21 @@ const LabelManagerEditor: React.FC<LabelManagerEditorProps> = ({ labels: initial
|
|||||||
setTab(1);
|
setTab(1);
|
||||||
}}
|
}}
|
||||||
onLabelToggle={labelId => {
|
onLabelToggle={labelId => {
|
||||||
setLabels(
|
setCurrentLabel(labelId);
|
||||||
produce(labels, draftState => {
|
setTab(1);
|
||||||
const idx = labels.findIndex(label => label.labelId === labelId);
|
|
||||||
if (idx !== -1) {
|
|
||||||
draftState[idx] = { ...draftState[idx], active: !labels[idx].active };
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Popup>
|
</Popup>
|
||||||
<Popup onClose={() => {}} title="Edit label" tab={1}>
|
<Popup onClose={() => {}} title="Edit label" tab={1}>
|
||||||
<LabelEditor
|
<LabelEditor
|
||||||
|
labelColors={labelColors}
|
||||||
label={labels.find(label => label.labelId === currentLabel) ?? null}
|
label={labels.find(label => label.labelId === currentLabel) ?? null}
|
||||||
onLabelEdit={(_labelId, name, color) => {
|
onLabelEdit={(_labelId, name, color) => {
|
||||||
setLabels(
|
setLabels(
|
||||||
produce(labels, draftState => {
|
produce(labels, draftState => {
|
||||||
const idx = labels.findIndex(label => label.labelId === currentLabel);
|
const idx = labels.findIndex(label => label.labelId === currentLabel);
|
||||||
if (idx !== -1) {
|
if (idx !== -1) {
|
||||||
draftState[idx] = { ...draftState[idx], name, color };
|
draftState[idx] = { ...draftState[idx], name, labelColor: color };
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -103,9 +110,12 @@ const LabelManagerEditor: React.FC<LabelManagerEditorProps> = ({ labels: initial
|
|||||||
</Popup>
|
</Popup>
|
||||||
<Popup onClose={() => {}} title="Create new label" tab={2}>
|
<Popup onClose={() => {}} title="Create new label" tab={2}>
|
||||||
<LabelEditor
|
<LabelEditor
|
||||||
|
labelColors={labelColors}
|
||||||
label={null}
|
label={null}
|
||||||
onLabelEdit={(_labelId, name, color) => {
|
onLabelEdit={(_labelId, name, color) => {
|
||||||
setLabels([...labels, { labelId: name, name, color, active: false }]);
|
console.log(name, color);
|
||||||
|
setLabels([...labels, { labelId: name, name, labelColor: color, active: false }]);
|
||||||
|
createProjectLabel({ variables: { projectID, labelColorID: color.id, name } });
|
||||||
setTab(0);
|
setTab(0);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -124,7 +134,7 @@ const initialQuickCardEditorState: QuickCardEditorState = { isOpen: false, top:
|
|||||||
const initialLabelsPopupState = { taskID: '', isOpen: false, top: 0, left: 0 };
|
const initialLabelsPopupState = { taskID: '', isOpen: false, top: 0, left: 0 };
|
||||||
const initialTaskDetailsState = { isOpen: false, taskID: '' };
|
const initialTaskDetailsState = { isOpen: false, taskID: '' };
|
||||||
|
|
||||||
const ProjectActions = styled.div`
|
const ProjectBar = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
@ -132,6 +142,11 @@ const ProjectActions = styled.div`
|
|||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const ProjectActions = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
const ProjectAction = styled.div`
|
const ProjectAction = styled.div`
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -351,46 +366,67 @@ const Project = () => {
|
|||||||
task: currentTask,
|
task: currentTask,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GlobalTopNavbar name={data.findProject.name} />
|
<GlobalTopNavbar projectMembers={availableMembers} name={data.findProject.name} />
|
||||||
<ProjectActions>
|
<ProjectBar>
|
||||||
<ProjectAction
|
<ProjectActions>
|
||||||
ref={$labelsRef}
|
<ProjectAction
|
||||||
onClick={() => {
|
ref={$labelsRef}
|
||||||
showPopup(
|
onClick={() => {
|
||||||
$labelsRef,
|
showPopup(
|
||||||
<LabelManagerEditor
|
$labelsRef,
|
||||||
labels={data.findProject.labels.map(label => {
|
<LabelManagerEditor
|
||||||
return {
|
labelColors={data.labelColors}
|
||||||
labelId: label.id,
|
labels={data.findProject.labels.map(label => {
|
||||||
name: label.name ?? '',
|
return {
|
||||||
color: label.colorHex,
|
labelId: label.id,
|
||||||
active: false,
|
name: label.name ?? '',
|
||||||
};
|
labelColor: label.labelColor,
|
||||||
})}
|
active: false,
|
||||||
/>,
|
};
|
||||||
);
|
})}
|
||||||
}}
|
projectID={projectId}
|
||||||
>
|
/>,
|
||||||
<Tags size={13} color="#c2c6dc" />
|
);
|
||||||
<ProjectActionText>Labels</ProjectActionText>
|
}}
|
||||||
</ProjectAction>
|
>
|
||||||
<ProjectAction>
|
<Tags size={13} color="#c2c6dc" />
|
||||||
<ToggleOn size={13} color="#c2c6dc" />
|
<ProjectActionText>Labels</ProjectActionText>
|
||||||
<ProjectActionText>Fields</ProjectActionText>
|
</ProjectAction>
|
||||||
</ProjectAction>
|
<ProjectAction>
|
||||||
<ProjectAction>
|
<ToggleOn size={13} color="#c2c6dc" />
|
||||||
<Bolt size={13} color="#c2c6dc" />
|
<ProjectActionText>Fields</ProjectActionText>
|
||||||
<ProjectActionText>Rules</ProjectActionText>
|
</ProjectAction>
|
||||||
</ProjectAction>
|
<ProjectAction>
|
||||||
</ProjectActions>
|
<Bolt size={13} color="#c2c6dc" />
|
||||||
|
<ProjectActionText>Rules</ProjectActionText>
|
||||||
|
</ProjectAction>
|
||||||
|
</ProjectActions>
|
||||||
|
</ProjectBar>
|
||||||
<KanbanBoard
|
<KanbanBoard
|
||||||
listsData={currentListsData}
|
listsData={currentListsData}
|
||||||
onCardDrop={onCardDrop}
|
onCardDrop={onCardDrop}
|
||||||
onListDrop={onListDrop}
|
onListDrop={onListDrop}
|
||||||
onCardCreate={onCardCreate}
|
onCardCreate={onCardCreate}
|
||||||
onCreateList={onCreateList}
|
onCreateList={onCreateList}
|
||||||
|
onCardMemberClick={($targetRef, taskID, memberID) => {
|
||||||
|
showPopup(
|
||||||
|
$targetRef,
|
||||||
|
<Popup title={null} onClose={() => {}} tab={0}>
|
||||||
|
<MiniProfile
|
||||||
|
profileIcon={availableMembers[0].profileIcon}
|
||||||
|
displayName="Jordan Knott"
|
||||||
|
username="@jordanthedev"
|
||||||
|
bio="None"
|
||||||
|
onRemoveFromTask={() => {
|
||||||
|
/* unassignTask({ variables: { taskID: data.findTask.id, userID: userID ?? '' } }); */
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popup>,
|
||||||
|
);
|
||||||
|
}}
|
||||||
onQuickEditorOpen={onQuickEditorOpen}
|
onQuickEditorOpen={onQuickEditorOpen}
|
||||||
onOpenListActionsPopup={($targetRef, taskGroupID) => {
|
onOpenListActionsPopup={($targetRef, taskGroupID) => {
|
||||||
showPopup(
|
showPopup(
|
||||||
|
12
web/src/citadel.d.ts
vendored
12
web/src/citadel.d.ts
vendored
@ -84,7 +84,7 @@ type Team = {
|
|||||||
type Label = {
|
type Label = {
|
||||||
labelId: string;
|
labelId: string;
|
||||||
name: string;
|
name: string;
|
||||||
color: string;
|
labelColor: LabelColor;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,7 +117,17 @@ type ElementSize = {
|
|||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type LabelColor = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
colorHex: string;
|
||||||
|
position: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type OnCardMemberClick = ($targetRef: RefObject<HTMLElement>, taskID: string, memberID: string) => void;
|
||||||
|
|
||||||
type ElementBounds = {
|
type ElementBounds = {
|
||||||
size: ElementSize;
|
size: ElementSize;
|
||||||
position: ElementPosition;
|
position: ElementPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
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';
|
||||||
|
import { mixin } from 'shared/utils/styles';
|
||||||
|
|
||||||
export const Container = styled.div``;
|
export const Container = styled.div``;
|
||||||
|
|
||||||
@ -27,11 +28,11 @@ export const Wrapper = styled.div<{ editorOpen: boolean }>`
|
|||||||
${props =>
|
${props =>
|
||||||
props.editorOpen &&
|
props.editorOpen &&
|
||||||
css`
|
css`
|
||||||
background-color: #ebecf0;
|
background-color: #10163a;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
height: auto;
|
height: auto;
|
||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
padding: 4px;
|
padding: 8px;
|
||||||
transition: background 85ms ease-in, opacity 40ms ease-in, border-color 85ms ease-in;
|
transition: background 85ms ease-in, opacity 40ms ease-in, border-color 85ms ease-in;
|
||||||
`}
|
`}
|
||||||
`;
|
`;
|
||||||
@ -53,17 +54,33 @@ export const ListNameEditorWrapper = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
`;
|
`;
|
||||||
export const ListNameEditor = styled(TextareaAutosize)`
|
export const ListNameEditor = styled(TextareaAutosize)`
|
||||||
background: #fff;
|
background-color: ${props => mixin.lighten('#262c49', 0.05)};
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: inset 0 0 0 2px #0079bf;
|
box-shadow: inset 0 0 0 2px #0079bf;
|
||||||
display: block;
|
|
||||||
margin: 0;
|
|
||||||
transition: margin 85ms ease-in, background 85ms ease-in;
|
transition: margin 85ms ease-in, background 85ms ease-in;
|
||||||
width: 100%;
|
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
|
|
||||||
|
font-family: 'Droid Sans';
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
resize: none;
|
||||||
|
height: 54px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: none;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
max-height: 162px;
|
||||||
|
min-height: 54px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
outline: none;
|
line-height: 20px;
|
||||||
|
|
||||||
|
color: #c2c6dc;
|
||||||
|
l &:focus {
|
||||||
|
background-color: ${props => mixin.lighten('#262c49', 0.05)};
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ListAddControls = styled.div`
|
export const ListAddControls = styled.div`
|
||||||
@ -74,10 +91,9 @@ export const ListAddControls = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const AddListButton = styled.button`
|
export const AddListButton = styled.button`
|
||||||
background-color: #5aac44;
|
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: #fff;
|
color: #c2c6dc;
|
||||||
float: left;
|
float: left;
|
||||||
margin: 0 4px 0 0;
|
margin: 0 4px 0 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -88,6 +104,8 @@ export const AddListButton = styled.button`
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
||||||
|
background: rgb(115, 103, 240);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CancelAdd = styled.div`
|
export const CancelAdd = styled.div`
|
||||||
|
@ -45,6 +45,7 @@ const NameEditor: React.FC<NameEditorProps> = ({ onSave, onCancel }) => {
|
|||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
value={listName}
|
value={listName}
|
||||||
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setListName(e.currentTarget.value)}
|
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setListName(e.currentTarget.value)}
|
||||||
|
placeholder="Enter a title for this list..."
|
||||||
/>
|
/>
|
||||||
</ListNameEditorWrapper>
|
</ListNameEditorWrapper>
|
||||||
<ListAddControls>
|
<ListAddControls>
|
||||||
@ -60,7 +61,7 @@ const NameEditor: React.FC<NameEditorProps> = ({ onSave, onCancel }) => {
|
|||||||
Save
|
Save
|
||||||
</AddListButton>
|
</AddListButton>
|
||||||
<CancelAdd onClick={() => onCancel()}>
|
<CancelAdd onClick={() => onCancel()}>
|
||||||
<Cross />
|
<Cross color="#c2c6dc" />
|
||||||
</CancelAdd>
|
</CancelAdd>
|
||||||
</ListAddControls>
|
</ListAddControls>
|
||||||
</>
|
</>
|
||||||
|
@ -18,13 +18,23 @@ const labelData = [
|
|||||||
{
|
{
|
||||||
labelId: 'development',
|
labelId: 'development',
|
||||||
name: 'Development',
|
name: 'Development',
|
||||||
color: LabelColors.BLUE,
|
labelColor: {
|
||||||
|
id: '1',
|
||||||
|
colorHex: LabelColors.BLUE,
|
||||||
|
name: 'blue',
|
||||||
|
position: 1,
|
||||||
|
},
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
labelId: 'general',
|
labelId: 'general',
|
||||||
name: 'General',
|
name: 'General',
|
||||||
color: LabelColors.PINK,
|
labelColor: {
|
||||||
|
id: '2',
|
||||||
|
colorHex: LabelColors.PINK,
|
||||||
|
name: 'pink',
|
||||||
|
position: 2,
|
||||||
|
},
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import styled, { css } from 'styled-components';
|
import styled, { css } from 'styled-components';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { mixin } from 'shared/utils/styles';
|
import { mixin } from 'shared/utils/styles';
|
||||||
|
import { RefObject } from 'react';
|
||||||
|
|
||||||
export const ClockIcon = styled(FontAwesomeIcon)``;
|
export const ClockIcon = styled(FontAwesomeIcon)``;
|
||||||
|
|
||||||
@ -127,7 +128,7 @@ export const CardMembers = styled.div`
|
|||||||
margin: 0 -2px 0 0;
|
margin: 0 -2px 0 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CardMember = styled.div<{ bgColor: string }>`
|
export const CardMember = styled.div<{ bgColor: string; ref: any }>`
|
||||||
height: 28px;
|
height: 28px;
|
||||||
width: 28px;
|
width: 28px;
|
||||||
float: right;
|
float: right;
|
||||||
|
@ -33,6 +33,31 @@ type Checklist = {
|
|||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type MemberProps = {
|
||||||
|
onCardMemberClick?: OnCardMemberClick;
|
||||||
|
taskID: string;
|
||||||
|
member: TaskUser;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Member: React.FC<MemberProps> = ({ onCardMemberClick, taskID, member }) => {
|
||||||
|
const $targetRef = useRef<HTMLDivElement>();
|
||||||
|
return (
|
||||||
|
<CardMember
|
||||||
|
ref={$targetRef}
|
||||||
|
onClick={e => {
|
||||||
|
if (onCardMemberClick) {
|
||||||
|
e.stopPropagation();
|
||||||
|
onCardMemberClick($targetRef, taskID, member.userID);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
key={member.userID}
|
||||||
|
bgColor={member.profileIcon.bgColor ?? '#7367F0'}
|
||||||
|
>
|
||||||
|
<CardMemberInitials>{member.profileIcon.initials}</CardMemberInitials>
|
||||||
|
</CardMember>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
@ -46,6 +71,7 @@ type Props = {
|
|||||||
labels?: Label[];
|
labels?: Label[];
|
||||||
wrapperProps?: any;
|
wrapperProps?: any;
|
||||||
members?: Array<TaskUser> | null;
|
members?: Array<TaskUser> | null;
|
||||||
|
onCardMemberClick?: OnCardMemberClick;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Card = React.forwardRef(
|
const Card = React.forwardRef(
|
||||||
@ -63,6 +89,7 @@ const Card = React.forwardRef(
|
|||||||
checklists,
|
checklists,
|
||||||
watched,
|
watched,
|
||||||
members,
|
members,
|
||||||
|
onCardMemberClick,
|
||||||
}: Props,
|
}: Props,
|
||||||
$cardRef: any,
|
$cardRef: any,
|
||||||
) => {
|
) => {
|
||||||
@ -109,7 +136,7 @@ const Card = React.forwardRef(
|
|||||||
<ListCardLabels>
|
<ListCardLabels>
|
||||||
{labels &&
|
{labels &&
|
||||||
labels.map(label => (
|
labels.map(label => (
|
||||||
<ListCardLabel color={label.color} key={label.name}>
|
<ListCardLabel color={label.labelColor.colorHex} key={label.name}>
|
||||||
{label.name}
|
{label.name}
|
||||||
</ListCardLabel>
|
</ListCardLabel>
|
||||||
))}
|
))}
|
||||||
@ -141,11 +168,7 @@ const Card = React.forwardRef(
|
|||||||
</ListCardBadges>
|
</ListCardBadges>
|
||||||
<CardMembers>
|
<CardMembers>
|
||||||
{members &&
|
{members &&
|
||||||
members.map(member => (
|
members.map(member => <Member taskID={taskID} member={member} onCardMemberClick={onCardMemberClick} />)}
|
||||||
<CardMember key={member.userID} bgColor={member.profileIcon.bgColor ?? '#7367F0'}>
|
|
||||||
<CardMemberInitials>{member.profileIcon.initials}</CardMemberInitials>
|
|
||||||
</CardMember>
|
|
||||||
))}
|
|
||||||
</CardMembers>
|
</CardMembers>
|
||||||
</ListCardDetails>
|
</ListCardDetails>
|
||||||
</ListCardInnerContainer>
|
</ListCardInnerContainer>
|
||||||
|
@ -75,10 +75,10 @@ export const ComposerControlsActionsSection = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const AddCardButton = styled.button`
|
export const AddCardButton = styled.button`
|
||||||
background-color: #5aac44;
|
background: rgb(115, 103, 240);
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: #fff;
|
color: #c2c6dc;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
@ -21,7 +21,14 @@ export const Default = () => {
|
|||||||
taskGroup: { name: 'General', taskGroupID: '1' },
|
taskGroup: { name: 'General', taskGroupID: '1' },
|
||||||
name: 'Hello, world',
|
name: 'Hello, world',
|
||||||
position: 1,
|
position: 1,
|
||||||
labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }],
|
labels: [
|
||||||
|
{
|
||||||
|
labelId: 'soft-skills',
|
||||||
|
labelColor: { id: '1', colorHex: '#fff', name: 'white', position: 1 },
|
||||||
|
active: true,
|
||||||
|
name: 'Soft Skills',
|
||||||
|
},
|
||||||
|
],
|
||||||
description: 'hello!',
|
description: 'hello!',
|
||||||
members: [
|
members: [
|
||||||
{ userID: '1', profileIcon: { url: null, initials: null, bgColor: null }, displayName: 'Jordan Knott' },
|
{ userID: '1', profileIcon: { url: null, initials: null, bgColor: null }, displayName: 'Jordan Knott' },
|
||||||
|
@ -20,13 +20,23 @@ const labelData = [
|
|||||||
{
|
{
|
||||||
labelId: 'development',
|
labelId: 'development',
|
||||||
name: 'Development',
|
name: 'Development',
|
||||||
color: LabelColors.BLUE,
|
labelColor: {
|
||||||
|
id: '1',
|
||||||
|
colorHex: LabelColors.BLUE,
|
||||||
|
name: 'blue',
|
||||||
|
position: 1,
|
||||||
|
},
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
labelId: 'general',
|
labelId: 'general',
|
||||||
name: 'General',
|
name: 'General',
|
||||||
color: LabelColors.PINK,
|
labelColor: {
|
||||||
|
id: '2',
|
||||||
|
colorHex: LabelColors.PINK,
|
||||||
|
name: 'pink',
|
||||||
|
position: 2,
|
||||||
|
},
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -96,6 +96,7 @@ export const Default = () => {
|
|||||||
onQuickEditorOpen={action('card composer open')}
|
onQuickEditorOpen={action('card composer open')}
|
||||||
onCardDrop={onCardDrop}
|
onCardDrop={onCardDrop}
|
||||||
onListDrop={onListDrop}
|
onListDrop={onListDrop}
|
||||||
|
onCardMemberClick={action('card member click')}
|
||||||
onCardCreate={action('card create')}
|
onCardCreate={action('card create')}
|
||||||
onCreateList={listName => {
|
onCreateList={listName => {
|
||||||
const [lastColumn] = Object.values(listsData.columns)
|
const [lastColumn] = Object.values(listsData.columns)
|
||||||
@ -209,6 +210,7 @@ export const ListsWithManyList = () => {
|
|||||||
onListDrop={onListDrop}
|
onListDrop={onListDrop}
|
||||||
onCreateList={action('create list')}
|
onCreateList={action('create list')}
|
||||||
onExtraMenuOpen={action('extra menu open')}
|
onExtraMenuOpen={action('extra menu open')}
|
||||||
|
onCardMemberClick={action('card member click')}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -30,6 +30,7 @@ type Props = {
|
|||||||
onQuickEditorOpen: (e: ContextMenuEvent) => void;
|
onQuickEditorOpen: (e: ContextMenuEvent) => void;
|
||||||
onCreateList: (listName: string) => void;
|
onCreateList: (listName: string) => void;
|
||||||
onExtraMenuOpen: (taskGroupID: string, $targetRef: React.RefObject<HTMLElement>) => void;
|
onExtraMenuOpen: (taskGroupID: string, $targetRef: React.RefObject<HTMLElement>) => void;
|
||||||
|
onCardMemberClick: OnCardMemberClick;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Lists: React.FC<Props> = ({
|
const Lists: React.FC<Props> = ({
|
||||||
@ -41,6 +42,7 @@ const Lists: React.FC<Props> = ({
|
|||||||
onCardCreate,
|
onCardCreate,
|
||||||
onQuickEditorOpen,
|
onQuickEditorOpen,
|
||||||
onCreateList,
|
onCreateList,
|
||||||
|
onCardMemberClick,
|
||||||
onExtraMenuOpen,
|
onExtraMenuOpen,
|
||||||
}) => {
|
}) => {
|
||||||
const onDragEnd = ({ draggableId, source, destination, type }: DropResult) => {
|
const onDragEnd = ({ draggableId, source, destination, type }: DropResult) => {
|
||||||
@ -161,6 +163,7 @@ const Lists: React.FC<Props> = ({
|
|||||||
labels={task.labels}
|
labels={task.labels}
|
||||||
members={task.members}
|
members={task.members}
|
||||||
onClick={() => onCardClick(task)}
|
onClick={() => onCardClick(task)}
|
||||||
|
onCardMemberClick={onCardMemberClick}
|
||||||
onContextMenu={onQuickEditorOpen}
|
onContextMenu={onQuickEditorOpen}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -4,14 +4,15 @@ import { Checkmark } from 'shared/icons';
|
|||||||
import { SaveButton, DeleteButton, LabelBox, EditLabelForm, FieldLabel, FieldName } from './Styles';
|
import { SaveButton, DeleteButton, LabelBox, EditLabelForm, FieldLabel, FieldName } from './Styles';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
labelColors: Array<LabelColor>;
|
||||||
label: Label | null;
|
label: Label | null;
|
||||||
onLabelEdit: (labelId: string | null, labelName: string, color: string) => void;
|
onLabelEdit: (labelId: string | null, labelName: string, labelColor: LabelColor) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const LabelManager = ({ label, onLabelEdit }: Props) => {
|
const LabelManager = ({ labelColors, label, onLabelEdit }: Props) => {
|
||||||
console.log(label);
|
console.log(label);
|
||||||
const [currentLabel, setCurrentLabel] = useState(label ? label.name : '');
|
const [currentLabel, setCurrentLabel] = useState(label ? label.name : '');
|
||||||
const [currentColor, setCurrentColor] = useState<string | null>(label ? label.color : null);
|
const [currentColor, setCurrentColor] = useState<LabelColor | null>(label ? label.labelColor : null);
|
||||||
return (
|
return (
|
||||||
<EditLabelForm>
|
<EditLabelForm>
|
||||||
<FieldLabel>Name</FieldLabel>
|
<FieldLabel>Name</FieldLabel>
|
||||||
@ -26,14 +27,14 @@ const LabelManager = ({ label, onLabelEdit }: Props) => {
|
|||||||
/>
|
/>
|
||||||
<FieldLabel>Select a color</FieldLabel>
|
<FieldLabel>Select a color</FieldLabel>
|
||||||
<div>
|
<div>
|
||||||
{Object.values(LabelColors).map(labelColor => (
|
{labelColors.map((labelColor: LabelColor) => (
|
||||||
<LabelBox
|
<LabelBox
|
||||||
color={labelColor}
|
color={labelColor.colorHex}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentColor(labelColor);
|
setCurrentColor(labelColor);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{labelColor === currentColor && <Checkmark color="#fff" size={12} />}
|
{currentColor && labelColor.id === currentColor.id && <Checkmark color="#fff" size={12} />}
|
||||||
</LabelBox>
|
</LabelBox>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,7 +49,7 @@ const LabelManager: React.FC<Props> = ({ labels, onLabelToggle, onLabelEdit, onL
|
|||||||
</LabelIcon>
|
</LabelIcon>
|
||||||
<CardLabel
|
<CardLabel
|
||||||
key={label.labelId}
|
key={label.labelId}
|
||||||
color={label.color}
|
color={label.labelColor.colorHex}
|
||||||
active={currentLabel === label.labelId}
|
active={currentLabel === label.labelId}
|
||||||
onMouseEnter={() => {
|
onMouseEnter={() => {
|
||||||
setCurrentLabel(label.labelId);
|
setCurrentLabel(label.labelId);
|
||||||
|
@ -28,13 +28,23 @@ const labelData = [
|
|||||||
{
|
{
|
||||||
labelId: 'development',
|
labelId: 'development',
|
||||||
name: 'Development',
|
name: 'Development',
|
||||||
color: LabelColors.BLUE,
|
labelColor: {
|
||||||
active: true,
|
id: '1',
|
||||||
|
name: 'white',
|
||||||
|
colorHex: LabelColors.BLUE,
|
||||||
|
position: 1,
|
||||||
|
},
|
||||||
|
active: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
labelId: 'general',
|
labelId: 'general',
|
||||||
name: 'General',
|
name: 'General',
|
||||||
color: LabelColors.PINK,
|
labelColor: {
|
||||||
|
id: '1',
|
||||||
|
name: 'white',
|
||||||
|
colorHex: LabelColors.PINK,
|
||||||
|
position: 1,
|
||||||
|
},
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -75,13 +85,14 @@ const LabelManagerEditor = () => {
|
|||||||
</Popup>
|
</Popup>
|
||||||
<Popup onClose={action('on close')} title="Edit label" tab={1}>
|
<Popup onClose={action('on close')} title="Edit label" tab={1}>
|
||||||
<LabelEditor
|
<LabelEditor
|
||||||
|
labelColors={[{ id: '1', colorHex: '#c2c6dc', position: 1, name: 'gray' }]}
|
||||||
label={labels.find(label => label.labelId === currentLabel) ?? null}
|
label={labels.find(label => label.labelId === currentLabel) ?? null}
|
||||||
onLabelEdit={(_labelId, name, color) => {
|
onLabelEdit={(_labelId, name, color) => {
|
||||||
setLabels(
|
setLabels(
|
||||||
produce(labels, draftState => {
|
produce(labels, draftState => {
|
||||||
const idx = labels.findIndex(label => label.labelId === currentLabel);
|
const idx = labels.findIndex(label => label.labelId === currentLabel);
|
||||||
if (idx !== -1) {
|
if (idx !== -1) {
|
||||||
draftState[idx] = { ...draftState[idx], name, color };
|
draftState[idx] = { ...draftState[idx], name, labelColor: color };
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -92,8 +103,9 @@ const LabelManagerEditor = () => {
|
|||||||
<Popup onClose={action('on close')} title="Create new label" tab={2}>
|
<Popup onClose={action('on close')} title="Create new label" tab={2}>
|
||||||
<LabelEditor
|
<LabelEditor
|
||||||
label={null}
|
label={null}
|
||||||
|
labelColors={[{ id: '1', colorHex: '#c2c6dc', position: 1, name: 'gray' }]}
|
||||||
onLabelEdit={(_labelId, name, color) => {
|
onLabelEdit={(_labelId, name, color) => {
|
||||||
setLabels([...labels, { labelId: name, name, color, active: false }]);
|
setLabels([...labels, { labelId: name, name, labelColor: color, active: false }]);
|
||||||
setTab(0);
|
setTab(0);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -141,7 +153,11 @@ export const LabelsLabelEditor = () => {
|
|||||||
onClose={() => setPopupOpen(false)}
|
onClose={() => setPopupOpen(false)}
|
||||||
left={10}
|
left={10}
|
||||||
>
|
>
|
||||||
<LabelEditor label={labelData[0]} onLabelEdit={action('label edit')} />
|
<LabelEditor
|
||||||
|
label={labelData[0]}
|
||||||
|
onLabelEdit={action('label edit')}
|
||||||
|
labelColors={[{ id: '1', colorHex: '#c2c6dc', position: 1, name: 'gray' }]}
|
||||||
|
/>
|
||||||
</PopupMenu>
|
</PopupMenu>
|
||||||
)}
|
)}
|
||||||
<button type="submit" onClick={() => setPopupOpen(true)}>
|
<button type="submit" onClick={() => setPopupOpen(true)}>
|
||||||
@ -239,7 +255,19 @@ export const DueDateManagerPopup = () => {
|
|||||||
taskGroup: { name: 'General', taskGroupID: '1' },
|
taskGroup: { name: 'General', taskGroupID: '1' },
|
||||||
name: 'Hello, world',
|
name: 'Hello, world',
|
||||||
position: 1,
|
position: 1,
|
||||||
labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }],
|
labels: [
|
||||||
|
{
|
||||||
|
labelId: 'soft-skills',
|
||||||
|
labelColor: {
|
||||||
|
id: '1',
|
||||||
|
name: 'white',
|
||||||
|
colorHex: '#fff',
|
||||||
|
position: 1,
|
||||||
|
},
|
||||||
|
active: true,
|
||||||
|
name: 'Soft Skills',
|
||||||
|
},
|
||||||
|
],
|
||||||
description: 'hello!',
|
description: 'hello!',
|
||||||
members: [
|
members: [
|
||||||
{ userID: '1', profileIcon: { bgColor: null, url: null, initials: null }, displayName: 'Jordan Knott' },
|
{ userID: '1', profileIcon: { bgColor: null, url: null, initials: null }, displayName: 'Jordan Knott' },
|
||||||
@ -325,4 +353,3 @@ export const MiniProfilePopup = () => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -207,22 +207,24 @@ export const FieldName = styled.input`
|
|||||||
margin: 4px 0 12px;
|
margin: 4px 0 12px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 3px;
|
|
||||||
display: block;
|
display: block;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
background: #262c49;
|
background: #262c49;
|
||||||
|
outline: none;
|
||||||
|
color: #c2c6dc;
|
||||||
|
|
||||||
|
border-radius: 3px;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
border-image: initial;
|
border-image: initial;
|
||||||
|
border-color: #414561;
|
||||||
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|
||||||
color: #c2c6dc;
|
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
box-shadow: rgb(115, 103, 240) 0px 0px 0px 1px;
|
box-shadow: rgb(115, 103, 240) 0px 0px 0px 1px;
|
||||||
background: ${mixin.darken('#262c49', 0.15)};
|
background: ${mixin.darken('#262c49', 0.15)};
|
||||||
|
@ -21,13 +21,23 @@ const labelData = [
|
|||||||
{
|
{
|
||||||
labelId: 'development',
|
labelId: 'development',
|
||||||
name: 'Development',
|
name: 'Development',
|
||||||
color: LabelColors.BLUE,
|
labelColor: {
|
||||||
|
id: '1',
|
||||||
|
name: 'white',
|
||||||
|
colorHex: LabelColors.BLUE,
|
||||||
|
position: 1,
|
||||||
|
},
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
labelId: 'general',
|
labelId: 'general',
|
||||||
name: 'General',
|
name: 'General',
|
||||||
color: LabelColors.PINK,
|
labelColor: {
|
||||||
|
id: '1',
|
||||||
|
name: 'white',
|
||||||
|
colorHex: LabelColors.PINK,
|
||||||
|
position: 1,
|
||||||
|
},
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -72,7 +72,7 @@ const QuickCardEditor = ({
|
|||||||
<ListCardLabels>
|
<ListCardLabels>
|
||||||
{labels &&
|
{labels &&
|
||||||
labels.map(label => (
|
labels.map(label => (
|
||||||
<ListCardLabel color={label.color} key={label.name}>
|
<ListCardLabel color={label.labelColor.colorHex} key={label.name}>
|
||||||
{label.name}
|
{label.name}
|
||||||
</ListCardLabel>
|
</ListCardLabel>
|
||||||
))}
|
))}
|
||||||
|
40
web/src/shared/components/TaskAssignee/index.tsx
Normal file
40
web/src/shared/components/TaskAssignee/index.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import React, { useRef } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const TaskDetailAssignee = styled.div`
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
margin-right: 4px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ProfileIcon = styled.div<{ size: string | number }>`
|
||||||
|
width: ${props => props.size}px;
|
||||||
|
height: ${props => props.size}px;
|
||||||
|
border-radius: 9999px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 400;
|
||||||
|
background: rgb(115, 103, 240);
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type TaskAssigneeProps = {
|
||||||
|
size: number | string;
|
||||||
|
member: TaskUser;
|
||||||
|
onMemberProfile: ($targetRef: React.RefObject<HTMLElement>, memberID: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TaskAssignee: React.FC<TaskAssigneeProps> = ({ member, onMemberProfile, size }) => {
|
||||||
|
const $memberRef = useRef<HTMLDivElement>(null);
|
||||||
|
return (
|
||||||
|
<TaskDetailAssignee ref={$memberRef} onClick={() => onMemberProfile($memberRef, member.userID)} key={member.userID}>
|
||||||
|
<ProfileIcon size={size}>{member.profileIcon.initials ?? ''}</ProfileIcon>
|
||||||
|
</TaskDetailAssignee>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TaskAssignee;
|
@ -199,6 +199,7 @@ export const TaskDetailAssignee = styled.div`
|
|||||||
}
|
}
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ProfileIcon = styled.div`
|
export const ProfileIcon = styled.div`
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
@ -33,7 +33,19 @@ export const Default = () => {
|
|||||||
taskGroup: { name: 'General', taskGroupID: '1' },
|
taskGroup: { name: 'General', taskGroupID: '1' },
|
||||||
name: 'Hello, world',
|
name: 'Hello, world',
|
||||||
position: 1,
|
position: 1,
|
||||||
labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }],
|
labels: [
|
||||||
|
{
|
||||||
|
labelId: 'soft-skills',
|
||||||
|
labelColor: {
|
||||||
|
id: '1',
|
||||||
|
name: 'white',
|
||||||
|
colorHex: '#fff',
|
||||||
|
position: 1,
|
||||||
|
},
|
||||||
|
active: true,
|
||||||
|
name: 'Soft Skills',
|
||||||
|
},
|
||||||
|
],
|
||||||
description,
|
description,
|
||||||
members: [
|
members: [
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { Bin, Cross, Plus } from 'shared/icons';
|
import { Bin, Cross, Plus } from 'shared/icons';
|
||||||
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
||||||
|
import TaskAssignee from 'shared/components/TaskAssignee';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
NoDueDateLabel,
|
NoDueDateLabel,
|
||||||
@ -93,19 +94,6 @@ const DetailsEditor: React.FC<DetailsEditorProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
type TaskAssigneeProps = {
|
|
||||||
member: TaskUser;
|
|
||||||
onMemberProfile: ($targetRef: React.RefObject<HTMLElement>, memberID: string) => void;
|
|
||||||
};
|
|
||||||
const TaskAssignee: React.FC<TaskAssigneeProps> = ({ member, onMemberProfile }) => {
|
|
||||||
const $memberRef = useRef<HTMLDivElement>(null);
|
|
||||||
return (
|
|
||||||
<TaskDetailAssignee ref={$memberRef} onClick={() => onMemberProfile($memberRef, member.userID)} key={member.userID}>
|
|
||||||
<ProfileIcon>{member.profileIcon.initials ?? ''}</ProfileIcon>
|
|
||||||
</TaskDetailAssignee>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
type TaskDetailsProps = {
|
type TaskDetailsProps = {
|
||||||
task: Task;
|
task: Task;
|
||||||
onTaskNameChange: (task: Task, newName: string) => void;
|
onTaskNameChange: (task: Task, newName: string) => void;
|
||||||
@ -210,7 +198,9 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{task.members &&
|
{task.members &&
|
||||||
task.members.map(member => <TaskAssignee member={member} onMemberProfile={onMemberProfile} />)}
|
task.members.map(member => (
|
||||||
|
<TaskAssignee size={32} member={member} onMemberProfile={onMemberProfile} />
|
||||||
|
))}
|
||||||
<TaskDetailsAddMember ref={$addMemberRef} onClick={onAddMember}>
|
<TaskDetailsAddMember ref={$addMemberRef} onClick={onAddMember}>
|
||||||
<TaskDetailsAddMemberIcon>
|
<TaskDetailsAddMemberIcon>
|
||||||
<Plus size={16} color="#c2c6dc" />
|
<Plus size={16} color="#c2c6dc" />
|
||||||
|
@ -5,6 +5,11 @@ export const NavbarWrapper = styled.div`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const ProjectMembers = styled.div`
|
||||||
|
display: flex;
|
||||||
|
padding-right: 18px;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
export const NavbarHeader = styled.header`
|
export const NavbarHeader = styled.header`
|
||||||
height: 80px;
|
height: 80px;
|
||||||
padding: 0 1.75rem;
|
padding: 0 1.75rem;
|
||||||
@ -174,3 +179,29 @@ export const ProjectSettingsButton = styled.button`
|
|||||||
background: rgb(115, 103, 240);
|
background: rgb(115, 103, 240);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const InviteButton = styled.button`
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background-color: none;
|
||||||
|
text-align: center;
|
||||||
|
color: #c2c6dc;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
margin: 0 0 0 8px;
|
||||||
|
|
||||||
|
border-radius: 3px;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: transparent;
|
||||||
|
border-image: initial;
|
||||||
|
border-color: #414561;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgb(115, 103, 240);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
@ -3,6 +3,7 @@ import { Star, Bell, Cog, AngleDown } from 'shared/icons';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
NotificationContainer,
|
NotificationContainer,
|
||||||
|
InviteButton,
|
||||||
GlobalActions,
|
GlobalActions,
|
||||||
ProjectActions,
|
ProjectActions,
|
||||||
ProjectSwitcher,
|
ProjectSwitcher,
|
||||||
@ -21,7 +22,11 @@ import {
|
|||||||
ProfileNameWrapper,
|
ProfileNameWrapper,
|
||||||
ProfileNamePrimary,
|
ProfileNamePrimary,
|
||||||
ProfileNameSecondary,
|
ProfileNameSecondary,
|
||||||
|
ProjectMembers,
|
||||||
} from './Styles';
|
} from './Styles';
|
||||||
|
import TaskAssignee from 'shared/components/TaskAssignee';
|
||||||
|
import { usePopup, Popup } from 'shared/components/PopupMenu';
|
||||||
|
import MiniProfile from 'shared/components/MiniProfile';
|
||||||
|
|
||||||
type NavBarProps = {
|
type NavBarProps = {
|
||||||
projectName: string;
|
projectName: string;
|
||||||
@ -31,6 +36,7 @@ type NavBarProps = {
|
|||||||
firstName: string;
|
firstName: string;
|
||||||
lastName: string;
|
lastName: string;
|
||||||
initials: string;
|
initials: string;
|
||||||
|
projectMembers?: Array<TaskUser> | null;
|
||||||
};
|
};
|
||||||
const NavBar: React.FC<NavBarProps> = ({
|
const NavBar: React.FC<NavBarProps> = ({
|
||||||
projectName,
|
projectName,
|
||||||
@ -40,6 +46,7 @@ const NavBar: React.FC<NavBarProps> = ({
|
|||||||
lastName,
|
lastName,
|
||||||
initials,
|
initials,
|
||||||
bgColor,
|
bgColor,
|
||||||
|
projectMembers,
|
||||||
}) => {
|
}) => {
|
||||||
const $profileRef: any = useRef(null);
|
const $profileRef: any = useRef(null);
|
||||||
const handleProfileClick = () => {
|
const handleProfileClick = () => {
|
||||||
@ -47,6 +54,21 @@ const NavBar: React.FC<NavBarProps> = ({
|
|||||||
const boundingRect = $profileRef.current.getBoundingClientRect();
|
const boundingRect = $profileRef.current.getBoundingClientRect();
|
||||||
onProfileClick(boundingRect.bottom, boundingRect.right);
|
onProfileClick(boundingRect.bottom, boundingRect.right);
|
||||||
};
|
};
|
||||||
|
const { showPopup } = usePopup();
|
||||||
|
const onMemberProfile = ($targetRef: React.RefObject<HTMLElement>, memberID: string) => {
|
||||||
|
showPopup(
|
||||||
|
$targetRef,
|
||||||
|
<Popup title={null} onClose={() => {}} tab={0}>
|
||||||
|
<MiniProfile
|
||||||
|
profileIcon={projectMembers ? projectMembers[0].profileIcon : { url: null, initials: 'JK', bgColor: '#000' }}
|
||||||
|
displayName="Jordan Knott"
|
||||||
|
username="@jordanthedev"
|
||||||
|
bio="None"
|
||||||
|
onRemoveFromTask={() => {}}
|
||||||
|
/>
|
||||||
|
</Popup>,
|
||||||
|
);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<NavbarWrapper>
|
<NavbarWrapper>
|
||||||
<NavbarHeader>
|
<NavbarHeader>
|
||||||
@ -58,7 +80,9 @@ const NavBar: React.FC<NavBarProps> = ({
|
|||||||
<ProjectSettingsButton>
|
<ProjectSettingsButton>
|
||||||
<AngleDown color="#c2c6dc" />
|
<AngleDown color="#c2c6dc" />
|
||||||
</ProjectSettingsButton>
|
</ProjectSettingsButton>
|
||||||
<Star filled color="#c2c6dc" />
|
<ProjectSettingsButton>
|
||||||
|
<Star width={16} height={16} color="#c2c6dc" />
|
||||||
|
</ProjectSettingsButton>
|
||||||
</ProjectMeta>
|
</ProjectMeta>
|
||||||
<ProjectTabs>
|
<ProjectTabs>
|
||||||
<ProjectTab active>Board</ProjectTab>
|
<ProjectTab active>Board</ProjectTab>
|
||||||
@ -68,6 +92,14 @@ const NavBar: React.FC<NavBarProps> = ({
|
|||||||
</ProjectTabs>
|
</ProjectTabs>
|
||||||
</ProjectActions>
|
</ProjectActions>
|
||||||
<GlobalActions>
|
<GlobalActions>
|
||||||
|
{projectMembers && (
|
||||||
|
<ProjectMembers>
|
||||||
|
{projectMembers.map(member => (
|
||||||
|
<TaskAssignee size={28} member={member} onMemberProfile={onMemberProfile} />
|
||||||
|
))}
|
||||||
|
<InviteButton>Invite</InviteButton>
|
||||||
|
</ProjectMembers>
|
||||||
|
)}
|
||||||
<NotificationContainer onClick={onNotificationClick}>
|
<NotificationContainer onClick={onNotificationClick}>
|
||||||
<Bell color="#c2c6dc" size={20} />
|
<Bell color="#c2c6dc" size={20} />
|
||||||
</NotificationContainer>
|
</NotificationContainer>
|
||||||
|
@ -19,10 +19,18 @@ export type ProjectLabel = {
|
|||||||
__typename?: 'ProjectLabel';
|
__typename?: 'ProjectLabel';
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
createdDate: Scalars['Time'];
|
createdDate: Scalars['Time'];
|
||||||
colorHex: Scalars['String'];
|
labelColor: LabelColor;
|
||||||
name?: Maybe<Scalars['String']>;
|
name?: Maybe<Scalars['String']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type LabelColor = {
|
||||||
|
__typename?: 'LabelColor';
|
||||||
|
id: Scalars['ID'];
|
||||||
|
name: Scalars['String'];
|
||||||
|
position: Scalars['Float'];
|
||||||
|
colorHex: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
export type TaskLabel = {
|
export type TaskLabel = {
|
||||||
__typename?: 'TaskLabel';
|
__typename?: 'TaskLabel';
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
@ -130,6 +138,7 @@ export type Query = {
|
|||||||
findProject: Project;
|
findProject: Project;
|
||||||
findTask: Task;
|
findTask: Task;
|
||||||
projects: Array<Project>;
|
projects: Array<Project>;
|
||||||
|
labelColors: Array<LabelColor>;
|
||||||
taskGroups: Array<TaskGroup>;
|
taskGroups: Array<TaskGroup>;
|
||||||
me: UserAccount;
|
me: UserAccount;
|
||||||
};
|
};
|
||||||
@ -401,7 +410,11 @@ export type CreateProjectLabelMutation = (
|
|||||||
{ __typename?: 'Mutation' }
|
{ __typename?: 'Mutation' }
|
||||||
& { createProjectLabel: (
|
& { createProjectLabel: (
|
||||||
{ __typename?: 'ProjectLabel' }
|
{ __typename?: 'ProjectLabel' }
|
||||||
& Pick<ProjectLabel, 'id' | 'createdDate' | 'colorHex' | 'name'>
|
& Pick<ProjectLabel, 'id' | 'createdDate' | 'name'>
|
||||||
|
& { labelColor: (
|
||||||
|
{ __typename?: 'LabelColor' }
|
||||||
|
& Pick<LabelColor, 'id' | 'colorHex'>
|
||||||
|
) }
|
||||||
) }
|
) }
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -499,7 +512,11 @@ export type FindProjectQuery = (
|
|||||||
) }
|
) }
|
||||||
)>, labels: Array<(
|
)>, labels: Array<(
|
||||||
{ __typename?: 'ProjectLabel' }
|
{ __typename?: 'ProjectLabel' }
|
||||||
& Pick<ProjectLabel, 'id' | 'createdDate' | 'colorHex' | 'name'>
|
& Pick<ProjectLabel, 'id' | 'createdDate' | 'name'>
|
||||||
|
& { labelColor: (
|
||||||
|
{ __typename?: 'LabelColor' }
|
||||||
|
& Pick<LabelColor, 'id' | 'name' | 'colorHex' | 'position'>
|
||||||
|
) }
|
||||||
)>, taskGroups: Array<(
|
)>, taskGroups: Array<(
|
||||||
{ __typename?: 'TaskGroup' }
|
{ __typename?: 'TaskGroup' }
|
||||||
& Pick<TaskGroup, 'id' | 'name' | 'position'>
|
& Pick<TaskGroup, 'id' | 'name' | 'position'>
|
||||||
@ -516,7 +533,10 @@ export type FindProjectQuery = (
|
|||||||
)> }
|
)> }
|
||||||
)> }
|
)> }
|
||||||
)> }
|
)> }
|
||||||
) }
|
), labelColors: Array<(
|
||||||
|
{ __typename?: 'LabelColor' }
|
||||||
|
& Pick<LabelColor, 'id' | 'position' | 'colorHex' | 'name'>
|
||||||
|
)> }
|
||||||
);
|
);
|
||||||
|
|
||||||
export type FindTaskQueryVariables = {
|
export type FindTaskQueryVariables = {
|
||||||
@ -692,7 +712,10 @@ export const CreateProjectLabelDocument = gql`
|
|||||||
createProjectLabel(input: {projectID: $projectID, labelColorID: $labelColorID, name: $name}) {
|
createProjectLabel(input: {projectID: $projectID, labelColorID: $labelColorID, name: $name}) {
|
||||||
id
|
id
|
||||||
createdDate
|
createdDate
|
||||||
colorHex
|
labelColor {
|
||||||
|
id
|
||||||
|
colorHex
|
||||||
|
}
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -899,7 +922,12 @@ export const FindProjectDocument = gql`
|
|||||||
labels {
|
labels {
|
||||||
id
|
id
|
||||||
createdDate
|
createdDate
|
||||||
colorHex
|
labelColor {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
colorHex
|
||||||
|
position
|
||||||
|
}
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
taskGroups {
|
taskGroups {
|
||||||
@ -924,6 +952,12 @@ export const FindProjectDocument = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
labelColors {
|
||||||
|
id
|
||||||
|
position
|
||||||
|
colorHex
|
||||||
|
name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -2,7 +2,10 @@ mutation createProjectLabel($projectID: UUID!, $labelColorID: UUID!, $name: Stri
|
|||||||
createProjectLabel(input:{projectID:$projectID, labelColorID: $labelColorID, name: $name}) {
|
createProjectLabel(input:{projectID:$projectID, labelColorID: $labelColorID, name: $name}) {
|
||||||
id
|
id
|
||||||
createdDate
|
createdDate
|
||||||
colorHex
|
labelColor {
|
||||||
|
id
|
||||||
|
colorHex
|
||||||
|
}
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,12 @@ query findProject($projectId: String!) {
|
|||||||
labels {
|
labels {
|
||||||
id
|
id
|
||||||
createdDate
|
createdDate
|
||||||
colorHex
|
labelColor {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
colorHex
|
||||||
|
position
|
||||||
|
}
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
taskGroups {
|
taskGroups {
|
||||||
@ -39,4 +44,10 @@ query findProject($projectId: String!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
labelColors {
|
||||||
|
id
|
||||||
|
position
|
||||||
|
colorHex
|
||||||
|
name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user