feature: remove sidebar & redesign top navbar
This commit is contained in:
parent
fd7c006b73
commit
57382de9d0
27
.tmuxinator.yml
Normal file
27
.tmuxinator.yml
Normal file
@ -0,0 +1,27 @@
|
||||
name: citadel
|
||||
root: .
|
||||
|
||||
on_project_start: docker start test-db
|
||||
|
||||
windows:
|
||||
- services:
|
||||
root: ./
|
||||
panes:
|
||||
- api:
|
||||
- cd api
|
||||
- go run cmd/citadel/main.go
|
||||
- yarn:
|
||||
- cd web
|
||||
- yarn start
|
||||
- web/editor:
|
||||
root: ./web
|
||||
panes:
|
||||
- vim src/index.tsx
|
||||
- api/editor:
|
||||
root: ./api
|
||||
panes:
|
||||
- vim cmd/citadel/main.go
|
||||
- database:
|
||||
root: ./api
|
||||
panes:
|
||||
- docker container exec -it test-db psql -U postgres citadel
|
@ -1,10 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
"fmt"
|
||||
_ "github.com/lib/pq"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/jordanknott/project-citadel/api/router"
|
||||
@ -20,6 +20,10 @@ func main() {
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
db.SetMaxOpenConns(25)
|
||||
db.SetMaxIdleConns(25)
|
||||
db.SetConnMaxLifetime(5 * time.Minute)
|
||||
|
||||
defer db.Close()
|
||||
fmt.Println("starting graphql server on http://localhost:3333")
|
||||
fmt.Println("starting graphql playground on http://localhost:3333/__graphql")
|
||||
|
@ -1,16 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
// "context"
|
||||
// "fmt"
|
||||
// "io/ioutil"
|
||||
|
||||
"github.com/jordan-wright/email"
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/jordanknott/project-citadel/api/pg"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"net/smtp"
|
||||
// "github.com/jmoiron/sqlx"
|
||||
// "github.com/jordanknott/project-citadel/api/pg"
|
||||
// "github.com/BurntSushi/toml"
|
||||
// "github.com/jordanknott/project-citadel/api/router"
|
||||
// "time"
|
||||
)
|
||||
@ -26,6 +26,14 @@ type colors struct {
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
e := email.NewEmail()
|
||||
e.From = "Jordan Knott <no-reply@citadel.com>"
|
||||
e.To = []string{"jordan@jordanthedev.com"}
|
||||
e.Subject = "Jordan Knott (@jordanthedev) invited you to join the team \"Paradox\" on Citadel"
|
||||
e.Text = []byte("Text Body is, of course, supported!")
|
||||
e.HTML = []byte("<h1>Fancy HTML is supported, too!</h1>")
|
||||
e.Send("localhost:1025", smtp.PlainAuth("", "test@gmail.com", "password123", "localhost"))
|
||||
// dur := time.Hour * 24 * 7 * 30
|
||||
// token, err := router.NewAccessTokenCustomExpiration("21345076-6423-4a00-a6bd-cd9f830e2764", dur)
|
||||
// if err != nil {
|
||||
@ -33,23 +41,23 @@ func main() {
|
||||
// }
|
||||
// fmt.Println(token)
|
||||
|
||||
fmt.Println("seeding database...")
|
||||
// fmt.Println("seeding database...")
|
||||
|
||||
dat, err := ioutil.ReadFile("data/colors.toml")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// dat, err := ioutil.ReadFile("data/colors.toml")
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
|
||||
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)})
|
||||
}
|
||||
// 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)})
|
||||
// }
|
||||
|
||||
}
|
||||
|
8
api/docker-compose.yml
Normal file
8
api/docker-compose.yml
Normal file
@ -0,0 +1,8 @@
|
||||
version: "3"
|
||||
services:
|
||||
mailhog:
|
||||
image: mailhog/mailhog:latest
|
||||
restart: always
|
||||
ports:
|
||||
- 1025:1025
|
||||
- 8025:8025
|
@ -5,17 +5,25 @@ go 1.13
|
||||
require (
|
||||
github.com/99designs/gqlgen v0.11.3
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/boyter/scc v2.12.0+incompatible // indirect
|
||||
github.com/dbaggerman/cuba v0.3.2 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/go-chi/chi v3.3.2+incompatible
|
||||
github.com/go-chi/cors v1.0.0
|
||||
github.com/google/martian v2.1.0+incompatible
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/jmoiron/sqlx v1.2.0
|
||||
github.com/jordan-wright/email v0.0.0-20200602115436-fd8a7622303e
|
||||
github.com/lib/pq v1.0.0
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200525100937-58356a36e03f // indirect
|
||||
github.com/pelletier/go-toml v1.8.0
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/spf13/cobra v1.0.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/urfave/cli v1.20.0 // indirect
|
||||
github.com/vektah/gqlparser/v2 v2.0.1
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
|
||||
golang.org/x/text v0.3.3 // indirect
|
||||
)
|
||||
|
129
api/go.sum
129
api/go.sum
@ -1,29 +1,64 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/99designs/gqlgen v0.11.1 h1:QoSL8/AAJ2T3UOeQbdnBR32JcG4pO08+P/g5jdbFkUg=
|
||||
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/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/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
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/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/boyter/scc v2.12.0+incompatible h1:Sxhi1Ry3gdreoaF0xEITQSdjR+pJT0cXHXhlDw5FHT0=
|
||||
github.com/boyter/scc v2.12.0+incompatible/go.mod h1:VB5w4e0dahmIiKnpZ7LRh/sjauoY0BmCWjIzZcShNY0=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dbaggerman/cuba v0.3.2 h1:6ZbQX3FNvkocR222YyoAIZ8wi4avrb7JcJkPvVI2AS4=
|
||||
github.com/dbaggerman/cuba v0.3.2/go.mod h1:t9Oo05XRZGcjaVqsA/gFeNAOm7DYZYNhI17unI5FlwY=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-chi/chi v3.3.2+incompatible h1:uQNcQN3NsV1j4ANsPh42P4ew4t6rnRbJb8frvpp31qQ=
|
||||
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-chi/cors v1.0.0 h1:e6x8k7uWbUwYs+aXDoiUzeQFT6l0cygBYyNhD7/1Tg0=
|
||||
github.com/go-chi/cors v1.0.0/go.mod h1:K2Yje0VW/SJzxiyMYu6iPQYa7hMjQX2i/F491VChg1I=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
@ -32,12 +67,28 @@ github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB
|
||||
github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ=
|
||||
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jordan-wright/email v0.0.0-20200602115436-fd8a7622303e h1:OGunVjqY7y4U4laftpEHv+mvZBlr7UGimJXKEGQtg48=
|
||||
github.com/jordan-wright/email v0.0.0-20200602115436-fd8a7622303e/go.mod h1:Fy2gCFfZhay8jplf/Csj6cyH/oshQTkLQYZbKkcV+SY=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
@ -46,6 +97,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007 h1:reVOUXwnhsYv/8UqjvhrMOu5CNT9UapHFLbQ2JcXsmg=
|
||||
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
@ -53,16 +105,39 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047 h1:zCoDWFD5nrJJVjbXiDZcVhOBSzKn3o9LgRLLMRNuru8=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200525100937-58356a36e03f h1:0HN0GKijN4mr9SmYoW/Ni3ozuNeHiSxo2s7drhv7obY=
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200525100937-58356a36e03f/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
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/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
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.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/profile v1.3.0/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
@ -71,14 +146,30 @@ github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJ
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
|
||||
@ -87,15 +178,36 @@ github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWp
|
||||
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
|
||||
github.com/vektah/gqlparser/v2 v2.0.1 h1:xgl5abVnsd4hkN9rk65OJID9bfcLSMuTaTcZj777q1o=
|
||||
github.com/vektah/gqlparser/v2 v2.0.1/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -104,18 +216,35 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtD
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589 h1:rjUrONFu4kLchcZTfp3/96bR8bW8dIa8uz3cR5n0cgM=
|
||||
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/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/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=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
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=
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -59,6 +59,10 @@ type DeleteProjectPayload struct {
|
||||
Project *pg.Project `json:"project"`
|
||||
}
|
||||
|
||||
type DeleteTaskChecklist struct {
|
||||
TaskChecklistID uuid.UUID `json:"taskChecklistID"`
|
||||
}
|
||||
|
||||
type DeleteTaskChecklistItem struct {
|
||||
TaskChecklistItemID uuid.UUID `json:"taskChecklistItemID"`
|
||||
}
|
||||
@ -68,6 +72,11 @@ type DeleteTaskChecklistItemPayload struct {
|
||||
TaskChecklistItem *pg.TaskChecklistItem `json:"taskChecklistItem"`
|
||||
}
|
||||
|
||||
type DeleteTaskChecklistPayload struct {
|
||||
Ok bool `json:"ok"`
|
||||
TaskChecklist *pg.TaskChecklist `json:"taskChecklist"`
|
||||
}
|
||||
|
||||
type DeleteTaskGroupInput struct {
|
||||
TaskGroupID uuid.UUID `json:"taskGroupID"`
|
||||
}
|
||||
@ -86,6 +95,25 @@ type DeleteTaskPayload struct {
|
||||
TaskID string `json:"taskID"`
|
||||
}
|
||||
|
||||
type DeleteTeam struct {
|
||||
TeamID uuid.UUID `json:"teamID"`
|
||||
}
|
||||
|
||||
type DeleteTeamPayload struct {
|
||||
Ok bool `json:"ok"`
|
||||
Team *pg.Team `json:"team"`
|
||||
Projects []pg.Project `json:"projects"`
|
||||
}
|
||||
|
||||
type DeleteUserAccount struct {
|
||||
UserID uuid.UUID `json:"userID"`
|
||||
}
|
||||
|
||||
type DeleteUserAccountPayload struct {
|
||||
Ok bool `json:"ok"`
|
||||
UserAccount *pg.UserAccount `json:"userAccount"`
|
||||
}
|
||||
|
||||
type FindProject struct {
|
||||
ProjectID string `json:"projectId"`
|
||||
}
|
||||
@ -94,6 +122,10 @@ type FindTask struct {
|
||||
TaskID uuid.UUID `json:"taskID"`
|
||||
}
|
||||
|
||||
type FindTeam struct {
|
||||
TeamID uuid.UUID `json:"teamID"`
|
||||
}
|
||||
|
||||
type FindUser struct {
|
||||
UserID string `json:"userId"`
|
||||
}
|
||||
@ -167,7 +199,7 @@ type ProjectMember struct {
|
||||
}
|
||||
|
||||
type ProjectsFilter struct {
|
||||
TeamID *string `json:"teamID"`
|
||||
TeamID *uuid.UUID `json:"teamID"`
|
||||
}
|
||||
|
||||
type RemoveTaskLabelInput struct {
|
||||
@ -229,6 +261,11 @@ type UpdateTaskChecklistItemName struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type UpdateTaskChecklistName struct {
|
||||
TaskChecklistID uuid.UUID `json:"taskChecklistID"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type UpdateTaskDescriptionInput struct {
|
||||
TaskID uuid.UUID `json:"taskID"`
|
||||
Description string `json:"description"`
|
||||
|
@ -103,7 +103,7 @@ type Task {
|
||||
}
|
||||
|
||||
input ProjectsFilter {
|
||||
teamID: String
|
||||
teamID: UUID
|
||||
}
|
||||
|
||||
input FindUser {
|
||||
@ -123,6 +123,10 @@ type Organization {
|
||||
name: String!
|
||||
}
|
||||
|
||||
input FindTeam {
|
||||
teamID: UUID!
|
||||
}
|
||||
|
||||
type Query {
|
||||
organizations: [Organization!]!
|
||||
users: [UserAccount!]!
|
||||
@ -130,6 +134,7 @@ type Query {
|
||||
findProject(input: FindProject!): Project!
|
||||
findTask(input: FindTask!): Task!
|
||||
projects(input: ProjectsFilter): [Project!]!
|
||||
findTeam(input: FindTeam!): Team!
|
||||
teams: [Team!]!
|
||||
labelColors: [LabelColor!]!
|
||||
taskGroups: [TaskGroup!]!
|
||||
@ -356,11 +361,43 @@ type DeleteProjectPayload {
|
||||
project: Project!
|
||||
}
|
||||
|
||||
input DeleteTeam {
|
||||
teamID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTeamPayload {
|
||||
ok: Boolean!
|
||||
team: Team!
|
||||
projects: [Project!]!
|
||||
}
|
||||
|
||||
input DeleteUserAccount {
|
||||
userID: UUID!
|
||||
}
|
||||
|
||||
type DeleteUserAccountPayload {
|
||||
ok: Boolean!
|
||||
userAccount: UserAccount!
|
||||
}
|
||||
|
||||
input UpdateTaskChecklistName {
|
||||
taskChecklistID: UUID!
|
||||
name: String!
|
||||
}
|
||||
input DeleteTaskChecklist {
|
||||
taskChecklistID: UUID!
|
||||
}
|
||||
type DeleteTaskChecklistPayload {
|
||||
ok: Boolean!
|
||||
taskChecklist: TaskChecklist!
|
||||
}
|
||||
type Mutation {
|
||||
createRefreshToken(input: NewRefreshToken!): RefreshToken!
|
||||
|
||||
createUserAccount(input: NewUserAccount!): UserAccount!
|
||||
deleteUserAccount(input: DeleteUserAccount!): DeleteUserAccountPayload!
|
||||
|
||||
deleteTeam(input: DeleteTeam!): DeleteTeamPayload!
|
||||
createTeam(input: NewTeam!): Team!
|
||||
clearProfileAvatar: UserAccount!
|
||||
|
||||
@ -386,6 +423,8 @@ type Mutation {
|
||||
toggleTaskLabel(input: ToggleTaskLabelInput!): ToggleTaskLabelPayload!
|
||||
|
||||
createTaskChecklist(input: CreateTaskChecklist!): TaskChecklist!
|
||||
deleteTaskChecklist(input: DeleteTaskChecklist!): DeleteTaskChecklistPayload!
|
||||
updateTaskChecklistName(input: UpdateTaskChecklistName!): TaskChecklist!
|
||||
createTaskChecklistItem(input: CreateTaskChecklistItem!): TaskChecklistItem!
|
||||
updateTaskChecklistItemName(input: UpdateTaskChecklistItemName!): TaskChecklistItem!
|
||||
setTaskChecklistItemComplete(input: SetTaskChecklistItemComplete!): TaskChecklistItem!
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/jordanknott/project-citadel/api/pg"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func (r *labelColorResolver) ID(ctx context.Context, obj *pg.LabelColor) (uuid.UUID, error) {
|
||||
@ -29,17 +30,54 @@ func (r *mutationResolver) CreateRefreshToken(ctx context.Context, input NewRefr
|
||||
|
||||
func (r *mutationResolver) CreateUserAccount(ctx context.Context, input NewUserAccount) (*pg.UserAccount, error) {
|
||||
createdAt := time.Now().UTC()
|
||||
hashedPwd, err := bcrypt.GenerateFromPassword([]byte(input.Password), 14)
|
||||
if err != nil {
|
||||
return &pg.UserAccount{}, err
|
||||
}
|
||||
userAccount, err := r.Repository.CreateUserAccount(ctx, pg.CreateUserAccountParams{
|
||||
FullName: input.FullName,
|
||||
Initials: input.Initials,
|
||||
Email: input.Email,
|
||||
Username: input.Username,
|
||||
CreatedAt: createdAt,
|
||||
PasswordHash: input.Password,
|
||||
PasswordHash: string(hashedPwd),
|
||||
})
|
||||
return &userAccount, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteUserAccount(ctx context.Context, input DeleteUserAccount) (*DeleteUserAccountPayload, error) {
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, input.UserID)
|
||||
if err != nil {
|
||||
return &DeleteUserAccountPayload{Ok: false}, err
|
||||
}
|
||||
|
||||
err = r.Repository.DeleteUserAccountByID(ctx, input.UserID)
|
||||
if err != nil {
|
||||
return &DeleteUserAccountPayload{Ok: false}, err
|
||||
}
|
||||
return &DeleteUserAccountPayload{UserAccount: &user, Ok: true}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteTeam(ctx context.Context, input DeleteTeam) (*DeleteTeamPayload, error) {
|
||||
team, err := r.Repository.GetTeamByID(ctx, input.TeamID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return &DeleteTeamPayload{Ok: false}, err
|
||||
}
|
||||
projects, err := r.Repository.GetAllProjectsForTeam(ctx, input.TeamID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return &DeleteTeamPayload{Ok: false}, err
|
||||
}
|
||||
err = r.Repository.DeleteTeamByID(ctx, input.TeamID)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return &DeleteTeamPayload{Ok: false}, err
|
||||
}
|
||||
|
||||
return &DeleteTeamPayload{Ok: true, Team: &team, Projects: projects}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) CreateTeam(ctx context.Context, input NewTeam) (*pg.Team, error) {
|
||||
createdAt := time.Now().UTC()
|
||||
team, err := r.Repository.CreateTeam(ctx, pg.CreateTeamParams{input.OrganizationID, createdAt, input.Name})
|
||||
@ -277,6 +315,26 @@ func (r *mutationResolver) CreateTaskChecklist(ctx context.Context, input Create
|
||||
return &taskChecklist, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteTaskChecklist(ctx context.Context, input DeleteTaskChecklist) (*DeleteTaskChecklistPayload, error) {
|
||||
taskChecklist, err := r.Repository.GetTaskChecklistByID(ctx, input.TaskChecklistID)
|
||||
if err != nil {
|
||||
return &DeleteTaskChecklistPayload{Ok: false}, err
|
||||
}
|
||||
err = r.Repository.DeleteTaskChecklistByID(ctx, input.TaskChecklistID)
|
||||
if err != nil {
|
||||
return &DeleteTaskChecklistPayload{Ok: false}, err
|
||||
}
|
||||
return &DeleteTaskChecklistPayload{Ok: true, TaskChecklist: &taskChecklist}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateTaskChecklistName(ctx context.Context, input UpdateTaskChecklistName) (*pg.TaskChecklist, error) {
|
||||
checklist, err := r.Repository.UpdateTaskChecklistName(ctx, pg.UpdateTaskChecklistNameParams{TaskChecklistID: input.TaskChecklistID, Name: input.Name})
|
||||
if err != nil {
|
||||
return &pg.TaskChecklist{}, err
|
||||
}
|
||||
return &checklist, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) CreateTaskChecklistItem(ctx context.Context, input CreateTaskChecklistItem) (*pg.TaskChecklistItem, error) {
|
||||
createdAt := time.Now().UTC()
|
||||
taskChecklistItem, err := r.Repository.CreateTaskChecklistItem(ctx, pg.CreateTaskChecklistItemParams{
|
||||
@ -475,6 +533,9 @@ func (r *projectResolver) TaskGroups(ctx context.Context, obj *pg.Project) ([]pg
|
||||
func (r *projectResolver) Members(ctx context.Context, obj *pg.Project) ([]ProjectMember, error) {
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, obj.Owner)
|
||||
members := []ProjectMember{}
|
||||
if err == sql.ErrNoRows {
|
||||
return members, nil
|
||||
}
|
||||
if err != nil {
|
||||
return members, err
|
||||
}
|
||||
@ -561,15 +622,19 @@ func (r *queryResolver) FindTask(ctx context.Context, input FindTask) (*pg.Task,
|
||||
|
||||
func (r *queryResolver) Projects(ctx context.Context, input *ProjectsFilter) ([]pg.Project, error) {
|
||||
if input != nil {
|
||||
teamID, err := uuid.Parse(*input.TeamID)
|
||||
if err != nil {
|
||||
return []pg.Project{}, err
|
||||
}
|
||||
return r.Repository.GetAllProjectsForTeam(ctx, teamID)
|
||||
return r.Repository.GetAllProjectsForTeam(ctx, *input.TeamID)
|
||||
}
|
||||
return r.Repository.GetAllProjects(ctx)
|
||||
}
|
||||
|
||||
func (r *queryResolver) FindTeam(ctx context.Context, input FindTeam) (*pg.Team, error) {
|
||||
team, err := r.Repository.GetTeamByID(ctx, input.TeamID)
|
||||
if err != nil {
|
||||
return &pg.Team{}, err
|
||||
}
|
||||
return &team, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Teams(ctx context.Context) ([]pg.Team, error) {
|
||||
return r.Repository.GetAllTeams(ctx)
|
||||
}
|
||||
@ -727,6 +792,9 @@ func (r *teamResolver) ID(ctx context.Context, obj *pg.Team) (uuid.UUID, error)
|
||||
func (r *teamResolver) Members(ctx context.Context, obj *pg.Team) ([]ProjectMember, error) {
|
||||
teamMembers, err := r.Repository.GetTeamMembersForTeamID(ctx, obj.TeamID)
|
||||
var projectMembers []ProjectMember
|
||||
if err == sql.ErrNoRows {
|
||||
return projectMembers, nil
|
||||
}
|
||||
if err != nil {
|
||||
return projectMembers, err
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
ALTER TABLE project DROP CONSTRAINT project_team_id_fkey;
|
||||
ALTER TABLE project
|
||||
ADD CONSTRAINT project_team_id_fkey
|
||||
FOREIGN KEY (team_id)
|
||||
REFERENCES team(team_id)
|
||||
ON DELETE CASCADE;
|
@ -0,0 +1,6 @@
|
||||
ALTER TABLE task_assigned DROP CONSTRAINT task_assigned_user_id_fkey;
|
||||
ALTER TABLE task_assigned
|
||||
ADD CONSTRAINT task_assigned_user_id_fkey
|
||||
FOREIGN KEY (user_id)
|
||||
REFERENCES user_account(user_id)
|
||||
ON DELETE CASCADE;
|
@ -0,0 +1,5 @@
|
||||
ALTER TABLE refresh_token
|
||||
ADD CONSTRAINT refresh_token_user_id_fkey
|
||||
FOREIGN KEY (user_id)
|
||||
REFERENCES user_account(user_id)
|
||||
ON DELETE CASCADE;
|
@ -17,7 +17,11 @@ type Repository interface {
|
||||
GetAllTeams(ctx context.Context) ([]Team, error)
|
||||
|
||||
DeleteProjectByID(ctx context.Context, projectID uuid.UUID) error
|
||||
DeleteUserAccountByID(ctx context.Context, userID uuid.UUID) error
|
||||
|
||||
GetTaskChecklistByID(ctx context.Context, taskChecklistID uuid.UUID) (TaskChecklist, error)
|
||||
DeleteTaskChecklistByID(ctx context.Context, taskChecklistID uuid.UUID) error
|
||||
UpdateTaskChecklistName(ctx context.Context, arg UpdateTaskChecklistNameParams) (TaskChecklist, error)
|
||||
CreateProject(ctx context.Context, arg CreateProjectParams) (Project, error)
|
||||
GetAllProjects(ctx context.Context) ([]Project, error)
|
||||
GetAllProjectsForTeam(ctx context.Context, teamID uuid.UUID) ([]Project, error)
|
||||
|
@ -30,6 +30,7 @@ type Querier interface {
|
||||
DeleteRefreshTokenByUserID(ctx context.Context, userID uuid.UUID) error
|
||||
DeleteTaskAssignedByID(ctx context.Context, arg DeleteTaskAssignedByIDParams) (TaskAssigned, error)
|
||||
DeleteTaskByID(ctx context.Context, taskID uuid.UUID) error
|
||||
DeleteTaskChecklistByID(ctx context.Context, taskChecklistID uuid.UUID) error
|
||||
DeleteTaskChecklistItem(ctx context.Context, taskChecklistItemID uuid.UUID) error
|
||||
DeleteTaskGroupByID(ctx context.Context, taskGroupID uuid.UUID) (int64, error)
|
||||
DeleteTaskLabelByID(ctx context.Context, taskLabelID uuid.UUID) error
|
||||
@ -37,6 +38,7 @@ type Querier interface {
|
||||
DeleteTasksByTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) (int64, error)
|
||||
DeleteTeamByID(ctx context.Context, teamID uuid.UUID) error
|
||||
DeleteTeamMemberByUserID(ctx context.Context, userID uuid.UUID) error
|
||||
DeleteUserAccountByID(ctx context.Context, userID uuid.UUID) error
|
||||
GetAllOrganizations(ctx context.Context) ([]Organization, error)
|
||||
GetAllProjects(ctx context.Context) ([]Project, error)
|
||||
GetAllProjectsForTeam(ctx context.Context, teamID uuid.UUID) ([]Project, error)
|
||||
@ -52,6 +54,7 @@ type Querier interface {
|
||||
GetProjectLabelsForProject(ctx context.Context, projectID uuid.UUID) ([]ProjectLabel, error)
|
||||
GetRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) (RefreshToken, error)
|
||||
GetTaskByID(ctx context.Context, taskID uuid.UUID) (Task, error)
|
||||
GetTaskChecklistByID(ctx context.Context, taskChecklistID uuid.UUID) (TaskChecklist, error)
|
||||
GetTaskChecklistItemByID(ctx context.Context, taskChecklistItemID uuid.UUID) (TaskChecklistItem, error)
|
||||
GetTaskChecklistItemsForTaskChecklist(ctx context.Context, taskChecklistID uuid.UUID) ([]TaskChecklistItem, error)
|
||||
GetTaskChecklistsForTask(ctx context.Context, taskID uuid.UUID) ([]TaskChecklist, error)
|
||||
@ -74,6 +77,7 @@ type Querier interface {
|
||||
UpdateProjectLabelName(ctx context.Context, arg UpdateProjectLabelNameParams) (ProjectLabel, error)
|
||||
UpdateProjectNameByID(ctx context.Context, arg UpdateProjectNameByIDParams) (Project, error)
|
||||
UpdateTaskChecklistItemName(ctx context.Context, arg UpdateTaskChecklistItemNameParams) (TaskChecklistItem, error)
|
||||
UpdateTaskChecklistName(ctx context.Context, arg UpdateTaskChecklistNameParams) (TaskChecklist, error)
|
||||
UpdateTaskDescription(ctx context.Context, arg UpdateTaskDescriptionParams) (Task, error)
|
||||
UpdateTaskDueDate(ctx context.Context, arg UpdateTaskDueDateParams) (Task, error)
|
||||
UpdateTaskGroupLocation(ctx context.Context, arg UpdateTaskGroupLocationParams) (TaskGroup, error)
|
||||
|
@ -72,6 +72,15 @@ func (q *Queries) CreateTaskChecklistItem(ctx context.Context, arg CreateTaskChe
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteTaskChecklistByID = `-- name: DeleteTaskChecklistByID :exec
|
||||
DELETE FROM task_checklist WHERE task_checklist_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteTaskChecklistByID(ctx context.Context, taskChecklistID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteTaskChecklistByID, taskChecklistID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteTaskChecklistItem = `-- name: DeleteTaskChecklistItem :exec
|
||||
DELETE FROM task_checklist_item WHERE task_checklist_item_id = $1
|
||||
`
|
||||
@ -81,6 +90,23 @@ func (q *Queries) DeleteTaskChecklistItem(ctx context.Context, taskChecklistItem
|
||||
return err
|
||||
}
|
||||
|
||||
const getTaskChecklistByID = `-- name: GetTaskChecklistByID :one
|
||||
SELECT task_checklist_id, task_id, created_at, name, position FROM task_checklist WHERE task_checklist_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTaskChecklistByID(ctx context.Context, taskChecklistID uuid.UUID) (TaskChecklist, error) {
|
||||
row := q.db.QueryRowContext(ctx, getTaskChecklistByID, taskChecklistID)
|
||||
var i TaskChecklist
|
||||
err := row.Scan(
|
||||
&i.TaskChecklistID,
|
||||
&i.TaskID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTaskChecklistItemByID = `-- name: GetTaskChecklistItemByID :one
|
||||
SELECT task_checklist_item_id, task_checklist_id, created_at, complete, name, position, due_date FROM task_checklist_item WHERE task_checklist_item_id = $1
|
||||
`
|
||||
@ -217,3 +243,26 @@ func (q *Queries) UpdateTaskChecklistItemName(ctx context.Context, arg UpdateTas
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateTaskChecklistName = `-- name: UpdateTaskChecklistName :one
|
||||
UPDATE task_checklist SET name = $2 WHERE task_checklist_id = $1
|
||||
RETURNING task_checklist_id, task_id, created_at, name, position
|
||||
`
|
||||
|
||||
type UpdateTaskChecklistNameParams struct {
|
||||
TaskChecklistID uuid.UUID `json:"task_checklist_id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateTaskChecklistName(ctx context.Context, arg UpdateTaskChecklistNameParams) (TaskChecklist, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateTaskChecklistName, arg.TaskChecklistID, arg.Name)
|
||||
var i TaskChecklist
|
||||
err := row.Scan(
|
||||
&i.TaskChecklistID,
|
||||
&i.TaskID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
@ -49,6 +49,15 @@ func (q *Queries) CreateUserAccount(ctx context.Context, arg CreateUserAccountPa
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteUserAccountByID = `-- name: DeleteUserAccountByID :exec
|
||||
DELETE FROM user_account WHERE user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteUserAccountByID(ctx context.Context, userID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteUserAccountByID, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
const getAllUserAccounts = `-- name: GetAllUserAccounts :many
|
||||
SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url FROM user_account
|
||||
`
|
||||
|
@ -5,6 +5,16 @@ INSERT INTO task_checklist (task_id, created_at, name, position) VALUES ($1, $2,
|
||||
-- name: GetTaskChecklistsForTask :many
|
||||
SELECT * FROM task_checklist WHERE task_id = $1;
|
||||
|
||||
-- name: UpdateTaskChecklistName :one
|
||||
UPDATE task_checklist SET name = $2 WHERE task_checklist_id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteTaskChecklistByID :exec
|
||||
DELETE FROM task_checklist WHERE task_checklist_id = $1;
|
||||
|
||||
-- name: GetTaskChecklistByID :one
|
||||
SELECT * FROM task_checklist WHERE task_checklist_id = $1;
|
||||
|
||||
-- name: CreateTaskChecklistItem :one
|
||||
INSERT INTO task_checklist_item (task_checklist_id, created_at, name, position, complete, due_date) VALUES ($1, $2, $3, $4, false, null)
|
||||
RETURNING *;
|
||||
|
@ -14,3 +14,6 @@ INSERT INTO user_account(full_name, initials, email, username, created_at, passw
|
||||
-- name: UpdateUserAccountProfileAvatarURL :one
|
||||
UPDATE user_account SET profile_avatar_url = $2 WHERE user_id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteUserAccountByID :exec
|
||||
DELETE FROM user_account WHERE user_id = $1;
|
||||
|
@ -3,6 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.0.0-rc.8",
|
||||
"@apollo/react-common": "^3.1.4",
|
||||
"@apollo/react-hooks": "^3.1.3",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.27",
|
||||
|
471
web/report.20200621.183857.68808.0.001.json
Normal file
471
web/report.20200621.183857.68808.0.001.json
Normal file
@ -0,0 +1,471 @@
|
||||
|
||||
{
|
||||
"header": {
|
||||
"reportVersion": 1,
|
||||
"event": "Allocation failed - JavaScript heap out of memory",
|
||||
"trigger": "FatalError",
|
||||
"filename": "report.20200621.183857.68808.0.001.json",
|
||||
"dumpEventTime": "2020-06-21T18:38:57Z",
|
||||
"dumpEventTimeStamp": "1592782737343",
|
||||
"processId": 68808,
|
||||
"cwd": "/home/jordan/Projects/project-citadel/web",
|
||||
"commandLine": [
|
||||
"/usr/bin/node",
|
||||
"/home/jordan/.config/coc/extensions/node_modules/coc-tsserver/bin/tsserverForkStart",
|
||||
"/home/jordan/Projects/project-citadel/web/node_modules/typescript/lib/tsserver.js",
|
||||
"--allowLocalPluginLoads",
|
||||
"--useInferredProjectPerProjectRoot",
|
||||
"--cancellationPipeName",
|
||||
"/tmp/coc-nvim-tscancellation-49e6b7aafa04f6c486f4.sock*",
|
||||
"--npmLocation",
|
||||
"\"/usr/bin/npm\"",
|
||||
"--noGetErrOnBackgroundUpdate",
|
||||
"--validateDefaultNpmLocation"
|
||||
],
|
||||
"nodejsVersion": "v13.8.0",
|
||||
"glibcVersionRuntime": "2.30",
|
||||
"glibcVersionCompiler": "2.30",
|
||||
"wordSize": 64,
|
||||
"arch": "x64",
|
||||
"platform": "linux",
|
||||
"componentVersions": {
|
||||
"node": "13.8.0",
|
||||
"v8": "7.9.317.25-node.28",
|
||||
"uv": "1.34.1",
|
||||
"zlib": "1.2.11",
|
||||
"brotli": "1.0.7",
|
||||
"ares": "1.15.0",
|
||||
"modules": "79",
|
||||
"nghttp2": "1.39.2",
|
||||
"napi": "5",
|
||||
"llhttp": "2.0.4",
|
||||
"openssl": "1.1.1d",
|
||||
"cldr": "36.0",
|
||||
"icu": "65.1",
|
||||
"tz": "2019c",
|
||||
"unicode": "12.1"
|
||||
},
|
||||
"release": {
|
||||
"name": "node",
|
||||
"headersUrl": "https://nodejs.org/download/release/v13.8.0/node-v13.8.0-headers.tar.gz",
|
||||
"sourceUrl": "https://nodejs.org/download/release/v13.8.0/node-v13.8.0.tar.gz"
|
||||
},
|
||||
"osName": "Linux",
|
||||
"osRelease": "4.19.101-1-lts",
|
||||
"osVersion": "#1 SMP Sat, 01 Feb 2020 16:35:36 +0000",
|
||||
"osMachine": "x86_64",
|
||||
"cpus": [
|
||||
{
|
||||
"model": "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz",
|
||||
"speed": 2646,
|
||||
"user": 48577700,
|
||||
"nice": 14200,
|
||||
"sys": 8014100,
|
||||
"idle": 166454900,
|
||||
"irq": 735500
|
||||
},
|
||||
{
|
||||
"model": "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz",
|
||||
"speed": 2646,
|
||||
"user": 48745100,
|
||||
"nice": 19200,
|
||||
"sys": 7840700,
|
||||
"idle": 42737200,
|
||||
"irq": 528800
|
||||
},
|
||||
{
|
||||
"model": "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz",
|
||||
"speed": 2647,
|
||||
"user": 48543900,
|
||||
"nice": 15800,
|
||||
"sys": 7804900,
|
||||
"idle": 42914200,
|
||||
"irq": 530200
|
||||
},
|
||||
{
|
||||
"model": "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz",
|
||||
"speed": 2726,
|
||||
"user": 48996200,
|
||||
"nice": 19900,
|
||||
"sys": 7808300,
|
||||
"idle": 42957300,
|
||||
"irq": 390800
|
||||
}
|
||||
],
|
||||
"networkInterfaces": [
|
||||
{
|
||||
"name": "lo",
|
||||
"internal": true,
|
||||
"mac": "00:00:00:00:00:00",
|
||||
"address": "127.0.0.1",
|
||||
"netmask": "255.0.0.0",
|
||||
"family": "IPv4"
|
||||
},
|
||||
{
|
||||
"name": "wlp3s0",
|
||||
"internal": false,
|
||||
"mac": "7c:b0:c2:fe:93:86",
|
||||
"address": "192.168.43.5",
|
||||
"netmask": "255.255.255.0",
|
||||
"family": "IPv4"
|
||||
},
|
||||
{
|
||||
"name": "docker0",
|
||||
"internal": false,
|
||||
"mac": "02:42:13:a9:89:9d",
|
||||
"address": "172.17.0.1",
|
||||
"netmask": "255.255.0.0",
|
||||
"family": "IPv4"
|
||||
},
|
||||
{
|
||||
"name": "br-e929893879ec",
|
||||
"internal": false,
|
||||
"mac": "02:42:48:f4:23:30",
|
||||
"address": "172.19.0.1",
|
||||
"netmask": "255.255.0.0",
|
||||
"family": "IPv4"
|
||||
},
|
||||
{
|
||||
"name": "lo",
|
||||
"internal": true,
|
||||
"mac": "00:00:00:00:00:00",
|
||||
"address": "::1",
|
||||
"netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
|
||||
"family": "IPv6",
|
||||
"scopeid": 0
|
||||
},
|
||||
{
|
||||
"name": "wlp3s0",
|
||||
"internal": false,
|
||||
"mac": "7c:b0:c2:fe:93:86",
|
||||
"address": "2600:100b:b000:9bf1:7eb0:c2ff:fefe:9386",
|
||||
"netmask": "ffff:ffff:ffff:ffff::",
|
||||
"family": "IPv6",
|
||||
"scopeid": 0
|
||||
},
|
||||
{
|
||||
"name": "wlp3s0",
|
||||
"internal": false,
|
||||
"mac": "7c:b0:c2:fe:93:86",
|
||||
"address": "fe80::7eb0:c2ff:fefe:9386",
|
||||
"netmask": "ffff:ffff:ffff:ffff::",
|
||||
"family": "IPv6",
|
||||
"scopeid": 3
|
||||
},
|
||||
{
|
||||
"name": "docker0",
|
||||
"internal": false,
|
||||
"mac": "02:42:13:a9:89:9d",
|
||||
"address": "fe80::42:13ff:fea9:899d",
|
||||
"netmask": "ffff:ffff:ffff:ffff::",
|
||||
"family": "IPv6",
|
||||
"scopeid": 5
|
||||
},
|
||||
{
|
||||
"name": "veth79cfd83",
|
||||
"internal": false,
|
||||
"mac": "a2:e9:86:a8:58:bb",
|
||||
"address": "fe80::a0e9:86ff:fea8:58bb",
|
||||
"netmask": "ffff:ffff:ffff:ffff::",
|
||||
"family": "IPv6",
|
||||
"scopeid": 7
|
||||
},
|
||||
{
|
||||
"name": "br-e929893879ec",
|
||||
"internal": false,
|
||||
"mac": "02:42:48:f4:23:30",
|
||||
"address": "fe80::42:48ff:fef4:2330",
|
||||
"netmask": "ffff:ffff:ffff:ffff::",
|
||||
"family": "IPv6",
|
||||
"scopeid": 8
|
||||
},
|
||||
{
|
||||
"name": "vethe27cc3e",
|
||||
"internal": false,
|
||||
"mac": "c6:bd:d7:3b:6c:96",
|
||||
"address": "fe80::c4bd:d7ff:fe3b:6c96",
|
||||
"netmask": "ffff:ffff:ffff:ffff::",
|
||||
"family": "IPv6",
|
||||
"scopeid": 10
|
||||
}
|
||||
],
|
||||
"host": "archlinux"
|
||||
},
|
||||
"javascriptStack": {
|
||||
"message": "No stack.",
|
||||
"stack": [
|
||||
"Unavailable."
|
||||
]
|
||||
},
|
||||
"nativeStack": [
|
||||
{
|
||||
"pc": "0x0000557aee1dae8a",
|
||||
"symbol": "report::TriggerNodeReport(v8::Isolate*, node::Environment*, char const*, char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, v8::Local<v8::String>) [/usr/bin/node]"
|
||||
},
|
||||
{
|
||||
"pc": "0x0000557aee09bd48",
|
||||
"symbol": "node::OnFatalError(char const*, char const*) [/usr/bin/node]"
|
||||
},
|
||||
{
|
||||
"pc": "0x0000557aee20f382",
|
||||
"symbol": "v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/bin/node]"
|
||||
},
|
||||
{
|
||||
"pc": "0x0000557aee20f5e8",
|
||||
"symbol": "v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/bin/node]"
|
||||
},
|
||||
{
|
||||
"pc": "0x0000557aee399906",
|
||||
"symbol": " [/usr/bin/node]"
|
||||
},
|
||||
{
|
||||
"pc": "0x0000557aee399a49",
|
||||
"symbol": " [/usr/bin/node]"
|
||||
},
|
||||
{
|
||||
"pc": "0x0000557aee3ac22d",
|
||||
"symbol": "v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/usr/bin/node]"
|
||||
},
|
||||
{
|
||||
"pc": "0x0000557aee3acf58",
|
||||
"symbol": "v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/bin/node]"
|
||||
},
|
||||
{
|
||||
"pc": "0x0000557aee3af48c",
|
||||
"symbol": "v8::internal::Heap::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/usr/bin/node]"
|
||||
},
|
||||
{
|
||||
"pc": "0x0000557aee3af4f4",
|
||||
"symbol": "v8::internal::Heap::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/usr/bin/node]"
|
||||
},
|
||||
{
|
||||
"pc": "0x0000557aee37499b",
|
||||
"symbol": "v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationType, v8::internal::AllocationOrigin) [/usr/bin/node]"
|
||||
},
|
||||
{
|
||||
"pc": "0x0000557aee6a5540",
|
||||
"symbol": "v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/usr/bin/node]"
|
||||
},
|
||||
{
|
||||
"pc": "0x0000557aee9febd9",
|
||||
"symbol": " [/usr/bin/node]"
|
||||
}
|
||||
],
|
||||
"javascriptHeap": {
|
||||
"totalMemory": 2152407040,
|
||||
"totalCommittedMemory": 2150546232,
|
||||
"usedMemory": 2137632424,
|
||||
"availableMemory": 47662336,
|
||||
"memoryLimit": 2197815296,
|
||||
"heapSpaces": {
|
||||
"read_only_space": {
|
||||
"memorySize": 262144,
|
||||
"committedMemory": 33328,
|
||||
"capacity": 33040,
|
||||
"used": 33040,
|
||||
"available": 0
|
||||
},
|
||||
"new_space": {
|
||||
"memorySize": 2097152,
|
||||
"committedMemory": 1029144,
|
||||
"capacity": 1047424,
|
||||
"used": 21136,
|
||||
"available": 1026288
|
||||
},
|
||||
"old_space": {
|
||||
"memorySize": 2058231808,
|
||||
"committedMemory": 2057888048,
|
||||
"capacity": 2048399928,
|
||||
"used": 2048219560,
|
||||
"available": 180368
|
||||
},
|
||||
"code_space": {
|
||||
"memorySize": 9080832,
|
||||
"committedMemory": 8864320,
|
||||
"capacity": 7755264,
|
||||
"used": 7755264,
|
||||
"available": 0
|
||||
},
|
||||
"map_space": {
|
||||
"memorySize": 1052672,
|
||||
"committedMemory": 1048960,
|
||||
"capacity": 740080,
|
||||
"used": 740080,
|
||||
"available": 0
|
||||
},
|
||||
"large_object_space": {
|
||||
"memorySize": 81305600,
|
||||
"committedMemory": 81305600,
|
||||
"capacity": 80548528,
|
||||
"used": 80548528,
|
||||
"available": 0
|
||||
},
|
||||
"code_large_object_space": {
|
||||
"memorySize": 376832,
|
||||
"committedMemory": 376832,
|
||||
"capacity": 314816,
|
||||
"used": 314816,
|
||||
"available": 0
|
||||
},
|
||||
"new_large_object_space": {
|
||||
"memorySize": 0,
|
||||
"committedMemory": 0,
|
||||
"capacity": 1047424,
|
||||
"used": 0,
|
||||
"available": 1047424
|
||||
}
|
||||
}
|
||||
},
|
||||
"resourceUsage": {
|
||||
"userCpuSeconds": 3484.11,
|
||||
"kernelCpuSeconds": 64.7409,
|
||||
"cpuConsumptionPercent": 35.606,
|
||||
"maxRss": 2330890240,
|
||||
"pageFaults": {
|
||||
"IORequired": 31,
|
||||
"IONotRequired": 9729381
|
||||
},
|
||||
"fsActivity": {
|
||||
"reads": 53144,
|
||||
"writes": 16
|
||||
}
|
||||
},
|
||||
"uvthreadResourceUsage": {
|
||||
"userCpuSeconds": 2308.89,
|
||||
"kernelCpuSeconds": 31.2857,
|
||||
"cpuConsumptionPercent": 23.4792,
|
||||
"fsActivity": {
|
||||
"reads": 53248,
|
||||
"writes": 16
|
||||
}
|
||||
},
|
||||
"libuv": [
|
||||
],
|
||||
"environmentVariables": {
|
||||
"COLORTERM": "truecolor",
|
||||
"DBUS_SESSION_BUS_ADDRESS": "unix:path=/run/user/1000/bus",
|
||||
"DESKTOP_SESSION": "awesome",
|
||||
"DISPLAY": ":0.0",
|
||||
"EDITOR": "nano",
|
||||
"FZF_DEFAULT_COMMAND": "ag --hidden --ignore .git -g \"\"",
|
||||
"GDMSESSION": "awesome",
|
||||
"GO111MODULE": "on",
|
||||
"GOBIN": "/home/jordan/go/bin",
|
||||
"GREP_COLOR": "37;45",
|
||||
"GREP_COLORS": "mt=37;45",
|
||||
"GTK_MODULES": "canberra-gtk-module",
|
||||
"HOME": "/home/jordan",
|
||||
"LANG": "C",
|
||||
"LESS": "-F -g -i -M -R -S -w -X -z-4",
|
||||
"LESS_TERMCAP_mb": "\u001b[01;31m",
|
||||
"LESS_TERMCAP_md": "\u001b[01;31m",
|
||||
"LESS_TERMCAP_me": "\u001b[0m",
|
||||
"LESS_TERMCAP_se": "\u001b[0m",
|
||||
"LESS_TERMCAP_so": "\u001b[00;47;30m",
|
||||
"LESS_TERMCAP_ue": "\u001b[0m",
|
||||
"LESS_TERMCAP_us": "\u001b[01;32m",
|
||||
"LOGNAME": "jordan",
|
||||
"LS_COLORS": "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:",
|
||||
"MAIL": "/var/spool/mail/jordan",
|
||||
"OLDPWD": "/home/jordan/Projects/project-citadel/web",
|
||||
"PAGER": "less",
|
||||
"PATH": "/home/jordan/.local/bin:/usr/local/bin:/usr/local/sbin:/home/nightwolf/Programs/cmake/bin:/home/nightwolf/Programs/idea-IU-163.13906.18/bin:/home/nightwolf/Programs/wpcli:/home/nightwolf/neovim/bin:/home/nightwolf/Programs/Postman:/home/nightwolf/Programs/Android_SDK/tools/bin:/home/nightwolf/Development/PhantomJS/bin:/home/nightwolf/Programs/node/bin:/home/nightwolf/pyenv/bin:/home/nightwolf/Programs/vv:/usr/bin:/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/usr/local/go/bin:/home/jordan/go/bin:/home/jordan/.garden/bin:~/Programs/node/bin:~/.utilities:/home/jordan/.fzf/bin:/home/jordan/.gem/ruby/2.6.0/bin:/home/jordan/.garden/bin:~/Programs/node/bin:~/.utilities:/home/jordan/.gem/ruby/2.6.0/bin",
|
||||
"PWD": "/home/jordan/Projects/project-citadel/web",
|
||||
"SHELL": "/usr/bin/zsh",
|
||||
"SHLVL": "2",
|
||||
"SSH_AGENT_PID": "773",
|
||||
"SSH_AUTH_SOCK": "/tmp/ssh-agent.sock.1000",
|
||||
"TERM": "xterm-256color",
|
||||
"TMUX": "/tmp/tmux-1000/default,13203,1",
|
||||
"TMUX_PANE": "%2",
|
||||
"USER": "jordan",
|
||||
"VIRTUALENVWRAPPER_PYTHON": "/usr/bin/python3",
|
||||
"VIRTUAL_ENV_DISABLE_PROMPT": "12",
|
||||
"VISUAL": "nano",
|
||||
"VTE_VERSION": "5602",
|
||||
"WINDOWID": "6291459",
|
||||
"WORKON_HOME": "/home/jordan/.virtualenvs",
|
||||
"XAUTHORITY": "/home/jordan/.Xauthority",
|
||||
"XDG_GREETER_DATA_DIR": "/var/lib/lightdm-data/jordan",
|
||||
"XDG_RUNTIME_DIR": "/run/user/1000",
|
||||
"XDG_SEAT": "seat0",
|
||||
"XDG_SEAT_PATH": "/org/freedesktop/DisplayManager/Seat0",
|
||||
"XDG_SESSION_CLASS": "user",
|
||||
"XDG_SESSION_DESKTOP": "awesome",
|
||||
"XDG_SESSION_ID": "1",
|
||||
"XDG_SESSION_PATH": "/org/freedesktop/DisplayManager/Session0",
|
||||
"XDG_SESSION_TYPE": "x11",
|
||||
"XDG_VTNR": "7",
|
||||
"_": "/usr/bin/nvim",
|
||||
"is_vim": "ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|n?vim?x?)(diff)?$'",
|
||||
"tmux_version": "$(tmux -V | sed -En \"s/^tmux ([0-9]+(.[0-9]+)?).*/\\1/p\")",
|
||||
"LC_MESSAGES": "",
|
||||
"VIMRUNTIME": "/usr/share/nvim/runtime",
|
||||
"NVIM_LISTEN_ADDRESS": "/tmp/nvimaHxiZq/0",
|
||||
"MYVIMRC": "/home/jordan/.config/nvim/init.vim",
|
||||
"COC_VIMCONFIG": "/home/jordan/.config/nvim",
|
||||
"COC_DATA_HOME": "/home/jordan/.config/coc",
|
||||
"TSS_LOG": "-level verbose -file /tmp/coc-nvim-tsc.log",
|
||||
"NODE_PATH": "/home/jordan/Projects/project-citadel/web/node_modules"
|
||||
},
|
||||
"userLimits": {
|
||||
"core_file_size_blocks": {
|
||||
"soft": "unlimited",
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"data_seg_size_kbytes": {
|
||||
"soft": "unlimited",
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"file_size_blocks": {
|
||||
"soft": "unlimited",
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"max_locked_memory_bytes": {
|
||||
"soft": 65536,
|
||||
"hard": 65536
|
||||
},
|
||||
"max_memory_size_kbytes": {
|
||||
"soft": "unlimited",
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"open_files": {
|
||||
"soft": 524288,
|
||||
"hard": 524288
|
||||
},
|
||||
"stack_size_bytes": {
|
||||
"soft": 8388608,
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"cpu_time_seconds": {
|
||||
"soft": "unlimited",
|
||||
"hard": "unlimited"
|
||||
},
|
||||
"max_user_processes": {
|
||||
"soft": 31138,
|
||||
"hard": 31138
|
||||
},
|
||||
"virtual_memory_kbytes": {
|
||||
"soft": "unlimited",
|
||||
"hard": "unlimited"
|
||||
}
|
||||
},
|
||||
"sharedObjects": [
|
||||
"linux-vdso.so.1",
|
||||
"/usr/lib/libz.so.1",
|
||||
"/usr/lib/libcares.so.2",
|
||||
"/usr/lib/libnghttp2.so.14",
|
||||
"/usr/lib/libcrypto.so.1.1",
|
||||
"/usr/lib/libssl.so.1.1",
|
||||
"/usr/lib/libicui18n.so.65",
|
||||
"/usr/lib/libicuuc.so.65",
|
||||
"/usr/lib/libdl.so.2",
|
||||
"/usr/lib/libstdc++.so.6",
|
||||
"/usr/lib/libm.so.6",
|
||||
"/usr/lib/libgcc_s.so.1",
|
||||
"/usr/lib/libpthread.so.0",
|
||||
"/usr/lib/libc.so.6",
|
||||
"/usr/lib/libicudata.so.65",
|
||||
"/lib64/ld-linux-x86-64.so.2"
|
||||
]
|
||||
}
|
158
web/src/Admin/index.tsx
Normal file
158
web/src/Admin/index.tsx
Normal file
@ -0,0 +1,158 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import Admin from 'shared/components/Admin';
|
||||
import GlobalTopNavbar from 'App/TopNavbar';
|
||||
import { useUsersQuery, useCreateUserAccountMutation, UsersDocument } from 'shared/generated/graphql';
|
||||
import Input from 'shared/components/Input';
|
||||
import styled from 'styled-components';
|
||||
import Button from 'shared/components/Button';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { usePopup, Popup } from 'shared/components/PopupMenu';
|
||||
import produce from 'immer';
|
||||
|
||||
type CreateUserData = {
|
||||
email: string;
|
||||
username: string;
|
||||
fullName: string;
|
||||
initials: string;
|
||||
password: string;
|
||||
};
|
||||
const CreateUserForm = styled.form`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
const CreateUserButton = styled(Button)`
|
||||
margin-top: 8px;
|
||||
padding: 6px 12px;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const AddUserInput = styled(Input)`
|
||||
margin-bottom: 8px;
|
||||
`;
|
||||
|
||||
const InputError = styled.span`
|
||||
color: rgba(${props => props.theme.colors.danger});
|
||||
font-size: 12px;
|
||||
`;
|
||||
type AddUserPopupProps = {
|
||||
onAddUser: (user: CreateUserData) => void;
|
||||
};
|
||||
const AddUserPopup: React.FC<AddUserPopupProps> = ({ onAddUser }) => {
|
||||
const { register, handleSubmit, errors } = useForm<CreateUserData>();
|
||||
const createUser = (data: CreateUserData) => {
|
||||
onAddUser(data);
|
||||
};
|
||||
return (
|
||||
<CreateUserForm onSubmit={handleSubmit(createUser)}>
|
||||
<AddUserInput
|
||||
floatingLabel
|
||||
width="100%"
|
||||
label="Full Name"
|
||||
id="fullName"
|
||||
name="fullName"
|
||||
variant="alternate"
|
||||
ref={register({ required: 'Full name is required' })}
|
||||
/>
|
||||
{errors.fullName && <InputError>{errors.fullName.message}</InputError>}
|
||||
<AddUserInput
|
||||
floatingLabel
|
||||
width="100%"
|
||||
label="Email"
|
||||
id="email"
|
||||
name="email"
|
||||
variant="alternate"
|
||||
ref={register({ required: 'Email is required' })}
|
||||
/>
|
||||
{errors.email && <InputError>{errors.email.message}</InputError>}
|
||||
<AddUserInput
|
||||
floatingLabel
|
||||
width="100%"
|
||||
label="Username"
|
||||
id="username"
|
||||
name="username"
|
||||
variant="alternate"
|
||||
ref={register({ required: 'Username is required' })}
|
||||
/>
|
||||
{errors.username && <InputError>{errors.username.message}</InputError>}
|
||||
<AddUserInput
|
||||
floatingLabel
|
||||
width="100%"
|
||||
label="Initials"
|
||||
id="initials"
|
||||
name="initials"
|
||||
variant="alternate"
|
||||
ref={register({ required: 'Initials is required' })}
|
||||
/>
|
||||
{errors.initials && <InputError>{errors.initials.message}</InputError>}
|
||||
<AddUserInput
|
||||
floatingLabel
|
||||
width="100%"
|
||||
label="Password"
|
||||
id="password"
|
||||
name="password"
|
||||
variant="alternate"
|
||||
ref={register({ required: 'Password is required' })}
|
||||
/>
|
||||
{errors.password && <InputError>{errors.password.message}</InputError>}
|
||||
<CreateUserButton type="submit">Create</CreateUserButton>
|
||||
</CreateUserForm>
|
||||
);
|
||||
};
|
||||
|
||||
const AdminRoute = () => {
|
||||
useEffect(() => {
|
||||
document.title = 'Citadel | Admin';
|
||||
}, []);
|
||||
const { loading, data } = useUsersQuery();
|
||||
const { showPopup, hidePopup } = usePopup();
|
||||
const [createUser] = useCreateUserAccountMutation({
|
||||
update: (client, createData) => {
|
||||
const cacheData: any = client.readQuery({
|
||||
query: UsersDocument,
|
||||
});
|
||||
console.log(cacheData);
|
||||
console.log(createData);
|
||||
const newData = produce(cacheData, (draftState: any) => {
|
||||
draftState.users = [...draftState.users, { ...createData.data.createUserAccount }];
|
||||
});
|
||||
|
||||
client.writeQuery({
|
||||
query: UsersDocument,
|
||||
data: {
|
||||
...newData,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
if (loading) {
|
||||
return <GlobalTopNavbar projectID={null} onSaveProjectName={() => {}} name={null} />;
|
||||
}
|
||||
if (data) {
|
||||
return (
|
||||
<>
|
||||
<GlobalTopNavbar projectID={null} onSaveProjectName={() => {}} name={null} />
|
||||
<Admin
|
||||
initialTab={1}
|
||||
users={data.users.map((user: any) => ({ ...user, role: 'TBD' }))}
|
||||
onInviteUser={() => {}}
|
||||
onAddUser={$target => {
|
||||
showPopup(
|
||||
$target,
|
||||
<Popup tab={0} title="Add member" onClose={() => hidePopup()}>
|
||||
<AddUserPopup
|
||||
onAddUser={user => {
|
||||
createUser({ variables: { ...user } });
|
||||
hidePopup();
|
||||
}}
|
||||
/>
|
||||
</Popup>,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return <span>error</span>;
|
||||
};
|
||||
|
||||
export default AdminRoute;
|
@ -15,7 +15,7 @@ const GlobalNavbar = () => {
|
||||
<ButtonContainer>
|
||||
<Link to="/">
|
||||
<ActionButton name="Home">
|
||||
<Home size={28} color="#c2c6dc" />
|
||||
<Home width={28} height={28} />
|
||||
</ActionButton>
|
||||
</Link>
|
||||
<Link to="/projects">
|
||||
|
@ -3,14 +3,16 @@ import { Router, Switch, Route } from 'react-router-dom';
|
||||
import * as H from 'history';
|
||||
|
||||
import Dashboard from 'Dashboard';
|
||||
import Admin from 'Admin';
|
||||
import Projects from 'Projects';
|
||||
import Project from 'Projects/Project';
|
||||
import Teams from 'Teams';
|
||||
import Login from 'Auth';
|
||||
import Profile from 'Profile';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const MainContent = styled.div`
|
||||
padding: 0 0 0 80px;
|
||||
padding: 0 0 0 0;
|
||||
background: #262c49;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
@ -28,7 +30,9 @@ const Routes = ({ history }: RoutesProps) => (
|
||||
<Route exact path="/" component={Dashboard} />
|
||||
<Route exact path="/projects" component={Projects} />
|
||||
<Route path="/projects/:projectID" component={Project} />
|
||||
<Route path="/teams/:teamID" component={Teams} />
|
||||
<Route path="/profile" component={Profile} />
|
||||
<Route path="/admin" component={Admin} />
|
||||
</MainContent>
|
||||
</Switch>
|
||||
);
|
||||
|
@ -1,24 +1,172 @@
|
||||
import React, { useState, useContext } from 'react';
|
||||
import React, { useState, useContext, useEffect } from 'react';
|
||||
import TopNavbar from 'shared/components/TopNavbar';
|
||||
import styled from 'styled-components/macro';
|
||||
import DropdownMenu, { ProfileMenu } from 'shared/components/DropdownMenu';
|
||||
import ProjectSettings, { DeleteProject } from 'shared/components/ProjectSettings';
|
||||
import ProjectSettings, { DeleteConfirm, DELETE_INFO } from 'shared/components/ProjectSettings';
|
||||
import { useHistory } from 'react-router';
|
||||
import UserIDContext from 'App/context';
|
||||
import { useMeQuery, useDeleteProjectMutation, GetProjectsDocument } from 'shared/generated/graphql';
|
||||
import {
|
||||
useMeQuery,
|
||||
useDeleteProjectMutation,
|
||||
useGetProjectsQuery,
|
||||
GetProjectsDocument,
|
||||
} from 'shared/generated/graphql';
|
||||
import { usePopup, Popup } from 'shared/components/PopupMenu';
|
||||
import { History } from 'history';
|
||||
import produce from 'immer';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
type GlobalTopNavbarProps = {
|
||||
projectID: string | null;
|
||||
name: string | null;
|
||||
projectMembers?: null | Array<TaskUser>;
|
||||
onSaveProjectName?: (projectName: string) => void;
|
||||
const TeamContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const TeamTitle = styled.h3`
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
`;
|
||||
|
||||
const TeamProjects = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 4px;
|
||||
`;
|
||||
|
||||
const TeamProjectLink = styled(Link)`
|
||||
display: flex;
|
||||
font-weight: 700;
|
||||
height: 36px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
user-select: none;
|
||||
`;
|
||||
|
||||
const TeamProjectBackground = styled.div<{ color: string }>`
|
||||
background-image: url(null);
|
||||
background-color: ${props => props.color};
|
||||
|
||||
background-size: cover;
|
||||
background-position: 50%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
opacity: 1;
|
||||
border-radius: 3px;
|
||||
&:before {
|
||||
background: rgba(${props => props.theme.colors.bg.secondary});
|
||||
bottom: 0;
|
||||
content: '';
|
||||
left: 0;
|
||||
opacity: 0.88;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const TeamProjectAvatar = styled.div<{ color: string }>`
|
||||
background-image: url(null);
|
||||
background-color: ${props => props.color};
|
||||
|
||||
display: inline-block;
|
||||
flex: 0 0 auto;
|
||||
background-size: cover;
|
||||
border-radius: 3px 0 0 3px;
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
position: relative;
|
||||
opacity: 0.7;
|
||||
`;
|
||||
|
||||
const TeamProjectContent = styled.div`
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
padding: 9px 0 9px 10px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
const TeamProjectTitle = styled.div`
|
||||
font-weight: 700;
|
||||
display: block;
|
||||
padding-right: 12px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
const TeamProjectContainer = styled.div`
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
margin: 0 4px 4px 0;
|
||||
min-width: 0;
|
||||
&:hover ${TeamProjectTitle} {
|
||||
color: rgba(${props => props.theme.colors.text.secondary});
|
||||
}
|
||||
&:hover ${TeamProjectAvatar} {
|
||||
opacity: 1;
|
||||
}
|
||||
&:hover ${TeamProjectBackground}:before {
|
||||
opacity: 0.78;
|
||||
}
|
||||
`;
|
||||
|
||||
const colors = ['#e362e3', '#7a6ff0', '#37c5ab', '#aa62e3', '#e8384f'];
|
||||
|
||||
const ProjectFinder = () => {
|
||||
const { loading, data } = useGetProjectsQuery();
|
||||
if (loading) {
|
||||
return <span>loading</span>;
|
||||
}
|
||||
if (data) {
|
||||
const { projects, teams, organizations } = data;
|
||||
const projectTeams = teams.map(team => {
|
||||
return {
|
||||
id: team.id,
|
||||
name: team.name,
|
||||
projects: projects.filter(project => project.team.id === team.id),
|
||||
};
|
||||
});
|
||||
return (
|
||||
<>
|
||||
{projectTeams.map(team => (
|
||||
<TeamContainer>
|
||||
<TeamTitle>{team.name}</TeamTitle>
|
||||
<TeamProjects>
|
||||
{team.projects.map((project, idx) => (
|
||||
<TeamProjectContainer>
|
||||
<TeamProjectLink to={`/projects/${project.id}`}>
|
||||
<TeamProjectBackground color={colors[idx % 5]} />
|
||||
<TeamProjectAvatar color={colors[idx % 5]} />
|
||||
<TeamProjectContent>
|
||||
<TeamProjectTitle>{project.name}</TeamProjectTitle>
|
||||
</TeamProjectContent>
|
||||
</TeamProjectLink>
|
||||
</TeamProjectContainer>
|
||||
))}
|
||||
</TeamProjects>
|
||||
</TeamContainer>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
return <span>error</span>;
|
||||
};
|
||||
const GlobalTopNavbar: React.FC<GlobalTopNavbarProps> = ({ projectID, name, projectMembers, onSaveProjectName }) => {
|
||||
const { loading, data } = useMeQuery();
|
||||
const { showPopup, hidePopup, setTab } = usePopup();
|
||||
const history = useHistory();
|
||||
const { userID, setUserID } = useContext(UserIDContext);
|
||||
type ProjectPopupProps = {
|
||||
history: History<History.PoorMansUnknown>;
|
||||
name: string;
|
||||
projectID: string;
|
||||
};
|
||||
|
||||
export const ProjectPopup: React.FC<ProjectPopupProps> = ({ history, name, projectID }) => {
|
||||
const { hidePopup, setTab } = usePopup();
|
||||
const [deleteProject] = useDeleteProjectMutation({
|
||||
update: (client, deleteData) => {
|
||||
const cacheData: any = client.readQuery({
|
||||
@ -42,6 +190,62 @@ const GlobalTopNavbar: React.FC<GlobalTopNavbarProps> = ({ projectID, name, proj
|
||||
});
|
||||
},
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<Popup title={null} tab={0}>
|
||||
<ProjectSettings
|
||||
onDeleteProject={() => {
|
||||
setTab(1);
|
||||
}}
|
||||
/>
|
||||
</Popup>
|
||||
<Popup title={`Delete the "${name}" project?`} tab={1}>
|
||||
<DeleteConfirm
|
||||
description={DELETE_INFO.DELETE_PROJECTS.description}
|
||||
deletedItems={DELETE_INFO.DELETE_PROJECTS.deletedItems}
|
||||
onConfirmDelete={() => {
|
||||
if (projectID) {
|
||||
deleteProject({ variables: { projectID } });
|
||||
hidePopup();
|
||||
history.push('/projects');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Popup>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
type GlobalTopNavbarProps = {
|
||||
nameOnly?: boolean;
|
||||
projectID: string | null;
|
||||
name: string | null;
|
||||
initialTab?: number;
|
||||
popupContent?: JSX.Element;
|
||||
menuType?: Array<string>;
|
||||
projectMembers?: null | Array<TaskUser>;
|
||||
onSaveProjectName?: (projectName: string) => void;
|
||||
};
|
||||
|
||||
const GlobalTopNavbar: React.FC<GlobalTopNavbarProps> = ({
|
||||
initialTab,
|
||||
menuType,
|
||||
projectID,
|
||||
name,
|
||||
popupContent,
|
||||
projectMembers,
|
||||
onSaveProjectName,
|
||||
nameOnly,
|
||||
}) => {
|
||||
console.log(popupContent);
|
||||
const { loading, data } = useMeQuery();
|
||||
const { showPopup, hidePopup, setTab } = usePopup();
|
||||
const history = useHistory();
|
||||
const [currentTab, setCurrentTab] = useState(initialTab);
|
||||
useEffect(() => {
|
||||
setCurrentTab(initialTab);
|
||||
}, [initialTab]);
|
||||
const { userID, setUserID } = useContext(UserIDContext);
|
||||
const onLogout = () => {
|
||||
fetch('http://localhost:3333/auth/logout', {
|
||||
method: 'POST',
|
||||
@ -61,42 +265,26 @@ const GlobalTopNavbar: React.FC<GlobalTopNavbarProps> = ({ projectID, name, proj
|
||||
<Popup title={null} tab={0}>
|
||||
<ProfileMenu
|
||||
onLogout={onLogout}
|
||||
onAdminConsole={() => {
|
||||
history.push('/admin');
|
||||
hidePopup();
|
||||
}}
|
||||
onProfile={() => {
|
||||
history.push('/profile');
|
||||
hidePopup();
|
||||
}}
|
||||
/>
|
||||
</Popup>,
|
||||
185,
|
||||
195,
|
||||
);
|
||||
};
|
||||
|
||||
const onOpenSettings = ($target: React.RefObject<HTMLElement>) => {
|
||||
showPopup(
|
||||
$target,
|
||||
<>
|
||||
<Popup title={null} tab={0}>
|
||||
<ProjectSettings
|
||||
onDeleteProject={() => {
|
||||
setTab(1, 325);
|
||||
}}
|
||||
/>
|
||||
</Popup>
|
||||
<Popup title={`Delete the "${name}" project?`} tab={1}>
|
||||
<DeleteProject
|
||||
name={name ?? ''}
|
||||
onDeleteProject={() => {
|
||||
if (projectID) {
|
||||
deleteProject({ variables: { projectID } });
|
||||
hidePopup();
|
||||
history.push('/projects');
|
||||
console.log('maybe firing popup');
|
||||
if (popupContent) {
|
||||
console.log('showing popup');
|
||||
showPopup($target, popupContent, 185);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Popup>
|
||||
</>,
|
||||
185,
|
||||
);
|
||||
};
|
||||
|
||||
if (!userID) {
|
||||
@ -105,12 +293,25 @@ const GlobalTopNavbar: React.FC<GlobalTopNavbarProps> = ({ projectID, name, proj
|
||||
return (
|
||||
<>
|
||||
<TopNavbar
|
||||
projectName={name}
|
||||
name={name}
|
||||
menuType={menuType}
|
||||
onOpenProjectFinder={$target => {
|
||||
showPopup(
|
||||
$target,
|
||||
<Popup tab={0} title={null}>
|
||||
<ProjectFinder />
|
||||
</Popup>,
|
||||
);
|
||||
}}
|
||||
currentTab={currentTab}
|
||||
user={data ? data.me : null}
|
||||
onNotificationClick={() => {}}
|
||||
onDashboardClick={() => {
|
||||
history.push('/');
|
||||
}}
|
||||
projectMembers={projectMembers}
|
||||
onProfileClick={onProfileClick}
|
||||
onSaveProjectName={onSaveProjectName}
|
||||
onSaveName={onSaveProjectName}
|
||||
onOpenSettings={onOpenSettings}
|
||||
/>
|
||||
</>
|
||||
|
@ -41,20 +41,19 @@ const App = () => {
|
||||
<>
|
||||
<UserIDContext.Provider value={{ userID, setUserID }}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<PopupProvider>
|
||||
<NormalizeStyles />
|
||||
<BaseStyles />
|
||||
<Router history={history}>
|
||||
<PopupProvider>
|
||||
{loading ? (
|
||||
<div>loading</div>
|
||||
) : (
|
||||
<>
|
||||
<Navbar />
|
||||
<Routes history={history} />
|
||||
</>
|
||||
)}
|
||||
</Router>
|
||||
</PopupProvider>
|
||||
</Router>
|
||||
</ThemeProvider>
|
||||
</UserIDContext.Provider>
|
||||
</>
|
||||
|
@ -5,6 +5,9 @@ import PopupMenu, { Popup, usePopup } from 'shared/components/PopupMenu';
|
||||
import MemberManager from 'shared/components/MemberManager';
|
||||
import { useRouteMatch, useHistory } from 'react-router';
|
||||
import {
|
||||
useDeleteTaskChecklistMutation,
|
||||
useUpdateTaskChecklistNameMutation,
|
||||
useCreateTaskChecklistMutation,
|
||||
useFindTaskQuery,
|
||||
useUpdateTaskDueDateMutation,
|
||||
useSetTaskCompleteMutation,
|
||||
@ -20,6 +23,82 @@ import UserIDContext from 'App/context';
|
||||
import MiniProfile from 'shared/components/MiniProfile';
|
||||
import DueDateManager from 'shared/components/DueDateManager';
|
||||
import produce from 'immer';
|
||||
import styled from 'styled-components';
|
||||
import Button from 'shared/components/Button';
|
||||
import Input from 'shared/components/Input';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
const calculateChecklistBadge = (draftState: any) => {
|
||||
const total = draftState.checklists.reduce((prev: any, next: any) => {
|
||||
return (
|
||||
prev +
|
||||
next.items.reduce((innerPrev: any, _item: any) => {
|
||||
return innerPrev + 1;
|
||||
}, 0)
|
||||
);
|
||||
}, 0);
|
||||
const complete = draftState.checklists.reduce(
|
||||
(prev: any, next: any) =>
|
||||
prev +
|
||||
next.items.reduce((innerPrev: any, item: any) => {
|
||||
return innerPrev + (item.complete ? 1 : 0);
|
||||
}, 0),
|
||||
0,
|
||||
);
|
||||
return { total, complete };
|
||||
};
|
||||
|
||||
const DeleteChecklistButton = styled(Button)`
|
||||
width: 100%;
|
||||
padding: 6px 12px;
|
||||
margin-top: 8px;
|
||||
`;
|
||||
type CreateChecklistData = {
|
||||
name: string;
|
||||
};
|
||||
const CreateChecklistForm = styled.form`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const CreateChecklistButton = styled(Button)`
|
||||
margin-top: 8px;
|
||||
padding: 6px 12px;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const CreateChecklistInput = styled(Input)`
|
||||
margin-bottom: 8px;
|
||||
`;
|
||||
|
||||
const InputError = styled.span`
|
||||
color: rgba(${props => props.theme.colors.danger});
|
||||
font-size: 12px;
|
||||
`;
|
||||
type CreateChecklistPopupProps = {
|
||||
onCreateChecklist: (data: CreateChecklistData) => void;
|
||||
};
|
||||
const CreateChecklistPopup: React.FC<CreateChecklistPopupProps> = ({ onCreateChecklist }) => {
|
||||
const { register, handleSubmit, errors } = useForm<CreateChecklistData>();
|
||||
const createUser = (data: CreateChecklistData) => {
|
||||
onCreateChecklist(data);
|
||||
};
|
||||
console.log(errors);
|
||||
return (
|
||||
<CreateChecklistForm onSubmit={handleSubmit(createUser)}>
|
||||
<CreateChecklistInput
|
||||
floatingLabel
|
||||
width="100%"
|
||||
label="Name"
|
||||
id="name"
|
||||
name="name"
|
||||
variant="alternate"
|
||||
ref={register({ required: 'Checklist name is required' })}
|
||||
/>
|
||||
<CreateChecklistButton type="submit">Create</CreateChecklistButton>
|
||||
</CreateChecklistForm>
|
||||
);
|
||||
};
|
||||
|
||||
type DetailsProps = {
|
||||
taskID: string;
|
||||
@ -50,8 +129,93 @@ const Details: React.FC<DetailsProps> = ({
|
||||
const match = useRouteMatch();
|
||||
const [currentMemberTask, setCurrentMemberTask] = useState('');
|
||||
const [memberPopupData, setMemberPopupData] = useState(initialMemberPopupState);
|
||||
const [setTaskChecklistItemComplete] = useSetTaskChecklistItemCompleteMutation();
|
||||
const [setTaskChecklistItemComplete] = useSetTaskChecklistItemCompleteMutation({
|
||||
update: client => {
|
||||
const cacheData: any = client.readQuery({
|
||||
query: FindTaskDocument,
|
||||
variables: { taskID },
|
||||
});
|
||||
const newData = produce(cacheData.findTask, (draftState: any) => {
|
||||
const { complete, total } = calculateChecklistBadge(draftState);
|
||||
if (!draftState.badges) {
|
||||
draftState.badges = {
|
||||
checklist: {},
|
||||
};
|
||||
}
|
||||
draftState.badges.checklist = {
|
||||
__typename: 'ChecklistBadge',
|
||||
complete,
|
||||
total,
|
||||
};
|
||||
});
|
||||
client.writeQuery({
|
||||
query: FindTaskDocument,
|
||||
variables: { taskID },
|
||||
data: {
|
||||
findTask: newData,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
const [deleteTaskChecklist] = useDeleteTaskChecklistMutation({
|
||||
update: (client, deleteData) => {
|
||||
const cacheData: any = client.readQuery({
|
||||
query: FindTaskDocument,
|
||||
variables: { taskID },
|
||||
});
|
||||
console.log(deleteData);
|
||||
|
||||
const newData = produce(cacheData.findTask, (draftState: any) => {
|
||||
draftState.checklists = cacheData.findTask.checklists.filter(
|
||||
(checklist: any) => checklist.id !== deleteData.data.deleteTaskChecklist.taskChecklist.id,
|
||||
);
|
||||
const { complete, total } = calculateChecklistBadge(draftState);
|
||||
if (!draftState.badges) {
|
||||
draftState.badges = {
|
||||
checklist: {},
|
||||
};
|
||||
}
|
||||
draftState.badges.checklist = {
|
||||
__typename: 'ChecklistBadge',
|
||||
complete,
|
||||
total,
|
||||
};
|
||||
if (complete === 0 && total === 0) {
|
||||
draftState.badges.checklist = null;
|
||||
}
|
||||
});
|
||||
client.writeQuery({
|
||||
query: FindTaskDocument,
|
||||
variables: { taskID },
|
||||
data: {
|
||||
findTask: newData,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
const [updateTaskChecklistItemName] = useUpdateTaskChecklistItemNameMutation();
|
||||
const [createTaskChecklist] = useCreateTaskChecklistMutation({
|
||||
update: (client, createData) => {
|
||||
const cacheData: any = client.readQuery({
|
||||
query: FindTaskDocument,
|
||||
variables: { taskID },
|
||||
});
|
||||
console.log(createData);
|
||||
|
||||
const newData = {
|
||||
findTask: {
|
||||
...cacheData.findTask,
|
||||
checklists: [...cacheData.findTask.checklists, { ...createData.data.createTaskChecklist }],
|
||||
},
|
||||
};
|
||||
client.writeQuery({
|
||||
query: FindTaskDocument,
|
||||
variables: { taskID },
|
||||
data: newData,
|
||||
});
|
||||
},
|
||||
});
|
||||
const [updateTaskChecklistName] = useUpdateTaskChecklistNameMutation();
|
||||
const [deleteTaskChecklistItem] = useDeleteTaskChecklistItemMutation({
|
||||
update: (client, deleteData) => {
|
||||
const cacheData: any = client.readQuery({
|
||||
@ -69,6 +233,17 @@ const Details: React.FC<DetailsProps> = ({
|
||||
draftState.checklists[idx].items = cacheData.findTask.checklists[idx].items.filter(
|
||||
(item: any) => item.id !== deleteData.data.deleteTaskChecklistItem.taskChecklistItem.id,
|
||||
);
|
||||
const { complete, total } = calculateChecklistBadge(draftState);
|
||||
if (!draftState.badges) {
|
||||
draftState.badges = {
|
||||
checklist: {},
|
||||
};
|
||||
}
|
||||
draftState.badges.checklist = {
|
||||
__typename: 'ChecklistBadge',
|
||||
complete,
|
||||
total,
|
||||
};
|
||||
}
|
||||
});
|
||||
client.writeQuery({
|
||||
@ -97,8 +272,23 @@ const Details: React.FC<DetailsProps> = ({
|
||||
...cacheData.findTask.checklists[idx].items,
|
||||
{ ...newTaskItem.data.createTaskChecklistItem },
|
||||
];
|
||||
console.log(draftState.checklists.map((item: any) => item.items));
|
||||
const { complete, total } = calculateChecklistBadge(draftState);
|
||||
if (!draftState.badges) {
|
||||
draftState.badges = {
|
||||
checklist: {},
|
||||
};
|
||||
}
|
||||
draftState.badges.checklist = {
|
||||
__typename: 'ChecklistBadge',
|
||||
complete,
|
||||
total,
|
||||
};
|
||||
console.log(draftState.badges.checklist);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(newData);
|
||||
client.writeQuery({
|
||||
query: FindTaskDocument,
|
||||
variables: { taskID },
|
||||
@ -156,11 +346,24 @@ const Details: React.FC<DetailsProps> = ({
|
||||
updateTaskChecklistItemName({ variables: { taskChecklistItemID: itemID, name: itemName } });
|
||||
}}
|
||||
onCloseModal={() => history.push(projectURL)}
|
||||
onChangeChecklistName={(checklistID, newName) => {
|
||||
updateTaskChecklistName({ variables: { taskChecklistID: checklistID, name: newName } });
|
||||
}}
|
||||
onDeleteItem={itemID => {
|
||||
deleteTaskChecklistItem({ variables: { taskChecklistItemID: itemID } });
|
||||
}}
|
||||
onToggleChecklistItem={(itemID, complete) => {
|
||||
setTaskChecklistItemComplete({ variables: { taskChecklistItemID: itemID, complete } });
|
||||
setTaskChecklistItemComplete({
|
||||
variables: { taskChecklistItemID: itemID, complete },
|
||||
optimisticResponse: {
|
||||
__typename: 'Mutation',
|
||||
setTaskChecklistItemComplete: {
|
||||
__typename: 'TaskChecklistItem',
|
||||
id: itemID,
|
||||
complete,
|
||||
},
|
||||
},
|
||||
});
|
||||
}}
|
||||
onAddItem={(taskChecklistID, name, position) => {
|
||||
createTaskChecklistItem({ variables: { taskChecklistID, name, position } });
|
||||
@ -202,6 +405,57 @@ const Details: React.FC<DetailsProps> = ({
|
||||
);
|
||||
}}
|
||||
onOpenAddLabelPopup={onOpenAddLabelPopup}
|
||||
onOpenAddChecklistPopup={(_task, $target) => {
|
||||
showPopup(
|
||||
$target,
|
||||
<Popup
|
||||
title={'Add checklist'}
|
||||
tab={0}
|
||||
onClose={() => {
|
||||
hidePopup();
|
||||
}}
|
||||
>
|
||||
<CreateChecklistPopup
|
||||
onCreateChecklist={checklistData => {
|
||||
let position = 65535;
|
||||
console.log(data.findTask.checklists);
|
||||
if (data.findTask.checklists) {
|
||||
const [lastChecklist] = data.findTask.checklists.slice(-1);
|
||||
console.log(`lastCheclist ${lastChecklist}`);
|
||||
if (lastChecklist) {
|
||||
position = lastChecklist.position * 2 + 1;
|
||||
}
|
||||
}
|
||||
createTaskChecklist({
|
||||
variables: {
|
||||
taskID: data.findTask.id,
|
||||
name: checklistData.name,
|
||||
position,
|
||||
},
|
||||
});
|
||||
hidePopup();
|
||||
}}
|
||||
/>
|
||||
</Popup>,
|
||||
);
|
||||
}}
|
||||
onDeleteChecklist={($target, checklistID) => {
|
||||
showPopup(
|
||||
$target,
|
||||
<Popup tab={0} title="Delete checklist?" onClose={() => hidePopup()}>
|
||||
<p>Deleting a checklist is permanent and there is no way to get it back.</p>
|
||||
<DeleteChecklistButton
|
||||
color="danger"
|
||||
onClick={() => {
|
||||
deleteTaskChecklist({ variables: { taskChecklistID: checklistID } });
|
||||
hidePopup();
|
||||
}}
|
||||
>
|
||||
Delete Checklist
|
||||
</DeleteChecklistButton>
|
||||
</Popup>,
|
||||
);
|
||||
}}
|
||||
onOpenDueDatePopop={(task, $targetRef) => {
|
||||
showPopup(
|
||||
$targetRef,
|
||||
|
@ -1,7 +1,9 @@
|
||||
import React, { useState, useRef, useContext, useEffect } from 'react';
|
||||
import GlobalTopNavbar from 'App/TopNavbar';
|
||||
import { MENU_TYPES } from 'shared/components/TopNavbar';
|
||||
import GlobalTopNavbar, { ProjectPopup } from 'App/TopNavbar';
|
||||
import styled from 'styled-components/macro';
|
||||
import { Bolt, ToggleOn, Tags } from 'shared/icons';
|
||||
import { DataProxy } from '@apollo/client';
|
||||
import { Bolt, ToggleOn, Tags, CheckCircle, Sort, Filter } from 'shared/icons';
|
||||
import { usePopup, Popup } from 'shared/components/PopupMenu';
|
||||
import { useParams, Route, useRouteMatch, useHistory, RouteComponentProps } from 'react-router-dom';
|
||||
import {
|
||||
@ -26,6 +28,7 @@ import {
|
||||
useCreateProjectLabelMutation,
|
||||
useUnassignTaskMutation,
|
||||
useUpdateTaskDueDateMutation,
|
||||
FindProjectQuery,
|
||||
} from 'shared/generated/graphql';
|
||||
|
||||
import TaskAssignee from 'shared/components/TaskAssignee';
|
||||
@ -42,11 +45,35 @@ import produce from 'immer';
|
||||
import MiniProfile from 'shared/components/MiniProfile';
|
||||
import Details from './Details';
|
||||
import { useApolloClient } from '@apollo/react-hooks';
|
||||
import { DocumentNode } from 'graphql';
|
||||
import UserIDContext from 'App/context';
|
||||
import DueDateManager from 'shared/components/DueDateManager';
|
||||
|
||||
type UpdateCacheFn<T> = (cache: T) => T;
|
||||
function updateApolloCache<T>(client: DataProxy, document: DocumentNode, update: UpdateCacheFn<T>, variables?: object) {
|
||||
let queryArgs: DataProxy.Query<any>;
|
||||
if (variables) {
|
||||
queryArgs = {
|
||||
query: document,
|
||||
variables,
|
||||
};
|
||||
} else {
|
||||
queryArgs = {
|
||||
query: document,
|
||||
};
|
||||
}
|
||||
const cache: T | null = client.readQuery(queryArgs);
|
||||
if (cache) {
|
||||
const newCache = update(cache);
|
||||
client.writeQuery({
|
||||
...queryArgs,
|
||||
data: newCache,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const getCacheData = (client: any, projectID: string) => {
|
||||
const cacheData: any = client.readQuery({
|
||||
const cacheData: FindProjectQuery = client.readQuery({
|
||||
query: FindProjectDocument,
|
||||
variables: {
|
||||
projectId: projectID,
|
||||
@ -220,7 +247,7 @@ const initialQuickCardEditorState: QuickCardEditorState = {
|
||||
const ProjectBar = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
justify-content: space-between;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
`;
|
||||
@ -302,13 +329,17 @@ const Project = () => {
|
||||
const [createTaskGroup] = useCreateTaskGroupMutation({
|
||||
onCompleted: newTaskGroupData => {},
|
||||
update: (client, newTaskGroupData) => {
|
||||
const cacheData = getCacheData(client, projectID);
|
||||
const newData = {
|
||||
...cacheData.findProject,
|
||||
taskGroups: [...cacheData.findProject.taskGroups, { ...newTaskGroupData.data.createTaskGroup, tasks: [] }],
|
||||
};
|
||||
|
||||
writeCacheData(client, projectID, cacheData, newData);
|
||||
updateApolloCache<FindProjectQuery>(
|
||||
client,
|
||||
FindProjectDocument,
|
||||
cache => {
|
||||
console.log(cache);
|
||||
return produce(cache, draftCache => {
|
||||
draftCache.findProject.taskGroups.push({ ...newTaskGroupData.data.createTaskGroup, tasks: [] });
|
||||
});
|
||||
},
|
||||
{ projectId: projectID },
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@ -316,7 +347,7 @@ const Project = () => {
|
||||
onCompleted: newTaskData => {},
|
||||
update: (client, newTaskData) => {
|
||||
const cacheData = getCacheData(client, projectID);
|
||||
const newTaskGroups = produce(cacheData.findProject.taskGroups, (draftState: any) => {
|
||||
const newTaskGroups = produce(cacheData.findProject.taskGroups, draftState => {
|
||||
const targetIndex = draftState.findIndex(
|
||||
(taskGroup: any) => taskGroup.id === newTaskData.data.createTask.taskGroup.id,
|
||||
);
|
||||
@ -388,14 +419,18 @@ const Project = () => {
|
||||
createTask: {
|
||||
__typename: 'Task',
|
||||
id: '' + Math.round(Math.random() * -1000000),
|
||||
name: name,
|
||||
name,
|
||||
complete: false,
|
||||
taskGroup: {
|
||||
__typename: 'TaskGroup',
|
||||
id: taskGroup.id,
|
||||
name: taskGroup.name,
|
||||
position: taskGroup.position,
|
||||
},
|
||||
position: position,
|
||||
badges: {
|
||||
checklist: null,
|
||||
},
|
||||
position,
|
||||
dueDate: null,
|
||||
description: null,
|
||||
labels: [],
|
||||
@ -509,11 +544,28 @@ const Project = () => {
|
||||
onSaveProjectName={projectName => {
|
||||
updateProjectName({ variables: { projectID, name: projectName } });
|
||||
}}
|
||||
popupContent={<ProjectPopup history={history} name={data.findProject.name} projectID={projectID} />}
|
||||
menuType={MENU_TYPES.PROJECT_MENU}
|
||||
initialTab={0}
|
||||
projectMembers={data.findProject.members}
|
||||
projectID={projectID}
|
||||
name={data.findProject.name}
|
||||
/>
|
||||
<ProjectBar>
|
||||
<ProjectActions>
|
||||
<ProjectAction>
|
||||
<CheckCircle width={13} height={13} />
|
||||
<ProjectActionText>All Tasks</ProjectActionText>
|
||||
</ProjectAction>
|
||||
<ProjectAction>
|
||||
<Filter width={13} height={13} />
|
||||
<ProjectActionText>Filter</ProjectActionText>
|
||||
</ProjectAction>
|
||||
<ProjectAction>
|
||||
<Sort width={13} height={13} />
|
||||
<ProjectActionText>Sort</ProjectActionText>
|
||||
</ProjectAction>
|
||||
</ProjectActions>
|
||||
<ProjectActions>
|
||||
<ProjectAction
|
||||
ref={$labelsRef}
|
||||
|
@ -137,6 +137,7 @@ const ProjectTileName = styled.div<{ centered?: boolean }>`
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
@ -146,10 +147,24 @@ const Wrapper = styled.div`
|
||||
const ProjectSectionTitleWrapper = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 32px;
|
||||
margin-bottom: 24px;
|
||||
padding: 8px 0;
|
||||
position: relative;
|
||||
margin-top: 16px;
|
||||
`;
|
||||
|
||||
const SectionActions = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const SectionAction = styled(Button)`
|
||||
padding: 6px 12px;
|
||||
`;
|
||||
const SectionActionLink = styled(Link)`
|
||||
margin-right: 8px;
|
||||
`;
|
||||
|
||||
const ProjectSectionTitle = styled.h3`
|
||||
@ -171,13 +186,19 @@ const ProjectGrid = styled.div`
|
||||
`;
|
||||
const AddTeamButton = styled(Button)`
|
||||
padding: 6px 12px;
|
||||
float: right;
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 12px;
|
||||
`;
|
||||
type ShowNewProject = {
|
||||
open: boolean;
|
||||
initialTeamID: null | string;
|
||||
};
|
||||
|
||||
const ProjectLink = styled(Link)``;
|
||||
|
||||
const Projects = () => {
|
||||
const { showPopup } = usePopup();
|
||||
const { showPopup, hidePopup } = usePopup();
|
||||
const { loading, data } = useGetProjectsQuery();
|
||||
useEffect(() => {
|
||||
document.title = 'Citadel';
|
||||
@ -202,9 +223,24 @@ const Projects = () => {
|
||||
});
|
||||
},
|
||||
});
|
||||
const [showNewProject, setShowNewProject] = useState(false);
|
||||
|
||||
const [showNewProject, setShowNewProject] = useState<ShowNewProject>({ open: false, initialTeamID: null });
|
||||
const { userID, setUserID } = useContext(UserIDContext);
|
||||
const [createTeam] = useCreateTeamMutation();
|
||||
const [createTeam] = useCreateTeamMutation({
|
||||
update: (client, createData) => {
|
||||
const cacheData: any = client.readQuery({
|
||||
query: GetProjectsDocument,
|
||||
});
|
||||
const newData = {
|
||||
...cacheData,
|
||||
teams: [...cacheData.teams, { ...createData.data.createTeam }],
|
||||
};
|
||||
client.writeQuery({
|
||||
query: GetProjectsDocument,
|
||||
data: newData,
|
||||
});
|
||||
},
|
||||
});
|
||||
if (loading) {
|
||||
return (
|
||||
<>
|
||||
@ -234,11 +270,18 @@ const Projects = () => {
|
||||
onClick={$target => {
|
||||
showPopup(
|
||||
$target,
|
||||
<Popup title="Create team" tab={0}>
|
||||
<Popup
|
||||
title="Create team"
|
||||
tab={0}
|
||||
onClose={() => {
|
||||
hidePopup();
|
||||
}}
|
||||
>
|
||||
<CreateTeamForm
|
||||
onCreateTeam={teamName => {
|
||||
if (organizationID) {
|
||||
createTeam({ variables: { name: teamName, organizationID } });
|
||||
hidePopup();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@ -253,6 +296,17 @@ const Projects = () => {
|
||||
<div key={team.id}>
|
||||
<ProjectSectionTitleWrapper>
|
||||
<ProjectSectionTitle>{team.name}</ProjectSectionTitle>
|
||||
<SectionActions>
|
||||
<SectionActionLink to={`/teams/${team.id}`}>
|
||||
<SectionAction variant="outline">Projects</SectionAction>
|
||||
</SectionActionLink>
|
||||
<SectionActionLink to="/">
|
||||
<SectionAction variant="outline">Members</SectionAction>
|
||||
</SectionActionLink>
|
||||
<SectionActionLink to="/">
|
||||
<SectionAction variant="outline">Settings</SectionAction>
|
||||
</SectionActionLink>
|
||||
</SectionActions>
|
||||
</ProjectSectionTitleWrapper>
|
||||
<ProjectList>
|
||||
{team.projects.map((project, idx) => (
|
||||
@ -268,7 +322,7 @@ const Projects = () => {
|
||||
<ProjectListItem>
|
||||
<ProjectAddTile
|
||||
onClick={() => {
|
||||
setShowNewProject(true);
|
||||
setShowNewProject({ open: true, initialTeamID: team.id });
|
||||
}}
|
||||
>
|
||||
<ProjectTileFade />
|
||||
@ -281,16 +335,17 @@ const Projects = () => {
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{showNewProject && (
|
||||
{showNewProject.open && (
|
||||
<NewProject
|
||||
initialTeamID={showNewProject.initialTeamID}
|
||||
onCreateProject={(name, teamID) => {
|
||||
if (userID) {
|
||||
createProject({ variables: { teamID, name, userID } });
|
||||
setShowNewProject(false);
|
||||
setShowNewProject({ open: false, initialTeamID: null });
|
||||
}
|
||||
}}
|
||||
onClose={() => {
|
||||
setShowNewProject(false);
|
||||
setShowNewProject({ open: false, initialTeamID: null });
|
||||
}}
|
||||
teams={teams}
|
||||
/>
|
||||
|
227
web/src/Teams/index.tsx
Normal file
227
web/src/Teams/index.tsx
Normal file
@ -0,0 +1,227 @@
|
||||
import React, { useState, useContext, useEffect } from 'react';
|
||||
import styled from 'styled-components/macro';
|
||||
import { MENU_TYPES } from 'shared/components/TopNavbar';
|
||||
import GlobalTopNavbar from 'App/TopNavbar';
|
||||
import { useGetTeamQuery, useDeleteTeamMutation, GetProjectsDocument } from 'shared/generated/graphql';
|
||||
import { useParams, useHistory } from 'react-router';
|
||||
import { usePopup, Popup } from 'shared/components/PopupMenu';
|
||||
import { History } from 'history';
|
||||
import produce from 'immer';
|
||||
import { TeamSettings, DeleteConfirm, DELETE_INFO } from 'shared/components/ProjectSettings';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const ProjectAddTile = styled.div`
|
||||
background-color: rgba(${props => props.theme.colors.bg.primary}, 0.4);
|
||||
background-size: cover;
|
||||
background-position: 50%;
|
||||
color: #fff;
|
||||
line-height: 20px;
|
||||
padding: 8px;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
|
||||
border-radius: 3px;
|
||||
display: block;
|
||||
`;
|
||||
|
||||
const ProjectTile = styled(Link)<{ color: string }>`
|
||||
background-color: ${props => props.color};
|
||||
background-size: cover;
|
||||
background-position: 50%;
|
||||
color: #fff;
|
||||
line-height: 20px;
|
||||
padding: 8px;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
|
||||
border-radius: 3px;
|
||||
display: block;
|
||||
`;
|
||||
|
||||
const ProjectTileFade = styled.div`
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
`;
|
||||
|
||||
const ProjectListItem = styled.li`
|
||||
width: 23.5%;
|
||||
padding: 0;
|
||||
margin: 0 2% 2% 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover ${ProjectTileFade} {
|
||||
background-color: rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
`;
|
||||
|
||||
const ProjectList = styled.ul`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
& ${ProjectListItem}:nth-of-type(4n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const ProjectTileDetails = styled.div`
|
||||
display: flex;
|
||||
height: 80px;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
`;
|
||||
|
||||
const ProjectAddTileDetails = styled.div`
|
||||
display: flex;
|
||||
height: 80px;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
const ProjectTileName = styled.div<{ centered?: boolean }>`
|
||||
flex: 0 0 auto;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
max-height: 40px;
|
||||
width: 100%;
|
||||
word-wrap: break-word;
|
||||
${props => props.centered && 'text-align: center;'}
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
type TeamPopupProps = {
|
||||
history: History<History.PoorMansUnknown>;
|
||||
name: string;
|
||||
teamID: string;
|
||||
};
|
||||
|
||||
export const TeamPopup: React.FC<TeamPopupProps> = ({ history, name, teamID }) => {
|
||||
const { hidePopup, setTab } = usePopup();
|
||||
const [deleteTeam] = useDeleteTeamMutation({
|
||||
update: (client, deleteData) => {
|
||||
const cacheData: any = client.readQuery({
|
||||
query: GetProjectsDocument,
|
||||
});
|
||||
|
||||
console.log(cacheData);
|
||||
console.log(deleteData);
|
||||
|
||||
const newData = produce(cacheData, (draftState: any) => {
|
||||
draftState.teams = draftState.teams.filter((team: any) => team.id !== deleteData.data.deleteTeam.team.id);
|
||||
draftState.projects = draftState.projects.filter(
|
||||
(project: any) => project.team.id !== deleteData.data.deleteTeam.team.id,
|
||||
);
|
||||
});
|
||||
|
||||
client.writeQuery({
|
||||
query: GetProjectsDocument,
|
||||
data: {
|
||||
...newData,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<Popup title={null} tab={0}>
|
||||
<TeamSettings
|
||||
onDeleteTeam={() => {
|
||||
setTab(1, 340);
|
||||
}}
|
||||
/>
|
||||
</Popup>
|
||||
<Popup title={`Delete the "${name}" team?`} tab={1} onClose={() => hidePopup()}>
|
||||
<DeleteConfirm
|
||||
description={DELETE_INFO.DELETE_TEAMS.description}
|
||||
deletedItems={DELETE_INFO.DELETE_TEAMS.deletedItems}
|
||||
onConfirmDelete={() => {
|
||||
if (teamID) {
|
||||
deleteTeam({ variables: { teamID } });
|
||||
hidePopup();
|
||||
history.push('/projects');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Popup>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ProjectsContainer = styled.div`
|
||||
margin: 40px 16px 0;
|
||||
width: 100%;
|
||||
max-width: 825px;
|
||||
min-width: 288px;
|
||||
`;
|
||||
|
||||
type TeamsRouteProps = {
|
||||
teamID: string;
|
||||
};
|
||||
|
||||
const colors = ['#e362e3', '#7a6ff0', '#37c5ab', '#aa62e3', '#e8384f'];
|
||||
const Projects = () => {
|
||||
const { teamID } = useParams<TeamsRouteProps>();
|
||||
const history = useHistory();
|
||||
const { loading, data } = useGetTeamQuery({ variables: { teamID } });
|
||||
useEffect(() => {
|
||||
document.title = 'Citadel | Teams';
|
||||
}, []);
|
||||
if (loading) {
|
||||
return (
|
||||
<>
|
||||
<span>loading</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (data) {
|
||||
return (
|
||||
<>
|
||||
<GlobalTopNavbar
|
||||
menuType={MENU_TYPES.TEAM_MENU}
|
||||
initialTab={0}
|
||||
popupContent={<TeamPopup history={history} name={data.findTeam.name} teamID={teamID} />}
|
||||
onSaveProjectName={() => {}}
|
||||
projectID={null}
|
||||
name={data.findTeam.name}
|
||||
/>
|
||||
<Wrapper>
|
||||
<ProjectsContainer>
|
||||
<ProjectList>
|
||||
{data.projects.map((project, idx) => (
|
||||
<ProjectListItem key={project.id}>
|
||||
<ProjectTile color={colors[idx % 5]} to={`/projects/${project.id}`}>
|
||||
<ProjectTileFade />
|
||||
<ProjectTileDetails>
|
||||
<ProjectTileName>{project.name}</ProjectTileName>
|
||||
</ProjectTileDetails>
|
||||
</ProjectTile>
|
||||
</ProjectListItem>
|
||||
))}
|
||||
</ProjectList>
|
||||
</ProjectsContainer>
|
||||
</Wrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return <div>Error!</div>;
|
||||
};
|
||||
|
||||
export default Projects;
|
9
web/src/citadel.d.ts
vendored
9
web/src/citadel.d.ts
vendored
@ -17,6 +17,15 @@ type ContextMenuEvent = {
|
||||
taskGroupID: string;
|
||||
};
|
||||
|
||||
type User = {
|
||||
id: string;
|
||||
fullName: string;
|
||||
username: string;
|
||||
email: string;
|
||||
role: string;
|
||||
profileIcon: ProfileIcon;
|
||||
};
|
||||
|
||||
type TaskUser = {
|
||||
id: string;
|
||||
fullName: string;
|
||||
|
10
web/src/projects.d.ts
vendored
10
web/src/projects.d.ts
vendored
@ -47,10 +47,20 @@ type TaskChecklistItem = {
|
||||
dueDate?: null | string;
|
||||
};
|
||||
|
||||
type ChecklistBadge = {
|
||||
complete: number;
|
||||
total: number;
|
||||
};
|
||||
|
||||
type TaskBadges = {
|
||||
checklist?: ChecklistBadge | null;
|
||||
};
|
||||
|
||||
type Task = {
|
||||
id: string;
|
||||
taskGroup: InnerTaskGroup;
|
||||
name: string;
|
||||
badges?: TaskBadges;
|
||||
position: number;
|
||||
dueDate?: string;
|
||||
complete?: boolean;
|
||||
|
@ -1,7 +1,10 @@
|
||||
import React, { useRef } from 'react';
|
||||
import Admin from '.';
|
||||
import { theme } from 'App/ThemeStyles';
|
||||
import NormalizeStyles from 'App/NormalizeStyles';
|
||||
import BaseStyles from 'App/BaseStyles';
|
||||
import { ThemeProvider } from 'styled-components';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
|
||||
export default {
|
||||
component: Admin,
|
||||
@ -19,7 +22,27 @@ export const Default = () => {
|
||||
<>
|
||||
<NormalizeStyles />
|
||||
<BaseStyles />
|
||||
<Admin />
|
||||
<ThemeProvider theme={theme}>
|
||||
<Admin
|
||||
onInviteUser={action('invite user')}
|
||||
initialTab={1}
|
||||
users={[
|
||||
{
|
||||
id: '1',
|
||||
username: 'jordanthedev',
|
||||
email: 'jordan@jordanthedev.com',
|
||||
role: 'Admin',
|
||||
fullName: 'Jordan Knott',
|
||||
profileIcon: {
|
||||
bgColor: '#fff',
|
||||
initials: 'JK',
|
||||
url: null,
|
||||
},
|
||||
},
|
||||
]}
|
||||
onAddUser={action('add user')}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,34 +1,28 @@
|
||||
import React, { useState, useRef } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { User, Plus } from 'shared/icons';
|
||||
import { User, Plus, Lock, Pencil, Trash } from 'shared/icons';
|
||||
import { AgGridReact } from 'ag-grid-react';
|
||||
|
||||
import 'ag-grid-community/dist/styles/ag-grid.css';
|
||||
import 'ag-grid-community/dist/styles/ag-theme-material.css';
|
||||
import Button from 'shared/components/Button';
|
||||
|
||||
const NewUserButton = styled.button`
|
||||
outline: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
line-height: 20px;
|
||||
padding: 0.75rem;
|
||||
background-color: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(115, 103, 240);
|
||||
font-size: 14px;
|
||||
|
||||
border-radius: 0.5rem;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
border-image: initial;
|
||||
border-color: rgba(115, 103, 240);
|
||||
span {
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
const NewUserButton = styled(Button)`
|
||||
padding: 6px 12px;
|
||||
margin-right: 12px;
|
||||
`;
|
||||
|
||||
const InviteUserButton = styled(Button)`
|
||||
padding: 6px 12px;
|
||||
margin-right: 8px;
|
||||
`;
|
||||
|
||||
const MemberActions = styled.div`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const GridTable = styled.div`
|
||||
height: 620px;
|
||||
`;
|
||||
@ -93,8 +87,29 @@ const Header = styled.div`
|
||||
min-height: 112px;
|
||||
`;
|
||||
|
||||
const ActionButtonsContainer = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const EditUserIcon = styled(Pencil)`
|
||||
margin-right: 8px;
|
||||
`;
|
||||
|
||||
const LockUserIcon = styled(Lock)`
|
||||
margin-right: 8px;
|
||||
`;
|
||||
|
||||
const DeleteUserIcon = styled(Trash)``;
|
||||
|
||||
const ActionButtons = () => {
|
||||
return <span>Hello!</span>;
|
||||
return (
|
||||
<>
|
||||
<EditUserIcon width={16} height={16} />
|
||||
<LockUserIcon width={16} height={16} />
|
||||
<DeleteUserIcon width={16} height={16} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
const data = {
|
||||
defaultColDef: {
|
||||
@ -103,16 +118,14 @@ const data = {
|
||||
},
|
||||
columnDefs: [
|
||||
{
|
||||
minWidth: 125,
|
||||
width: 125,
|
||||
minWidth: 55,
|
||||
width: 55,
|
||||
headerCheckboxSelection: true,
|
||||
checkboxSelection: true,
|
||||
headerName: 'ID',
|
||||
field: 'id',
|
||||
},
|
||||
{ minWidth: 210, headerName: 'Username', editable: true, field: 'username' },
|
||||
{ minWidth: 225, headerName: 'Email', field: 'email' },
|
||||
{ minWidth: 200, headerName: 'Name', editable: true, field: 'full_name' },
|
||||
{ minWidth: 200, headerName: 'Name', editable: true, field: 'fullName' },
|
||||
{ minWidth: 200, headerName: 'Role', editable: true, field: 'role' },
|
||||
{
|
||||
minWidth: 200,
|
||||
@ -123,14 +136,13 @@ const data = {
|
||||
frameworkComponents: {
|
||||
actionButtons: ActionButtons,
|
||||
},
|
||||
rowData: [
|
||||
{ id: '1', full_name: 'Jordan Knott', username: 'jordan', email: 'jordan@jordanthedev.com', role: 'Admin' },
|
||||
{ id: '2', full_name: 'Jordan Test', username: 'jordantest', email: 'jordan@jordanthedev.com', role: 'Admin' },
|
||||
{ id: '3', full_name: 'Jordan Other', username: 'alphatest1050', email: 'jordan@jordanthedev.com', role: 'Admin' },
|
||||
{ id: '5', full_name: 'Jordan French', username: 'other', email: 'jordan@jordanthedev.com', role: 'Admin' },
|
||||
],
|
||||
};
|
||||
const ListTable = () => {
|
||||
|
||||
type ListTableProps = {
|
||||
users: Array<User>;
|
||||
};
|
||||
|
||||
const ListTable: React.FC<ListTableProps> = ({ users }) => {
|
||||
return (
|
||||
<Root>
|
||||
<div className="ag-theme-material" style={{ height: '296px', width: '100%' }}>
|
||||
@ -138,7 +150,7 @@ const ListTable = () => {
|
||||
rowSelection="multiple"
|
||||
defaultColDef={data.defaultColDef}
|
||||
columnDefs={data.columnDefs}
|
||||
rowData={data.rowData}
|
||||
rowData={users}
|
||||
frameworkComponents={data.frameworkComponents}
|
||||
onFirstDataRendered={params => {
|
||||
params.api.sizeColumnsToFit();
|
||||
@ -146,7 +158,7 @@ const ListTable = () => {
|
||||
onGridSizeChanged={params => {
|
||||
params.api.sizeColumnsToFit();
|
||||
}}
|
||||
></AgGridReact>
|
||||
/>
|
||||
</div>
|
||||
</Root>
|
||||
);
|
||||
@ -184,6 +196,7 @@ const TabNavContent = styled.ul`
|
||||
|
||||
const TabNavItem = styled.li`
|
||||
padding: 0.35rem 0.3rem;
|
||||
height: 48px;
|
||||
display: block;
|
||||
position: relative;
|
||||
`;
|
||||
@ -282,9 +295,16 @@ const NavItem: React.FC<NavItemProps> = ({ active, name, tab, onClick }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const Admin = () => {
|
||||
const [currentTop, setTop] = useState(0);
|
||||
const [currentTab, setTab] = useState(0);
|
||||
type AdminProps = {
|
||||
initialTab: number;
|
||||
onAddUser: ($target: React.RefObject<HTMLElement>) => void;
|
||||
onInviteUser: ($target: React.RefObject<HTMLElement>) => void;
|
||||
users: Array<User>;
|
||||
};
|
||||
|
||||
const Admin: React.FC<AdminProps> = ({ initialTab, onAddUser, onInviteUser, users }) => {
|
||||
const [currentTop, setTop] = useState(initialTab * 48);
|
||||
const [currentTab, setTab] = useState(initialTab);
|
||||
const $tabNav = useRef<HTMLDivElement>(null);
|
||||
return (
|
||||
<Container>
|
||||
@ -309,11 +329,17 @@ const Admin = () => {
|
||||
</TabNav>
|
||||
<TabContentWrapper>
|
||||
<TabContent>
|
||||
<NewUserButton>
|
||||
<MemberActions>
|
||||
<NewUserButton variant="outline" onClick={onAddUser}>
|
||||
<Plus color="rgba(115, 103, 240)" size={10} />
|
||||
<span>Add New</span>
|
||||
<span style={{ paddingLeft: '5px' }}>Create member</span>
|
||||
</NewUserButton>
|
||||
<ListTable />
|
||||
<InviteUserButton variant="outline" onClick={onInviteUser}>
|
||||
<Plus color="rgba(115, 103, 240)" size={10} />
|
||||
<span style={{ paddingLeft: '5px' }}>Invite member</span>
|
||||
</InviteUserButton>
|
||||
</MemberActions>
|
||||
<ListTable users={users} />
|
||||
</TabContent>
|
||||
</TabContentWrapper>
|
||||
</Container>
|
||||
|
@ -42,7 +42,7 @@ type Props = {
|
||||
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
||||
description?: null | string;
|
||||
dueDate?: DueDate;
|
||||
checklists?: Checklist;
|
||||
checklists?: Checklist | null;
|
||||
labels?: Array<ProjectLabel>;
|
||||
watched?: boolean;
|
||||
wrapperProps?: any;
|
||||
|
@ -501,7 +501,7 @@ const ChecklistTitleEditor = React.forwardRef(
|
||||
);
|
||||
type ChecklistProps = {
|
||||
checklistID: string;
|
||||
onDeleteChecklist: (checklistID: string) => void;
|
||||
onDeleteChecklist: ($target: React.RefObject<HTMLElement>, checklistID: string) => void;
|
||||
name: string;
|
||||
onChangeName: (item: string) => void;
|
||||
onToggleItem: (taskID: string, complete: boolean) => void;
|
||||
@ -554,8 +554,8 @@ const Checklist: React.FC<ChecklistProps> = ({
|
||||
<WindowTitleText onClick={() => setEditting(true)}>{name}</WindowTitleText>
|
||||
<WindowOptions>
|
||||
<DeleteButton
|
||||
onClick={() => {
|
||||
onDeleteChecklist(checklistID);
|
||||
onClick={$target => {
|
||||
onDeleteChecklist($target, checklistID);
|
||||
}}
|
||||
color="danger"
|
||||
variant="outline"
|
||||
|
@ -51,6 +51,7 @@ export const Default = () => {
|
||||
</Container>
|
||||
{menu.isOpen && (
|
||||
<DropdownMenu
|
||||
onAdminConsole={action('admin')}
|
||||
onCloseDropdown={() => {
|
||||
setMenu({ top: 0, left: 0, isOpen: false });
|
||||
}}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useRef } from 'react';
|
||||
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
||||
import { Exit, User } from 'shared/icons';
|
||||
import { Exit, User, Cog } from 'shared/icons';
|
||||
import { Separator, Container, WrapperDiamond, Wrapper, ActionsList, ActionItem, ActionTitle } from './Styles';
|
||||
|
||||
type DropdownMenuProps = {
|
||||
@ -8,15 +8,16 @@ type DropdownMenuProps = {
|
||||
top: number;
|
||||
onLogout: () => void;
|
||||
onCloseDropdown: () => void;
|
||||
onAdminConsole: () => void;
|
||||
};
|
||||
|
||||
const DropdownMenu: React.FC<DropdownMenuProps> = ({ left, top, onLogout, onCloseDropdown }) => {
|
||||
const DropdownMenu: React.FC<DropdownMenuProps> = ({ left, top, onLogout, onCloseDropdown, onAdminConsole }) => {
|
||||
const $containerRef = useRef<HTMLDivElement>(null);
|
||||
useOnOutsideClick($containerRef, true, onCloseDropdown, null);
|
||||
return (
|
||||
<Container ref={$containerRef} left={left} top={top}>
|
||||
<Wrapper>
|
||||
<ActionItem>
|
||||
<ActionItem onClick={onAdminConsole}>
|
||||
<User size={16} color="#c2c6dc" />
|
||||
<ActionTitle>Profile</ActionTitle>
|
||||
</ActionItem>
|
||||
@ -36,16 +37,21 @@ const DropdownMenu: React.FC<DropdownMenuProps> = ({ left, top, onLogout, onClos
|
||||
type ProfileMenuProps = {
|
||||
onProfile: () => void;
|
||||
onLogout: () => void;
|
||||
onAdminConsole: () => void;
|
||||
};
|
||||
|
||||
const ProfileMenu: React.FC<ProfileMenuProps> = ({ onProfile, onLogout }) => {
|
||||
const ProfileMenu: React.FC<ProfileMenuProps> = ({ onAdminConsole, onProfile, onLogout }) => {
|
||||
return (
|
||||
<>
|
||||
<ActionItem onClick={onAdminConsole}>
|
||||
<Cog size={16} color="#c2c6dc" />
|
||||
<ActionTitle>Admin Console</ActionTitle>
|
||||
</ActionItem>
|
||||
<Separator />
|
||||
<ActionItem onClick={onProfile}>
|
||||
<User size={16} color="#c2c6dc" />
|
||||
<ActionTitle>Profile</ActionTitle>
|
||||
</ActionItem>
|
||||
<Separator />
|
||||
<ActionsList>
|
||||
<ActionItem onClick={onLogout}>
|
||||
<Exit size={16} color="#c2c6dc" />
|
||||
|
@ -80,8 +80,10 @@ type InputProps = {
|
||||
variant?: 'normal' | 'alternate';
|
||||
label?: string;
|
||||
width?: string;
|
||||
floatingLabel?: boolean;
|
||||
placeholder?: string;
|
||||
icon?: JSX.Element;
|
||||
autocomplete?: boolean;
|
||||
id?: string;
|
||||
name?: string;
|
||||
className?: string;
|
||||
@ -95,6 +97,7 @@ const Input = React.forwardRef(
|
||||
{
|
||||
width = 'auto',
|
||||
variant = 'normal',
|
||||
autocomplete,
|
||||
label,
|
||||
placeholder,
|
||||
icon,
|
||||
@ -102,6 +105,7 @@ const Input = React.forwardRef(
|
||||
onChange,
|
||||
className,
|
||||
onClick,
|
||||
floatingLabel,
|
||||
value: initialValue,
|
||||
id,
|
||||
}: InputProps,
|
||||
@ -124,12 +128,13 @@ const Input = React.forwardRef(
|
||||
return (
|
||||
<InputWrapper className={className} width={width}>
|
||||
<InputInput
|
||||
hasValue={value !== ''}
|
||||
hasValue={floatingLabel || value !== ''}
|
||||
ref={$ref}
|
||||
id={id}
|
||||
name={name}
|
||||
onClick={onClick}
|
||||
onChange={handleChange}
|
||||
autoComplete={autocomplete ? 'on' : 'off'}
|
||||
value={value}
|
||||
hasIcon={typeof icon !== 'undefined'}
|
||||
width={width}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const Container = styled.div`
|
||||
flex: 1;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
margin-bottom: 8px;
|
||||
|
@ -181,6 +181,7 @@ const SimpleLists: React.FC<SimpleProps> = ({
|
||||
onClick={() => {
|
||||
onTaskClick(task);
|
||||
}}
|
||||
checklists={task.badges && task.badges.checklist}
|
||||
onCardMemberClick={onCardMemberClick}
|
||||
onContextMenu={onQuickEditorOpen}
|
||||
/>
|
||||
|
@ -38,7 +38,7 @@ const Login = ({ onSubmit }: LoginProps) => {
|
||||
<LoginFormWrapper>
|
||||
<LoginFormContainer>
|
||||
<LogoWrapper>
|
||||
<Citadel size={42} />
|
||||
<Citadel width={42} height={42} />
|
||||
<LogoTitle>Citadel</LogoTitle>
|
||||
</LogoWrapper>
|
||||
<Title>Login</Title>
|
||||
@ -66,7 +66,7 @@ const Login = ({ onSubmit }: LoginProps) => {
|
||||
ref={register({ required: 'Password is required' })}
|
||||
/>
|
||||
<FormIcon>
|
||||
<Lock color="#c2c6dc" size={20} />
|
||||
<Lock width={20} height={20} />
|
||||
</FormIcon>
|
||||
</FormLabel>
|
||||
{errors.password && <FormError>{errors.password.message}</FormError>}
|
||||
|
@ -28,10 +28,10 @@ export const Default = () => {
|
||||
<PrimaryLogo />
|
||||
<ButtonContainer>
|
||||
<ActionButton name="Home">
|
||||
<Home size={28} color="#c2c6dc" />
|
||||
<Home width={28} height={28} />
|
||||
</ActionButton>
|
||||
<ActionButton name="Home">
|
||||
<Home size={28} color="#c2c6dc" />
|
||||
<Home width={28} height={28} />
|
||||
</ActionButton>
|
||||
</ButtonContainer>
|
||||
</Navbar>
|
||||
|
@ -35,7 +35,7 @@ export const ButtonContainer: React.FC = ({ children }) => (
|
||||
export const PrimaryLogo = () => {
|
||||
return (
|
||||
<LogoWrapper>
|
||||
<Citadel size={42} />
|
||||
<Citadel width={42} height={42} />
|
||||
<LogoTitle>Citadel</LogoTitle>
|
||||
</LogoWrapper>
|
||||
);
|
||||
|
@ -23,6 +23,7 @@ export const Default = () => {
|
||||
<NormalizeStyles />
|
||||
<BaseStyles />
|
||||
<NewProject
|
||||
initialTeamID={null}
|
||||
onCreateProject={action('create project')}
|
||||
teams={[{ name: 'General', id: 'general', createdAt: '' }]}
|
||||
onClose={() => {}}
|
||||
|
@ -207,14 +207,15 @@ const CreateButton = styled.button`
|
||||
}
|
||||
`;
|
||||
type NewProjectProps = {
|
||||
initialTeamID: string | null;
|
||||
teams: Array<Team>;
|
||||
onClose: () => void;
|
||||
onCreateProject: (projectName: string, teamID: string) => void;
|
||||
};
|
||||
|
||||
const NewProject: React.FC<NewProjectProps> = ({ teams, onClose, onCreateProject }) => {
|
||||
const NewProject: React.FC<NewProjectProps> = ({ initialTeamID, teams, onClose, onCreateProject }) => {
|
||||
const [projectName, setProjectName] = useState('');
|
||||
const [team, setTeam] = useState<null | string>(null);
|
||||
const [team, setTeam] = useState<null | string>(initialTeamID);
|
||||
const options = teams.map(t => ({ label: t.name, value: t.id }));
|
||||
return (
|
||||
<Overlay>
|
||||
|
@ -58,7 +58,7 @@ const LabelManager: React.FC<Props> = ({ labels, taskLabels, onLabelToggle, onLa
|
||||
onLabelEdit(label.id);
|
||||
}}
|
||||
>
|
||||
<Pencil color="#c2c6dc" />
|
||||
<Pencil width={16} height={16} />
|
||||
</LabelIcon>
|
||||
<CardLabel
|
||||
key={label.id}
|
||||
|
@ -42,7 +42,6 @@ export const HeaderTitle = styled.span`
|
||||
box-sizing: border-box;
|
||||
color: #c2c6dc;
|
||||
display: block;
|
||||
line-height: 40px;
|
||||
border-bottom: 1px solid #414561;
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
@ -51,6 +50,13 @@ export const HeaderTitle = styled.span`
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
|
||||
height: 40px;
|
||||
line-height: 18px;
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
export const Content = styled.div`
|
||||
@ -138,7 +144,7 @@ export const CardLabel = styled.span<{ active: boolean; color: string }>`
|
||||
`;
|
||||
|
||||
export const CloseButton = styled.div`
|
||||
padding: 10px 12px 10px 8px;
|
||||
padding: 18px 18px 14px 12px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
@ -312,7 +318,7 @@ export const CreateLabelButton = styled.button`
|
||||
`;
|
||||
|
||||
export const PreviousButton = styled.div`
|
||||
padding: 10px 12px 10px 8px;
|
||||
padding: 18px 18px 14px 12px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
@ -2,7 +2,6 @@ import React, { useRef } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const Container = styled.div<{ size: number | string; bgColor: string | null; backgroundURL: string | null }>`
|
||||
margin-left: 10px;
|
||||
width: ${props => props.size}px;
|
||||
height: ${props => props.size}px;
|
||||
border-radius: 9999px;
|
||||
|
@ -52,6 +52,21 @@ const ProjectSettings: React.FC<Props> = ({ onDeleteProject }) => {
|
||||
);
|
||||
};
|
||||
|
||||
type TeamSettingsProps = {
|
||||
onDeleteTeam: () => void;
|
||||
};
|
||||
export const TeamSettings: React.FC<TeamSettingsProps> = ({ onDeleteTeam }) => {
|
||||
return (
|
||||
<>
|
||||
<ListActionsWrapper>
|
||||
<ListActionItemWrapper onClick={() => onDeleteTeam()}>
|
||||
<ListActionItem>Delete Team</ListActionItem>
|
||||
</ListActionItemWrapper>
|
||||
</ListActionsWrapper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ConfirmWrapper = styled.div``;
|
||||
|
||||
const ConfirmSubTitle = styled.h3`
|
||||
@ -76,25 +91,40 @@ const ConfirmDeleteButton = styled(Button)`
|
||||
padding: 6px 12px;
|
||||
`;
|
||||
|
||||
type DeleteProjectProps = {
|
||||
name: string;
|
||||
onDeleteProject: () => void;
|
||||
type DeleteConfirmProps = {
|
||||
description: string;
|
||||
deletedItems: Array<string>;
|
||||
onConfirmDelete: () => void;
|
||||
};
|
||||
const DeleteProject: React.FC<DeleteProjectProps> = ({ name, onDeleteProject }) => {
|
||||
|
||||
export const DELETE_INFO = {
|
||||
DELETE_PROJECTS: {
|
||||
description: 'Deleting the project will also delete the following:',
|
||||
deletedItems: ['Task groups and tasks'],
|
||||
},
|
||||
DELETE_TEAMS: {
|
||||
description: 'Deleting the team will also delete the following:',
|
||||
deletedItems: ['Projects under the team', 'All task groups & tasks associated with the team projects'],
|
||||
},
|
||||
};
|
||||
|
||||
const DeleteConfirm: React.FC<DeleteConfirmProps> = ({ description, deletedItems, onConfirmDelete }) => {
|
||||
return (
|
||||
<ConfirmWrapper>
|
||||
<ConfirmDescription>
|
||||
Deleting the project will also delete the following:
|
||||
{description}
|
||||
<DeleteList>
|
||||
<DeleteListItem>Task groups and tasks</DeleteListItem>
|
||||
{deletedItems.map(item => (
|
||||
<DeleteListItem>{item}</DeleteListItem>
|
||||
))}
|
||||
</DeleteList>
|
||||
</ConfirmDescription>
|
||||
<ConfirmDeleteButton onClick={() => onDeleteProject()} color="danger">
|
||||
<ConfirmDeleteButton onClick={() => onConfirmDelete()} color="danger">
|
||||
Delete
|
||||
</ConfirmDeleteButton>
|
||||
</ConfirmWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export { DeleteProject };
|
||||
export { DeleteConfirm };
|
||||
export default ProjectSettings;
|
||||
|
@ -71,6 +71,9 @@ export const Default = () => {
|
||||
onToggleTaskComplete={action('toggle task complete')}
|
||||
onToggleChecklistItem={action('toggle checklist item')}
|
||||
onOpenAddLabelPopup={action('open add label popup')}
|
||||
onChangeChecklistName={action('change checklist name')}
|
||||
onDeleteChecklist={action('delete checklist')}
|
||||
onOpenAddChecklistPopup={action(' open checklist')}
|
||||
onOpenDueDatePopop={action('open due date popup')}
|
||||
/>
|
||||
);
|
||||
|
@ -140,13 +140,19 @@ type TaskDetailsProps = {
|
||||
onOpenAddMemberPopup: (task: Task, $targetRef: React.RefObject<HTMLElement>) => void;
|
||||
onOpenAddLabelPopup: (task: Task, $targetRef: React.RefObject<HTMLElement>) => void;
|
||||
onOpenDueDatePopop: (task: Task, $targetRef: React.RefObject<HTMLElement>) => void;
|
||||
onOpenAddChecklistPopup: (task: Task, $targetRef: React.RefObject<HTMLElement>) => void;
|
||||
onMemberProfile: ($targetRef: React.RefObject<HTMLElement>, memberID: string) => void;
|
||||
onChangeChecklistName: (checklistID: string, name: string) => void;
|
||||
onDeleteChecklist: ($target: React.RefObject<HTMLElement>, checklistID: string) => void;
|
||||
onCloseModal: () => void;
|
||||
};
|
||||
|
||||
const TaskDetails: React.FC<TaskDetailsProps> = ({
|
||||
task,
|
||||
onDeleteChecklist,
|
||||
onTaskNameChange,
|
||||
onOpenAddChecklistPopup,
|
||||
onChangeChecklistName,
|
||||
onToggleTaskComplete,
|
||||
onTaskDescriptionChange,
|
||||
onChangeItemName,
|
||||
@ -183,6 +189,9 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
||||
const onAddMember = ($target: React.RefObject<HTMLElement>) => {
|
||||
onOpenAddMemberPopup(task, $target);
|
||||
};
|
||||
const onAddChecklist = ($target: React.RefObject<HTMLElement>) => {
|
||||
onOpenAddChecklistPopup(task, $target)
|
||||
}
|
||||
const $dueDateLabel = useRef<HTMLDivElement>(null);
|
||||
const $addLabelRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@ -290,16 +299,16 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
||||
name={checklist.name}
|
||||
checklistID={checklist.id}
|
||||
items={checklist.items}
|
||||
onDeleteChecklist={() => {}}
|
||||
onChangeName={() => {}}
|
||||
onDeleteChecklist={onDeleteChecklist}
|
||||
onChangeName={newName => onChangeChecklistName(checklist.id, newName)}
|
||||
onToggleItem={onToggleChecklistItem}
|
||||
onDeleteItem={onDeleteItem}
|
||||
onAddItem={n => {
|
||||
if (task.checklists) {
|
||||
let position = 1;
|
||||
const lastChecklist = task.checklists.sort((a, b) => a.position - b.position)[-1];
|
||||
if (lastChecklist) {
|
||||
position = lastChecklist.position * 2 + 1;
|
||||
let position = 65535;
|
||||
const [lastItem] = checklist.items.sort((a, b) => a.position - b.position).slice(-1);
|
||||
if (lastItem) {
|
||||
position = lastItem.position * 2 + 1;
|
||||
}
|
||||
onAddItem(checklist.id, n, position);
|
||||
}
|
||||
@ -317,7 +326,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
||||
</ActionButton>
|
||||
<ActionButton onClick={$target => onAddMember($target)}>Members</ActionButton>
|
||||
<ActionButton onClick={$target => onAddLabel($target)}>Labels</ActionButton>
|
||||
<ActionButton>Checklist</ActionButton>
|
||||
<ActionButton onClick={$target => onAddChecklist($target)}>Checklist</ActionButton>
|
||||
<ActionButton onClick={$target => onOpenDueDatePopop(task, $target)}>Due Date</ActionButton>
|
||||
<ActionButton>Attachment</ActionButton>
|
||||
<ActionButton>Cover</ActionButton>
|
||||
|
@ -2,6 +2,8 @@ import styled, { css } from 'styled-components';
|
||||
import TextareaAutosize from 'react-autosize-textarea';
|
||||
import { mixin } from 'shared/utils/styles';
|
||||
import Button from 'shared/components/Button';
|
||||
import { Citadel } from 'shared/icons';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export const NavbarWrapper = styled.div`
|
||||
width: 100%;
|
||||
@ -9,7 +11,6 @@ export const NavbarWrapper = styled.div`
|
||||
|
||||
export const ProjectMembers = styled.div`
|
||||
display: flex;
|
||||
padding-right: 18px;
|
||||
align-items: center;
|
||||
`;
|
||||
export const NavbarHeader = styled.header`
|
||||
@ -34,9 +35,9 @@ export const BreadcrumpSeparator = styled.span`
|
||||
`;
|
||||
|
||||
export const ProjectActions = styled.div`
|
||||
flex: 1;
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
min-width: 1px;
|
||||
`;
|
||||
@ -56,10 +57,11 @@ export const ProfileNameWrapper = styled.div`
|
||||
line-height: 1.25;
|
||||
`;
|
||||
|
||||
export const NotificationContainer = styled.div`
|
||||
export const IconContainer = styled.div`
|
||||
margin-right: 20px;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
export const ProfileNamePrimary = styled.div`
|
||||
color: #c2c6dc;
|
||||
font-weight: 600;
|
||||
@ -70,7 +72,6 @@ export const ProfileNameSecondary = styled.small`
|
||||
`;
|
||||
|
||||
export const ProfileIcon = styled.div<{ bgColor: string | null; backgroundURL: string | null }>`
|
||||
margin-left: 10px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 9999px;
|
||||
@ -84,9 +85,9 @@ export const ProfileIcon = styled.div<{ bgColor: string | null; backgroundURL: s
|
||||
background-size: contain;
|
||||
`;
|
||||
|
||||
export const ProjectMeta = styled.div`
|
||||
export const ProjectMeta = styled.div<{ nameOnly?: boolean }>`
|
||||
display: flex;
|
||||
padding-top: 9px;
|
||||
${props => !props.nameOnly && 'padding-top: 9px;'}
|
||||
margin-left: -14px;
|
||||
align-items: center;
|
||||
max-width: 100%;
|
||||
@ -188,7 +189,7 @@ export const ProjectSwitcher = styled.button`
|
||||
|
||||
export const Separator = styled.div`
|
||||
color: #c2c6dc;
|
||||
font-size: 16px;
|
||||
font-size: 20px;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
`;
|
||||
@ -214,3 +215,36 @@ export const InviteButton = styled(Button)`
|
||||
margin: 0 0 0 8px;
|
||||
padding: 6px 12px;
|
||||
`;
|
||||
|
||||
export const ProjectFinder = styled(Button)`
|
||||
margin-right: 20px;
|
||||
padding: 6px 12px;
|
||||
`;
|
||||
|
||||
export const NavSeparator = styled.div`
|
||||
width: 1px;
|
||||
background: rgba(${props => props.theme.colors.border});
|
||||
height: 34px;
|
||||
margin: 0 20px;
|
||||
`;
|
||||
|
||||
export const LogoContainer = styled(Link)`
|
||||
display: block;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
export const CitadelTitle = styled.h2`
|
||||
margin-left: 5px;
|
||||
color: rgba(${props => props.theme.colors.text.primary});
|
||||
font-size: 20px;
|
||||
`;
|
||||
|
||||
export const CitadelLogo = styled(Citadel)`
|
||||
fill: rgba(${props => props.theme.colors.text.primary});
|
||||
stroke: rgba(${props => props.theme.colors.text.primary});
|
||||
`;
|
||||
|
@ -26,7 +26,8 @@ export const Default = () => {
|
||||
<NormalizeStyles />
|
||||
<BaseStyles />
|
||||
<TopNavbar
|
||||
projectName="Projects"
|
||||
onOpenProjectFinder={action('finder')}
|
||||
name="Projects"
|
||||
user={{
|
||||
id: '1',
|
||||
fullName: 'Jordan Knott',
|
||||
@ -38,6 +39,7 @@ export const Default = () => {
|
||||
}}
|
||||
onNotificationClick={action('notifications click')}
|
||||
onOpenSettings={action('open settings')}
|
||||
onDashboardClick={action('open dashboard')}
|
||||
onProfileClick={action('profile click')}
|
||||
/>
|
||||
</>
|
||||
|
@ -1,22 +1,27 @@
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import { Star, Ellipsis, Bell, Cog, AngleDown } from 'shared/icons';
|
||||
import { Home, Star, Bell, AngleDown, BarChart, CheckCircle } from 'shared/icons';
|
||||
import styled from 'styled-components';
|
||||
import ProfileIcon from 'shared/components/ProfileIcon';
|
||||
import TaskAssignee from 'shared/components/TaskAssignee';
|
||||
import { usePopup, Popup } from 'shared/components/PopupMenu';
|
||||
import MiniProfile from 'shared/components/MiniProfile';
|
||||
import {
|
||||
NotificationContainer,
|
||||
CitadelLogo,
|
||||
CitadelTitle,
|
||||
ProjectFinder,
|
||||
LogoContainer,
|
||||
NavSeparator,
|
||||
IconContainer,
|
||||
ProjectNameTextarea,
|
||||
InviteButton,
|
||||
GlobalActions,
|
||||
ProjectActions,
|
||||
ProjectSwitcher,
|
||||
Separator,
|
||||
ProjectMeta,
|
||||
ProjectName,
|
||||
ProjectTabs,
|
||||
ProjectTab,
|
||||
NavbarWrapper,
|
||||
NavbarHeader,
|
||||
Breadcrumbs,
|
||||
BreadcrumpSeparator,
|
||||
ProjectSettingsButton,
|
||||
ProfileContainer,
|
||||
ProfileNameWrapper,
|
||||
@ -24,18 +29,20 @@ import {
|
||||
ProfileNameSecondary,
|
||||
ProjectMembers,
|
||||
} from './Styles';
|
||||
import TaskAssignee from 'shared/components/TaskAssignee';
|
||||
import { usePopup, Popup } from 'shared/components/PopupMenu';
|
||||
import MiniProfile from 'shared/components/MiniProfile';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const HomeDashboard = styled(Home)``;
|
||||
|
||||
type ProjectHeadingProps = {
|
||||
projectName: string;
|
||||
onFavorite?: () => void;
|
||||
name: string;
|
||||
onSaveProjectName?: (projectName: string) => void;
|
||||
onOpenSettings: ($target: React.RefObject<HTMLElement>) => void;
|
||||
};
|
||||
|
||||
const ProjectHeading: React.FC<ProjectHeadingProps> = ({
|
||||
projectName: initialProjectName,
|
||||
onFavorite,
|
||||
name: initialProjectName,
|
||||
onSaveProjectName,
|
||||
onOpenSettings,
|
||||
}) => {
|
||||
@ -73,7 +80,6 @@ const ProjectHeading: React.FC<ProjectHeadingProps> = ({
|
||||
const $settings = useRef<HTMLButtonElement>(null);
|
||||
return (
|
||||
<>
|
||||
<Separator>»</Separator>
|
||||
{isEditProjectName ? (
|
||||
<ProjectNameTextarea
|
||||
ref={$projectName}
|
||||
@ -100,28 +106,54 @@ const ProjectHeading: React.FC<ProjectHeadingProps> = ({
|
||||
>
|
||||
<AngleDown color="#c2c6dc" />
|
||||
</ProjectSettingsButton>
|
||||
<ProjectSettingsButton>
|
||||
{onFavorite && (
|
||||
<ProjectSettingsButton onClick={() => onFavorite()}>
|
||||
<Star width={16} height={16} color="#c2c6dc" />
|
||||
</ProjectSettingsButton>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
type MenuType = {
|
||||
[key: number]: string;
|
||||
};
|
||||
type MenuTypes = {
|
||||
[key: string]: Array<string>;
|
||||
};
|
||||
|
||||
export const MENU_TYPES: MenuTypes = {
|
||||
PROJECT_MENU: ['Board', 'Timeline', 'Calender'],
|
||||
TEAM_MENU: ['Projects', 'Members', 'Settings'],
|
||||
};
|
||||
|
||||
type NavBarProps = {
|
||||
projectName: string | null;
|
||||
menuType?: Array<string> | null;
|
||||
name: string | null;
|
||||
currentTab?: number;
|
||||
onOpenProjectFinder: ($target: React.RefObject<HTMLElement>) => void;
|
||||
onFavorite?: () => void;
|
||||
onProfileClick: ($target: React.RefObject<HTMLElement>) => void;
|
||||
onSaveProjectName?: (projectName: string) => void;
|
||||
onTabClick?: (tab: number) => void;
|
||||
onSaveName?: (name: string) => void;
|
||||
onNotificationClick: () => void;
|
||||
onDashboardClick: () => void;
|
||||
user: TaskUser | null;
|
||||
onOpenSettings: ($target: React.RefObject<HTMLElement>) => void;
|
||||
projectMembers?: Array<TaskUser> | null;
|
||||
};
|
||||
|
||||
const NavBar: React.FC<NavBarProps> = ({
|
||||
projectName,
|
||||
onSaveProjectName,
|
||||
menuType,
|
||||
currentTab,
|
||||
onOpenProjectFinder,
|
||||
onFavorite,
|
||||
onTabClick,
|
||||
name,
|
||||
onSaveName,
|
||||
onProfileClick,
|
||||
onNotificationClick,
|
||||
onDashboardClick,
|
||||
user,
|
||||
projectMembers,
|
||||
onOpenSettings,
|
||||
@ -152,45 +184,61 @@ const NavBar: React.FC<NavBarProps> = ({
|
||||
<NavbarHeader>
|
||||
<ProjectActions>
|
||||
<ProjectMeta>
|
||||
<ProjectSwitcher>Projects</ProjectSwitcher>
|
||||
{projectName && (
|
||||
{name && (
|
||||
<ProjectHeading
|
||||
onFavorite={onFavorite}
|
||||
onOpenSettings={onOpenSettings}
|
||||
projectName={projectName}
|
||||
onSaveProjectName={onSaveProjectName}
|
||||
name={name}
|
||||
onSaveProjectName={onSaveName}
|
||||
/>
|
||||
)}
|
||||
</ProjectMeta>
|
||||
{projectName && (
|
||||
{name && (
|
||||
<ProjectTabs>
|
||||
<ProjectTab active>Board</ProjectTab>
|
||||
<ProjectTab>Calender</ProjectTab>
|
||||
<ProjectTab>Timeline</ProjectTab>
|
||||
<ProjectTab>Wiki</ProjectTab>
|
||||
{menuType &&
|
||||
menuType.map((name, idx) => {
|
||||
console.log(`${name} : ${idx} === ${currentTab}`);
|
||||
return <ProjectTab active={currentTab === idx}>{name}</ProjectTab>;
|
||||
})}
|
||||
</ProjectTabs>
|
||||
)}
|
||||
</ProjectActions>
|
||||
<LogoContainer to="/">
|
||||
<CitadelLogo width={24} height={24} />
|
||||
<CitadelTitle>Citadel</CitadelTitle>
|
||||
</LogoContainer>
|
||||
<GlobalActions>
|
||||
{projectMembers && (
|
||||
<>
|
||||
<ProjectMembers>
|
||||
{projectMembers.map(member => (
|
||||
<TaskAssignee key={member.id} size={28} member={member} onMemberProfile={onMemberProfile} />
|
||||
))}
|
||||
<InviteButton variant="outline">Invite</InviteButton>
|
||||
</ProjectMembers>
|
||||
<NavSeparator />
|
||||
</>
|
||||
)}
|
||||
<NotificationContainer onClick={onNotificationClick}>
|
||||
<ProjectFinder onClick={onOpenProjectFinder} variant="gradient">
|
||||
Projects
|
||||
</ProjectFinder>
|
||||
<IconContainer onClick={onDashboardClick}>
|
||||
<HomeDashboard width={20} height={20} />
|
||||
</IconContainer>
|
||||
<IconContainer>
|
||||
<CheckCircle width={20} height={20} />
|
||||
</IconContainer>
|
||||
<IconContainer onClick={onNotificationClick}>
|
||||
<Bell color="#c2c6dc" size={20} />
|
||||
</NotificationContainer>
|
||||
</IconContainer>
|
||||
<IconContainer>
|
||||
<BarChart width={20} height={20} />
|
||||
</IconContainer>
|
||||
|
||||
{user && (
|
||||
<ProfileContainer>
|
||||
<ProfileNameWrapper>
|
||||
<ProfileNamePrimary>{user.fullName}</ProfileNamePrimary>
|
||||
<ProfileNameSecondary>Manager</ProfileNameSecondary>
|
||||
</ProfileNameWrapper>
|
||||
<ProfileIcon user={user} size={40} onProfileClick={handleProfileClick} />}
|
||||
</ProfileContainer>
|
||||
<IconContainer>
|
||||
<ProfileIcon user={user} size={30} onProfileClick={handleProfileClick} />
|
||||
</IconContainer>
|
||||
)}
|
||||
</GlobalActions>
|
||||
</NavbarHeader>
|
||||
|
@ -131,7 +131,7 @@ export type Task = {
|
||||
};
|
||||
|
||||
export type ProjectsFilter = {
|
||||
teamID?: Maybe<Scalars['String']>;
|
||||
teamID?: Maybe<Scalars['UUID']>;
|
||||
};
|
||||
|
||||
export type FindUser = {
|
||||
@ -152,6 +152,10 @@ export type Organization = {
|
||||
name: Scalars['String'];
|
||||
};
|
||||
|
||||
export type FindTeam = {
|
||||
teamID: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type Query = {
|
||||
__typename?: 'Query';
|
||||
organizations: Array<Organization>;
|
||||
@ -160,6 +164,7 @@ export type Query = {
|
||||
findProject: Project;
|
||||
findTask: Task;
|
||||
projects: Array<Project>;
|
||||
findTeam: Team;
|
||||
teams: Array<Team>;
|
||||
labelColors: Array<LabelColor>;
|
||||
taskGroups: Array<TaskGroup>;
|
||||
@ -186,6 +191,11 @@ export type QueryProjectsArgs = {
|
||||
input?: Maybe<ProjectsFilter>;
|
||||
};
|
||||
|
||||
|
||||
export type QueryFindTeamArgs = {
|
||||
input: FindTeam;
|
||||
};
|
||||
|
||||
export type NewRefreshToken = {
|
||||
userId: Scalars['String'];
|
||||
};
|
||||
@ -419,10 +429,48 @@ export type DeleteProjectPayload = {
|
||||
project: Project;
|
||||
};
|
||||
|
||||
export type DeleteTeam = {
|
||||
teamID: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type DeleteTeamPayload = {
|
||||
__typename?: 'DeleteTeamPayload';
|
||||
ok: Scalars['Boolean'];
|
||||
team: Team;
|
||||
projects: Array<Project>;
|
||||
};
|
||||
|
||||
export type DeleteUserAccount = {
|
||||
userID: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type DeleteUserAccountPayload = {
|
||||
__typename?: 'DeleteUserAccountPayload';
|
||||
ok: Scalars['Boolean'];
|
||||
userAccount: UserAccount;
|
||||
};
|
||||
|
||||
export type UpdateTaskChecklistName = {
|
||||
taskChecklistID: Scalars['UUID'];
|
||||
name: Scalars['String'];
|
||||
};
|
||||
|
||||
export type DeleteTaskChecklist = {
|
||||
taskChecklistID: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type DeleteTaskChecklistPayload = {
|
||||
__typename?: 'DeleteTaskChecklistPayload';
|
||||
ok: Scalars['Boolean'];
|
||||
taskChecklist: TaskChecklist;
|
||||
};
|
||||
|
||||
export type Mutation = {
|
||||
__typename?: 'Mutation';
|
||||
createRefreshToken: RefreshToken;
|
||||
createUserAccount: UserAccount;
|
||||
deleteUserAccount: DeleteUserAccountPayload;
|
||||
deleteTeam: DeleteTeamPayload;
|
||||
createTeam: Team;
|
||||
clearProfileAvatar: UserAccount;
|
||||
createTeamMember: CreateTeamMemberPayload;
|
||||
@ -442,6 +490,8 @@ export type Mutation = {
|
||||
removeTaskLabel: Task;
|
||||
toggleTaskLabel: ToggleTaskLabelPayload;
|
||||
createTaskChecklist: TaskChecklist;
|
||||
deleteTaskChecklist: DeleteTaskChecklistPayload;
|
||||
updateTaskChecklistName: TaskChecklist;
|
||||
createTaskChecklistItem: TaskChecklistItem;
|
||||
updateTaskChecklistItemName: TaskChecklistItem;
|
||||
setTaskChecklistItemComplete: TaskChecklistItem;
|
||||
@ -469,6 +519,16 @@ export type MutationCreateUserAccountArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeleteUserAccountArgs = {
|
||||
input: DeleteUserAccount;
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeleteTeamArgs = {
|
||||
input: DeleteTeam;
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateTeamArgs = {
|
||||
input: NewTeam;
|
||||
};
|
||||
@ -559,6 +619,16 @@ export type MutationCreateTaskChecklistArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeleteTaskChecklistArgs = {
|
||||
input: DeleteTaskChecklist;
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateTaskChecklistNameArgs = {
|
||||
input: UpdateTaskChecklistName;
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateTaskChecklistItemArgs = {
|
||||
input: CreateTaskChecklistItem;
|
||||
};
|
||||
@ -699,43 +769,6 @@ export type CreateProjectLabelMutation = (
|
||||
) }
|
||||
);
|
||||
|
||||
export type CreateTaskMutationVariables = {
|
||||
taskGroupID: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
position: Scalars['Float'];
|
||||
};
|
||||
|
||||
|
||||
export type CreateTaskMutation = (
|
||||
{ __typename?: 'Mutation' }
|
||||
& { createTask: (
|
||||
{ __typename?: 'Task' }
|
||||
& Pick<Task, 'id' | 'name' | 'position' | 'description' | 'dueDate'>
|
||||
& { taskGroup: (
|
||||
{ __typename?: 'TaskGroup' }
|
||||
& Pick<TaskGroup, 'id' | 'name' | 'position'>
|
||||
), labels: Array<(
|
||||
{ __typename?: 'TaskLabel' }
|
||||
& Pick<TaskLabel, 'id' | 'assignedDate'>
|
||||
& { projectLabel: (
|
||||
{ __typename?: 'ProjectLabel' }
|
||||
& Pick<ProjectLabel, 'id' | 'name' | 'createdDate'>
|
||||
& { labelColor: (
|
||||
{ __typename?: 'LabelColor' }
|
||||
& Pick<LabelColor, 'id' | 'colorHex' | 'position' | 'name'>
|
||||
) }
|
||||
) }
|
||||
)>, assigned: Array<(
|
||||
{ __typename?: 'ProjectMember' }
|
||||
& Pick<ProjectMember, 'id' | 'fullName'>
|
||||
& { profileIcon: (
|
||||
{ __typename?: 'ProfileIcon' }
|
||||
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
||||
) }
|
||||
)> }
|
||||
) }
|
||||
);
|
||||
|
||||
export type CreateTaskGroupMutationVariables = {
|
||||
projectID: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
@ -849,6 +882,12 @@ export type FindTaskQuery = (
|
||||
& { taskGroup: (
|
||||
{ __typename?: 'TaskGroup' }
|
||||
& Pick<TaskGroup, 'id'>
|
||||
), badges: (
|
||||
{ __typename?: 'TaskBadges' }
|
||||
& { checklist?: Maybe<(
|
||||
{ __typename?: 'ChecklistBadge' }
|
||||
& Pick<ChecklistBadge, 'total' | 'complete'>
|
||||
)> }
|
||||
), checklists: Array<(
|
||||
{ __typename?: 'TaskChecklist' }
|
||||
& Pick<TaskChecklist, 'id' | 'name' | 'position'>
|
||||
@ -881,9 +920,15 @@ export type FindTaskQuery = (
|
||||
export type TaskFieldsFragment = (
|
||||
{ __typename?: 'Task' }
|
||||
& Pick<Task, 'id' | 'name' | 'description' | 'dueDate' | 'complete' | 'position'>
|
||||
& { taskGroup: (
|
||||
& { badges: (
|
||||
{ __typename?: 'TaskBadges' }
|
||||
& { checklist?: Maybe<(
|
||||
{ __typename?: 'ChecklistBadge' }
|
||||
& Pick<ChecklistBadge, 'complete' | 'total'>
|
||||
)> }
|
||||
), taskGroup: (
|
||||
{ __typename?: 'TaskGroup' }
|
||||
& Pick<TaskGroup, 'id'>
|
||||
& Pick<TaskGroup, 'id' | 'name' | 'position'>
|
||||
), labels: Array<(
|
||||
{ __typename?: 'TaskLabel' }
|
||||
& Pick<TaskLabel, 'id' | 'assignedDate'>
|
||||
@ -958,6 +1003,40 @@ export type DeleteProjectMutation = (
|
||||
) }
|
||||
);
|
||||
|
||||
export type CreateTaskMutationVariables = {
|
||||
taskGroupID: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
position: Scalars['Float'];
|
||||
};
|
||||
|
||||
|
||||
export type CreateTaskMutation = (
|
||||
{ __typename?: 'Mutation' }
|
||||
& { createTask: (
|
||||
{ __typename?: 'Task' }
|
||||
& TaskFieldsFragment
|
||||
) }
|
||||
);
|
||||
|
||||
export type CreateTaskChecklistMutationVariables = {
|
||||
taskID: Scalars['UUID'];
|
||||
name: Scalars['String'];
|
||||
position: Scalars['Float'];
|
||||
};
|
||||
|
||||
|
||||
export type CreateTaskChecklistMutation = (
|
||||
{ __typename?: 'Mutation' }
|
||||
& { createTaskChecklist: (
|
||||
{ __typename?: 'TaskChecklist' }
|
||||
& Pick<TaskChecklist, 'id' | 'name' | 'position'>
|
||||
& { items: Array<(
|
||||
{ __typename?: 'TaskChecklistItem' }
|
||||
& Pick<TaskChecklistItem, 'id' | 'name' | 'taskChecklistID' | 'complete' | 'position'>
|
||||
)> }
|
||||
) }
|
||||
);
|
||||
|
||||
export type CreateTaskChecklistItemMutationVariables = {
|
||||
taskChecklistID: Scalars['UUID'];
|
||||
name: Scalars['String'];
|
||||
@ -973,6 +1052,23 @@ export type CreateTaskChecklistItemMutation = (
|
||||
) }
|
||||
);
|
||||
|
||||
export type DeleteTaskChecklistMutationVariables = {
|
||||
taskChecklistID: Scalars['UUID'];
|
||||
};
|
||||
|
||||
|
||||
export type DeleteTaskChecklistMutation = (
|
||||
{ __typename?: 'Mutation' }
|
||||
& { deleteTaskChecklist: (
|
||||
{ __typename?: 'DeleteTaskChecklistPayload' }
|
||||
& Pick<DeleteTaskChecklistPayload, 'ok'>
|
||||
& { taskChecklist: (
|
||||
{ __typename?: 'TaskChecklist' }
|
||||
& Pick<TaskChecklist, 'id'>
|
||||
) }
|
||||
) }
|
||||
);
|
||||
|
||||
export type DeleteTaskChecklistItemMutationVariables = {
|
||||
taskChecklistItemID: Scalars['UUID'];
|
||||
};
|
||||
@ -1000,7 +1096,7 @@ export type SetTaskChecklistItemCompleteMutation = (
|
||||
{ __typename?: 'Mutation' }
|
||||
& { setTaskChecklistItemComplete: (
|
||||
{ __typename?: 'TaskChecklistItem' }
|
||||
& Pick<TaskChecklistItem, 'id' | 'name' | 'taskChecklistID' | 'complete' | 'position'>
|
||||
& Pick<TaskChecklistItem, 'id' | 'complete'>
|
||||
) }
|
||||
);
|
||||
|
||||
@ -1032,6 +1128,24 @@ export type UpdateTaskChecklistItemNameMutation = (
|
||||
) }
|
||||
);
|
||||
|
||||
export type UpdateTaskChecklistNameMutationVariables = {
|
||||
taskChecklistID: Scalars['UUID'];
|
||||
name: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type UpdateTaskChecklistNameMutation = (
|
||||
{ __typename?: 'Mutation' }
|
||||
& { updateTaskChecklistName: (
|
||||
{ __typename?: 'TaskChecklist' }
|
||||
& Pick<TaskChecklist, 'id' | 'name' | 'position'>
|
||||
& { items: Array<(
|
||||
{ __typename?: 'TaskChecklistItem' }
|
||||
& Pick<TaskChecklistItem, 'id' | 'name' | 'taskChecklistID' | 'complete' | 'position'>
|
||||
)> }
|
||||
) }
|
||||
);
|
||||
|
||||
export type UpdateTaskGroupNameMutationVariables = {
|
||||
taskGroupID: Scalars['UUID'];
|
||||
name: Scalars['String'];
|
||||
@ -1060,6 +1174,43 @@ export type CreateTeamMutation = (
|
||||
) }
|
||||
);
|
||||
|
||||
export type DeleteTeamMutationVariables = {
|
||||
teamID: Scalars['UUID'];
|
||||
};
|
||||
|
||||
|
||||
export type DeleteTeamMutation = (
|
||||
{ __typename?: 'Mutation' }
|
||||
& { deleteTeam: (
|
||||
{ __typename?: 'DeleteTeamPayload' }
|
||||
& Pick<DeleteTeamPayload, 'ok'>
|
||||
& { team: (
|
||||
{ __typename?: 'Team' }
|
||||
& Pick<Team, 'id'>
|
||||
) }
|
||||
) }
|
||||
);
|
||||
|
||||
export type GetTeamQueryVariables = {
|
||||
teamID: Scalars['UUID'];
|
||||
};
|
||||
|
||||
|
||||
export type GetTeamQuery = (
|
||||
{ __typename?: 'Query' }
|
||||
& { findTeam: (
|
||||
{ __typename?: 'Team' }
|
||||
& Pick<Team, 'id' | 'createdAt' | 'name'>
|
||||
), projects: Array<(
|
||||
{ __typename?: 'Project' }
|
||||
& Pick<Project, 'id' | 'name'>
|
||||
& { team: (
|
||||
{ __typename?: 'Team' }
|
||||
& Pick<Team, 'id' | 'name'>
|
||||
) }
|
||||
)> }
|
||||
);
|
||||
|
||||
export type ToggleTaskLabelMutationVariables = {
|
||||
taskID: Scalars['UUID'];
|
||||
projectLabelID: Scalars['UUID'];
|
||||
@ -1220,6 +1371,42 @@ export type UpdateTaskNameMutation = (
|
||||
) }
|
||||
);
|
||||
|
||||
export type CreateUserAccountMutationVariables = {
|
||||
username: Scalars['String'];
|
||||
email: Scalars['String'];
|
||||
fullName: Scalars['String'];
|
||||
initials: Scalars['String'];
|
||||
password: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type CreateUserAccountMutation = (
|
||||
{ __typename?: 'Mutation' }
|
||||
& { createUserAccount: (
|
||||
{ __typename?: 'UserAccount' }
|
||||
& Pick<UserAccount, 'id' | 'email' | 'fullName' | 'initials' | 'username'>
|
||||
& { profileIcon: (
|
||||
{ __typename?: 'ProfileIcon' }
|
||||
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
||||
) }
|
||||
) }
|
||||
);
|
||||
|
||||
export type UsersQueryVariables = {};
|
||||
|
||||
|
||||
export type UsersQuery = (
|
||||
{ __typename?: 'Query' }
|
||||
& { users: Array<(
|
||||
{ __typename?: 'UserAccount' }
|
||||
& Pick<UserAccount, 'id' | 'email' | 'fullName' | 'username'>
|
||||
& { profileIcon: (
|
||||
{ __typename?: 'ProfileIcon' }
|
||||
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
||||
) }
|
||||
)> }
|
||||
);
|
||||
|
||||
export const TaskFieldsFragmentDoc = gql`
|
||||
fragment TaskFields on Task {
|
||||
id
|
||||
@ -1228,8 +1415,16 @@ export const TaskFieldsFragmentDoc = gql`
|
||||
dueDate
|
||||
complete
|
||||
position
|
||||
badges {
|
||||
checklist {
|
||||
complete
|
||||
total
|
||||
}
|
||||
}
|
||||
taskGroup {
|
||||
id
|
||||
name
|
||||
position
|
||||
}
|
||||
labels {
|
||||
id
|
||||
@ -1412,73 +1607,6 @@ export function useCreateProjectLabelMutation(baseOptions?: ApolloReactHooks.Mut
|
||||
export type CreateProjectLabelMutationHookResult = ReturnType<typeof useCreateProjectLabelMutation>;
|
||||
export type CreateProjectLabelMutationResult = ApolloReactCommon.MutationResult<CreateProjectLabelMutation>;
|
||||
export type CreateProjectLabelMutationOptions = ApolloReactCommon.BaseMutationOptions<CreateProjectLabelMutation, CreateProjectLabelMutationVariables>;
|
||||
export const CreateTaskDocument = gql`
|
||||
mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
|
||||
createTask(input: {taskGroupID: $taskGroupID, name: $name, position: $position}) {
|
||||
id
|
||||
name
|
||||
position
|
||||
description
|
||||
dueDate
|
||||
taskGroup {
|
||||
id
|
||||
name
|
||||
position
|
||||
}
|
||||
labels {
|
||||
id
|
||||
assignedDate
|
||||
projectLabel {
|
||||
id
|
||||
name
|
||||
createdDate
|
||||
labelColor {
|
||||
id
|
||||
colorHex
|
||||
position
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
assigned {
|
||||
id
|
||||
fullName
|
||||
profileIcon {
|
||||
url
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type CreateTaskMutationFn = ApolloReactCommon.MutationFunction<CreateTaskMutation, CreateTaskMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useCreateTaskMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useCreateTaskMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useCreateTaskMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [createTaskMutation, { data, loading, error }] = useCreateTaskMutation({
|
||||
* variables: {
|
||||
* taskGroupID: // value for 'taskGroupID'
|
||||
* name: // value for 'name'
|
||||
* position: // value for 'position'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useCreateTaskMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<CreateTaskMutation, CreateTaskMutationVariables>) {
|
||||
return ApolloReactHooks.useMutation<CreateTaskMutation, CreateTaskMutationVariables>(CreateTaskDocument, baseOptions);
|
||||
}
|
||||
export type CreateTaskMutationHookResult = ReturnType<typeof useCreateTaskMutation>;
|
||||
export type CreateTaskMutationResult = ApolloReactCommon.MutationResult<CreateTaskMutation>;
|
||||
export type CreateTaskMutationOptions = ApolloReactCommon.BaseMutationOptions<CreateTaskMutation, CreateTaskMutationVariables>;
|
||||
export const CreateTaskGroupDocument = gql`
|
||||
mutation createTaskGroup($projectID: String!, $name: String!, $position: Float!) {
|
||||
createTaskGroup(input: {projectID: $projectID, name: $name, position: $position}) {
|
||||
@ -1698,6 +1826,12 @@ export const FindTaskDocument = gql`
|
||||
taskGroup {
|
||||
id
|
||||
}
|
||||
badges {
|
||||
checklist {
|
||||
total
|
||||
complete
|
||||
}
|
||||
}
|
||||
checklists {
|
||||
id
|
||||
name
|
||||
@ -1882,6 +2016,83 @@ export function useDeleteProjectMutation(baseOptions?: ApolloReactHooks.Mutation
|
||||
export type DeleteProjectMutationHookResult = ReturnType<typeof useDeleteProjectMutation>;
|
||||
export type DeleteProjectMutationResult = ApolloReactCommon.MutationResult<DeleteProjectMutation>;
|
||||
export type DeleteProjectMutationOptions = ApolloReactCommon.BaseMutationOptions<DeleteProjectMutation, DeleteProjectMutationVariables>;
|
||||
export const CreateTaskDocument = gql`
|
||||
mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
|
||||
createTask(input: {taskGroupID: $taskGroupID, name: $name, position: $position}) {
|
||||
...TaskFields
|
||||
}
|
||||
}
|
||||
${TaskFieldsFragmentDoc}`;
|
||||
export type CreateTaskMutationFn = ApolloReactCommon.MutationFunction<CreateTaskMutation, CreateTaskMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useCreateTaskMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useCreateTaskMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useCreateTaskMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [createTaskMutation, { data, loading, error }] = useCreateTaskMutation({
|
||||
* variables: {
|
||||
* taskGroupID: // value for 'taskGroupID'
|
||||
* name: // value for 'name'
|
||||
* position: // value for 'position'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useCreateTaskMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<CreateTaskMutation, CreateTaskMutationVariables>) {
|
||||
return ApolloReactHooks.useMutation<CreateTaskMutation, CreateTaskMutationVariables>(CreateTaskDocument, baseOptions);
|
||||
}
|
||||
export type CreateTaskMutationHookResult = ReturnType<typeof useCreateTaskMutation>;
|
||||
export type CreateTaskMutationResult = ApolloReactCommon.MutationResult<CreateTaskMutation>;
|
||||
export type CreateTaskMutationOptions = ApolloReactCommon.BaseMutationOptions<CreateTaskMutation, CreateTaskMutationVariables>;
|
||||
export const CreateTaskChecklistDocument = gql`
|
||||
mutation createTaskChecklist($taskID: UUID!, $name: String!, $position: Float!) {
|
||||
createTaskChecklist(input: {taskID: $taskID, name: $name, position: $position}) {
|
||||
id
|
||||
name
|
||||
position
|
||||
items {
|
||||
id
|
||||
name
|
||||
taskChecklistID
|
||||
complete
|
||||
position
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type CreateTaskChecklistMutationFn = ApolloReactCommon.MutationFunction<CreateTaskChecklistMutation, CreateTaskChecklistMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useCreateTaskChecklistMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useCreateTaskChecklistMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useCreateTaskChecklistMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [createTaskChecklistMutation, { data, loading, error }] = useCreateTaskChecklistMutation({
|
||||
* variables: {
|
||||
* taskID: // value for 'taskID'
|
||||
* name: // value for 'name'
|
||||
* position: // value for 'position'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useCreateTaskChecklistMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<CreateTaskChecklistMutation, CreateTaskChecklistMutationVariables>) {
|
||||
return ApolloReactHooks.useMutation<CreateTaskChecklistMutation, CreateTaskChecklistMutationVariables>(CreateTaskChecklistDocument, baseOptions);
|
||||
}
|
||||
export type CreateTaskChecklistMutationHookResult = ReturnType<typeof useCreateTaskChecklistMutation>;
|
||||
export type CreateTaskChecklistMutationResult = ApolloReactCommon.MutationResult<CreateTaskChecklistMutation>;
|
||||
export type CreateTaskChecklistMutationOptions = ApolloReactCommon.BaseMutationOptions<CreateTaskChecklistMutation, CreateTaskChecklistMutationVariables>;
|
||||
export const CreateTaskChecklistItemDocument = gql`
|
||||
mutation createTaskChecklistItem($taskChecklistID: UUID!, $name: String!, $position: Float!) {
|
||||
createTaskChecklistItem(input: {taskChecklistID: $taskChecklistID, name: $name, position: $position}) {
|
||||
@ -1920,6 +2131,41 @@ export function useCreateTaskChecklistItemMutation(baseOptions?: ApolloReactHook
|
||||
export type CreateTaskChecklistItemMutationHookResult = ReturnType<typeof useCreateTaskChecklistItemMutation>;
|
||||
export type CreateTaskChecklistItemMutationResult = ApolloReactCommon.MutationResult<CreateTaskChecklistItemMutation>;
|
||||
export type CreateTaskChecklistItemMutationOptions = ApolloReactCommon.BaseMutationOptions<CreateTaskChecklistItemMutation, CreateTaskChecklistItemMutationVariables>;
|
||||
export const DeleteTaskChecklistDocument = gql`
|
||||
mutation deleteTaskChecklist($taskChecklistID: UUID!) {
|
||||
deleteTaskChecklist(input: {taskChecklistID: $taskChecklistID}) {
|
||||
ok
|
||||
taskChecklist {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type DeleteTaskChecklistMutationFn = ApolloReactCommon.MutationFunction<DeleteTaskChecklistMutation, DeleteTaskChecklistMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useDeleteTaskChecklistMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useDeleteTaskChecklistMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useDeleteTaskChecklistMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [deleteTaskChecklistMutation, { data, loading, error }] = useDeleteTaskChecklistMutation({
|
||||
* variables: {
|
||||
* taskChecklistID: // value for 'taskChecklistID'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useDeleteTaskChecklistMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<DeleteTaskChecklistMutation, DeleteTaskChecklistMutationVariables>) {
|
||||
return ApolloReactHooks.useMutation<DeleteTaskChecklistMutation, DeleteTaskChecklistMutationVariables>(DeleteTaskChecklistDocument, baseOptions);
|
||||
}
|
||||
export type DeleteTaskChecklistMutationHookResult = ReturnType<typeof useDeleteTaskChecklistMutation>;
|
||||
export type DeleteTaskChecklistMutationResult = ApolloReactCommon.MutationResult<DeleteTaskChecklistMutation>;
|
||||
export type DeleteTaskChecklistMutationOptions = ApolloReactCommon.BaseMutationOptions<DeleteTaskChecklistMutation, DeleteTaskChecklistMutationVariables>;
|
||||
export const DeleteTaskChecklistItemDocument = gql`
|
||||
mutation deleteTaskChecklistItem($taskChecklistItemID: UUID!) {
|
||||
deleteTaskChecklistItem(input: {taskChecklistItemID: $taskChecklistItemID}) {
|
||||
@ -1960,10 +2206,7 @@ export const SetTaskChecklistItemCompleteDocument = gql`
|
||||
mutation setTaskChecklistItemComplete($taskChecklistItemID: UUID!, $complete: Boolean!) {
|
||||
setTaskChecklistItemComplete(input: {taskChecklistItemID: $taskChecklistItemID, complete: $complete}) {
|
||||
id
|
||||
name
|
||||
taskChecklistID
|
||||
complete
|
||||
position
|
||||
}
|
||||
}
|
||||
`;
|
||||
@ -2060,6 +2303,48 @@ export function useUpdateTaskChecklistItemNameMutation(baseOptions?: ApolloReact
|
||||
export type UpdateTaskChecklistItemNameMutationHookResult = ReturnType<typeof useUpdateTaskChecklistItemNameMutation>;
|
||||
export type UpdateTaskChecklistItemNameMutationResult = ApolloReactCommon.MutationResult<UpdateTaskChecklistItemNameMutation>;
|
||||
export type UpdateTaskChecklistItemNameMutationOptions = ApolloReactCommon.BaseMutationOptions<UpdateTaskChecklistItemNameMutation, UpdateTaskChecklistItemNameMutationVariables>;
|
||||
export const UpdateTaskChecklistNameDocument = gql`
|
||||
mutation updateTaskChecklistName($taskChecklistID: UUID!, $name: String!) {
|
||||
updateTaskChecklistName(input: {taskChecklistID: $taskChecklistID, name: $name}) {
|
||||
id
|
||||
name
|
||||
position
|
||||
items {
|
||||
id
|
||||
name
|
||||
taskChecklistID
|
||||
complete
|
||||
position
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type UpdateTaskChecklistNameMutationFn = ApolloReactCommon.MutationFunction<UpdateTaskChecklistNameMutation, UpdateTaskChecklistNameMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useUpdateTaskChecklistNameMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useUpdateTaskChecklistNameMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useUpdateTaskChecklistNameMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [updateTaskChecklistNameMutation, { data, loading, error }] = useUpdateTaskChecklistNameMutation({
|
||||
* variables: {
|
||||
* taskChecklistID: // value for 'taskChecklistID'
|
||||
* name: // value for 'name'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useUpdateTaskChecklistNameMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<UpdateTaskChecklistNameMutation, UpdateTaskChecklistNameMutationVariables>) {
|
||||
return ApolloReactHooks.useMutation<UpdateTaskChecklistNameMutation, UpdateTaskChecklistNameMutationVariables>(UpdateTaskChecklistNameDocument, baseOptions);
|
||||
}
|
||||
export type UpdateTaskChecklistNameMutationHookResult = ReturnType<typeof useUpdateTaskChecklistNameMutation>;
|
||||
export type UpdateTaskChecklistNameMutationResult = ApolloReactCommon.MutationResult<UpdateTaskChecklistNameMutation>;
|
||||
export type UpdateTaskChecklistNameMutationOptions = ApolloReactCommon.BaseMutationOptions<UpdateTaskChecklistNameMutation, UpdateTaskChecklistNameMutationVariables>;
|
||||
export const UpdateTaskGroupNameDocument = gql`
|
||||
mutation updateTaskGroupName($taskGroupID: UUID!, $name: String!) {
|
||||
updateTaskGroupName(input: {taskGroupID: $taskGroupID, name: $name}) {
|
||||
@ -2129,6 +2414,84 @@ export function useCreateTeamMutation(baseOptions?: ApolloReactHooks.MutationHoo
|
||||
export type CreateTeamMutationHookResult = ReturnType<typeof useCreateTeamMutation>;
|
||||
export type CreateTeamMutationResult = ApolloReactCommon.MutationResult<CreateTeamMutation>;
|
||||
export type CreateTeamMutationOptions = ApolloReactCommon.BaseMutationOptions<CreateTeamMutation, CreateTeamMutationVariables>;
|
||||
export const DeleteTeamDocument = gql`
|
||||
mutation deleteTeam($teamID: UUID!) {
|
||||
deleteTeam(input: {teamID: $teamID}) {
|
||||
ok
|
||||
team {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type DeleteTeamMutationFn = ApolloReactCommon.MutationFunction<DeleteTeamMutation, DeleteTeamMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useDeleteTeamMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useDeleteTeamMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useDeleteTeamMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [deleteTeamMutation, { data, loading, error }] = useDeleteTeamMutation({
|
||||
* variables: {
|
||||
* teamID: // value for 'teamID'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useDeleteTeamMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<DeleteTeamMutation, DeleteTeamMutationVariables>) {
|
||||
return ApolloReactHooks.useMutation<DeleteTeamMutation, DeleteTeamMutationVariables>(DeleteTeamDocument, baseOptions);
|
||||
}
|
||||
export type DeleteTeamMutationHookResult = ReturnType<typeof useDeleteTeamMutation>;
|
||||
export type DeleteTeamMutationResult = ApolloReactCommon.MutationResult<DeleteTeamMutation>;
|
||||
export type DeleteTeamMutationOptions = ApolloReactCommon.BaseMutationOptions<DeleteTeamMutation, DeleteTeamMutationVariables>;
|
||||
export const GetTeamDocument = gql`
|
||||
query getTeam($teamID: UUID!) {
|
||||
findTeam(input: {teamID: $teamID}) {
|
||||
id
|
||||
createdAt
|
||||
name
|
||||
}
|
||||
projects(input: {teamID: $teamID}) {
|
||||
id
|
||||
name
|
||||
team {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useGetTeamQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useGetTeamQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGetTeamQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useGetTeamQuery({
|
||||
* variables: {
|
||||
* teamID: // value for 'teamID'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useGetTeamQuery(baseOptions?: ApolloReactHooks.QueryHookOptions<GetTeamQuery, GetTeamQueryVariables>) {
|
||||
return ApolloReactHooks.useQuery<GetTeamQuery, GetTeamQueryVariables>(GetTeamDocument, baseOptions);
|
||||
}
|
||||
export function useGetTeamLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<GetTeamQuery, GetTeamQueryVariables>) {
|
||||
return ApolloReactHooks.useLazyQuery<GetTeamQuery, GetTeamQueryVariables>(GetTeamDocument, baseOptions);
|
||||
}
|
||||
export type GetTeamQueryHookResult = ReturnType<typeof useGetTeamQuery>;
|
||||
export type GetTeamLazyQueryHookResult = ReturnType<typeof useGetTeamLazyQuery>;
|
||||
export type GetTeamQueryResult = ApolloReactCommon.QueryResult<GetTeamQuery, GetTeamQueryVariables>;
|
||||
export const ToggleTaskLabelDocument = gql`
|
||||
mutation toggleTaskLabel($taskID: UUID!, $projectLabelID: UUID!) {
|
||||
toggleTaskLabel(input: {taskID: $taskID, projectLabelID: $projectLabelID}) {
|
||||
@ -2473,3 +2836,88 @@ export function useUpdateTaskNameMutation(baseOptions?: ApolloReactHooks.Mutatio
|
||||
export type UpdateTaskNameMutationHookResult = ReturnType<typeof useUpdateTaskNameMutation>;
|
||||
export type UpdateTaskNameMutationResult = ApolloReactCommon.MutationResult<UpdateTaskNameMutation>;
|
||||
export type UpdateTaskNameMutationOptions = ApolloReactCommon.BaseMutationOptions<UpdateTaskNameMutation, UpdateTaskNameMutationVariables>;
|
||||
export const CreateUserAccountDocument = gql`
|
||||
mutation createUserAccount($username: String!, $email: String!, $fullName: String!, $initials: String!, $password: String!) {
|
||||
createUserAccount(input: {username: $username, email: $email, fullName: $fullName, initials: $initials, password: $password}) {
|
||||
id
|
||||
email
|
||||
fullName
|
||||
initials
|
||||
username
|
||||
profileIcon {
|
||||
url
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type CreateUserAccountMutationFn = ApolloReactCommon.MutationFunction<CreateUserAccountMutation, CreateUserAccountMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useCreateUserAccountMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useCreateUserAccountMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useCreateUserAccountMutation` returns a tuple that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - An object with fields that represent the current status of the mutation's execution
|
||||
*
|
||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||
*
|
||||
* @example
|
||||
* const [createUserAccountMutation, { data, loading, error }] = useCreateUserAccountMutation({
|
||||
* variables: {
|
||||
* username: // value for 'username'
|
||||
* email: // value for 'email'
|
||||
* fullName: // value for 'fullName'
|
||||
* initials: // value for 'initials'
|
||||
* password: // value for 'password'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useCreateUserAccountMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<CreateUserAccountMutation, CreateUserAccountMutationVariables>) {
|
||||
return ApolloReactHooks.useMutation<CreateUserAccountMutation, CreateUserAccountMutationVariables>(CreateUserAccountDocument, baseOptions);
|
||||
}
|
||||
export type CreateUserAccountMutationHookResult = ReturnType<typeof useCreateUserAccountMutation>;
|
||||
export type CreateUserAccountMutationResult = ApolloReactCommon.MutationResult<CreateUserAccountMutation>;
|
||||
export type CreateUserAccountMutationOptions = ApolloReactCommon.BaseMutationOptions<CreateUserAccountMutation, CreateUserAccountMutationVariables>;
|
||||
export const UsersDocument = gql`
|
||||
query users {
|
||||
users {
|
||||
id
|
||||
email
|
||||
fullName
|
||||
username
|
||||
profileIcon {
|
||||
url
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useUsersQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useUsersQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useUsersQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useUsersQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useUsersQuery(baseOptions?: ApolloReactHooks.QueryHookOptions<UsersQuery, UsersQueryVariables>) {
|
||||
return ApolloReactHooks.useQuery<UsersQuery, UsersQueryVariables>(UsersDocument, baseOptions);
|
||||
}
|
||||
export function useUsersLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<UsersQuery, UsersQueryVariables>) {
|
||||
return ApolloReactHooks.useLazyQuery<UsersQuery, UsersQueryVariables>(UsersDocument, baseOptions);
|
||||
}
|
||||
export type UsersQueryHookResult = ReturnType<typeof useUsersQuery>;
|
||||
export type UsersLazyQueryHookResult = ReturnType<typeof useUsersLazyQuery>;
|
||||
export type UsersQueryResult = ApolloReactCommon.QueryResult<UsersQuery, UsersQueryVariables>;
|
@ -1,38 +0,0 @@
|
||||
mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
|
||||
createTask(input: { taskGroupID: $taskGroupID, name: $name, position: $position }) {
|
||||
id
|
||||
name
|
||||
position
|
||||
description
|
||||
dueDate
|
||||
taskGroup {
|
||||
id
|
||||
name
|
||||
position
|
||||
}
|
||||
labels {
|
||||
id
|
||||
assignedDate
|
||||
projectLabel {
|
||||
id
|
||||
name
|
||||
createdDate
|
||||
labelColor {
|
||||
id
|
||||
colorHex
|
||||
position
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
assigned {
|
||||
id
|
||||
fullName
|
||||
profileIcon {
|
||||
url
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,12 @@ query findTask($taskID: UUID!) {
|
||||
taskGroup {
|
||||
id
|
||||
}
|
||||
badges {
|
||||
checklist {
|
||||
total
|
||||
complete
|
||||
}
|
||||
}
|
||||
checklists {
|
||||
id
|
||||
name
|
||||
|
@ -8,8 +8,16 @@ const TASK_FRAGMENT = gql`
|
||||
dueDate
|
||||
complete
|
||||
position
|
||||
badges {
|
||||
checklist {
|
||||
complete
|
||||
total
|
||||
}
|
||||
}
|
||||
taskGroup {
|
||||
id
|
||||
name
|
||||
position
|
||||
}
|
||||
labels {
|
||||
id
|
||||
|
13
web/src/shared/graphql/task/createTask.ts
Normal file
13
web/src/shared/graphql/task/createTask.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import gql from 'graphql-tag';
|
||||
import TASK_FRAGMENT from '../fragments/task';
|
||||
|
||||
const CREATE_TASK_MUTATION = gql`
|
||||
mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
|
||||
createTask(input: { taskGroupID: $taskGroupID, name: $name, position: $position }) {
|
||||
...TaskFields
|
||||
}
|
||||
}
|
||||
${TASK_FRAGMENT}
|
||||
`;
|
||||
|
||||
export default CREATE_TASK_MUTATION;
|
20
web/src/shared/graphql/task/createTaskChecklist.ts
Normal file
20
web/src/shared/graphql/task/createTaskChecklist.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
const CREATE_TASK_CHECKLIST_MUTATION = gql`
|
||||
mutation createTaskChecklist($taskID: UUID!, $name: String!, $position: Float!) {
|
||||
createTaskChecklist(input: { taskID: $taskID, name: $name, position: $position }) {
|
||||
id
|
||||
name
|
||||
position
|
||||
items {
|
||||
id
|
||||
name
|
||||
taskChecklistID
|
||||
complete
|
||||
position
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default CREATE_TASK_CHECKLIST_MUTATION;
|
14
web/src/shared/graphql/task/deleteTaskChecklist.ts
Normal file
14
web/src/shared/graphql/task/deleteTaskChecklist.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
const DELETE_TASK_CHECKLIST_MUTATION = gql`
|
||||
mutation deleteTaskChecklist($taskChecklistID: UUID!) {
|
||||
deleteTaskChecklist(input: { taskChecklistID: $taskChecklistID }) {
|
||||
ok
|
||||
taskChecklist {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default DELETE_TASK_CHECKLIST_MUTATION;
|
@ -4,10 +4,7 @@ const SET_TASK_CHECKLIST_ITEM_COMPLETE = gql`
|
||||
mutation setTaskChecklistItemComplete($taskChecklistItemID: UUID!, $complete: Boolean!) {
|
||||
setTaskChecklistItemComplete(input: { taskChecklistItemID: $taskChecklistItemID, complete: $complete }) {
|
||||
id
|
||||
name
|
||||
taskChecklistID
|
||||
complete
|
||||
position
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
19
web/src/shared/graphql/task/updateTaskChecklistName.ts
Normal file
19
web/src/shared/graphql/task/updateTaskChecklistName.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
const UPDATE_TASK_CHECKLIST_NAME_MUTATION = gql`
|
||||
mutation updateTaskChecklistName($taskChecklistID: UUID!, $name: String!) {
|
||||
updateTaskChecklistName(input: { taskChecklistID: $taskChecklistID, name: $name }) {
|
||||
id
|
||||
name
|
||||
position
|
||||
items {
|
||||
id
|
||||
name
|
||||
taskChecklistID
|
||||
complete
|
||||
position
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export default UPDATE_TASK_CHECKLIST_NAME_MUTATION;
|
14
web/src/shared/graphql/team/deleteTeam.ts
Normal file
14
web/src/shared/graphql/team/deleteTeam.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export const DELETE_TEAM_MUTATION = gql`
|
||||
mutation deleteTeam($teamID: UUID!) {
|
||||
deleteTeam(input: { teamID: $teamID }) {
|
||||
ok
|
||||
team {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default DELETE_TEAM_MUTATION;
|
21
web/src/shared/graphql/team/getTeam.ts
Normal file
21
web/src/shared/graphql/team/getTeam.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export const GET_TEAM_QUERY = gql`
|
||||
query getTeam($teamID: UUID!) {
|
||||
findTeam(input: { teamID: $teamID }) {
|
||||
id
|
||||
createdAt
|
||||
name
|
||||
}
|
||||
projects(input: { teamID: $teamID }) {
|
||||
id
|
||||
name
|
||||
team {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default GET_TEAM_QUERY;
|
28
web/src/shared/graphql/user/createUser.ts
Normal file
28
web/src/shared/graphql/user/createUser.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export const CREATE_USER_MUTATION = gql`
|
||||
mutation createUserAccount(
|
||||
$username: String!
|
||||
$email: String!
|
||||
$fullName: String!
|
||||
$initials: String!
|
||||
$password: String!
|
||||
) {
|
||||
createUserAccount(
|
||||
input: { username: $username, email: $email, fullName: $fullName, initials: $initials, password: $password }
|
||||
) {
|
||||
id
|
||||
email
|
||||
fullName
|
||||
initials
|
||||
username
|
||||
profileIcon {
|
||||
url
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default CREATE_USER_MUTATION;
|
14
web/src/shared/graphql/users.graphqls
Normal file
14
web/src/shared/graphql/users.graphqls
Normal file
@ -0,0 +1,14 @@
|
||||
query users {
|
||||
users {
|
||||
id
|
||||
email
|
||||
fullName
|
||||
username
|
||||
profileIcon {
|
||||
url
|
||||
initials
|
||||
bgColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
web/src/shared/icons/BarChart.tsx
Normal file
12
web/src/shared/icons/BarChart.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import Icon, { IconProps } from './Icon';
|
||||
|
||||
const BarChart: React.FC<IconProps> = ({ width = '16px', height = '16px', className }) => {
|
||||
return (
|
||||
<Icon width={width} height={height} className={className} viewBox="0 0 512 512">
|
||||
<path d="M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z" />
|
||||
</Icon>
|
||||
);
|
||||
};
|
||||
|
||||
export default BarChart;
|
@ -1,29 +1,15 @@
|
||||
import React from 'react';
|
||||
import Icon, { IconProps } from './Icon';
|
||||
|
||||
type Props = {
|
||||
size: number | string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
const Citadel = ({ size, color }: Props) => {
|
||||
const Citadel: React.FC<IconProps> = ({ width = '16px', height = '16px', className }) => {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 12.7 12.7">
|
||||
<Icon width={width} height={height} className={className} viewBox="0 0 12.7 12.7">
|
||||
<g transform="translate(-.26 -24.137) scale(.1249)">
|
||||
<path
|
||||
d="M50.886 286.515l-40.4-44.46 44.459-40.401 40.401 44.46z"
|
||||
fill="none"
|
||||
stroke={color}
|
||||
strokeWidth="11.90597031"
|
||||
/>
|
||||
<circle cx="52.917" cy="244.083" r="11.025" fill={color} />
|
||||
<path d="M50.886 286.515l-40.4-44.46 44.459-40.401 40.401 44.46z" fill="none" strokeWidth="11.90597031" />
|
||||
<circle cx="52.917" cy="244.083" r="11.025" />
|
||||
</g>
|
||||
</svg>
|
||||
</Icon>
|
||||
);
|
||||
};
|
||||
|
||||
Citadel.defaultProps = {
|
||||
size: 16,
|
||||
color: '#7367f0',
|
||||
};
|
||||
|
||||
export default Citadel;
|
||||
|
12
web/src/shared/icons/Filter.tsx
Normal file
12
web/src/shared/icons/Filter.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import Icon, { IconProps } from './Icon';
|
||||
|
||||
const Filter: React.FC<IconProps> = ({ width = '16px', height = '16px', className }) => {
|
||||
return (
|
||||
<Icon width={width} height={height} className={className} viewBox="0 0 512 512">
|
||||
<path d="M487.976 0H24.028C2.71 0-8.047 25.866 7.058 40.971L192 225.941V432c0 7.831 3.821 15.17 10.237 19.662l80 55.98C298.02 518.69 320 507.493 320 487.98V225.941l184.947-184.97C520.021 25.896 509.338 0 487.976 0z" />
|
||||
</Icon>
|
||||
);
|
||||
};
|
||||
|
||||
export default Filter;
|
@ -1,21 +1,12 @@
|
||||
import React from 'react';
|
||||
import Icon, { IconProps } from './Icon';
|
||||
|
||||
type Props = {
|
||||
size: number | string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
const Home = ({ size, color }: Props) => {
|
||||
const Checkmark: React.FC<IconProps> = ({ width = '16px', height = '16px', className }) => {
|
||||
return (
|
||||
<svg fill={color} xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16">
|
||||
<path d="M16 9.226l-8-6.21-8 6.21v-2.532l8-6.21 8 6.21zM14 9v6h-4v-4h-4v4h-4v-6l6-4.5z" />
|
||||
</svg>
|
||||
<Icon width={width} height={height} className={className} viewBox="0 0 576 512">
|
||||
<path d="M280.37 148.26L96 300.11V464a16 16 0 0 0 16 16l112.06-.29a16 16 0 0 0 15.92-16V368a16 16 0 0 1 16-16h64a16 16 0 0 1 16 16v95.64a16 16 0 0 0 16 16.05L464 480a16 16 0 0 0 16-16V300L295.67 148.26a12.19 12.19 0 0 0-15.3 0zM571.6 251.47L488 182.56V44.05a12 12 0 0 0-12-12h-56a12 12 0 0 0-12 12v72.61L318.47 43a48 48 0 0 0-61 0L4.34 251.47a12 12 0 0 0-1.6 16.9l25.5 31A12 12 0 0 0 45.15 301l235.22-193.74a12.19 12.19 0 0 1 15.3 0L530.9 301a12 12 0 0 0 16.9-1.6l25.5-31a12 12 0 0 0-1.7-16.93z" />
|
||||
</Icon>
|
||||
);
|
||||
};
|
||||
|
||||
Home.defaultProps = {
|
||||
size: 16,
|
||||
color: '#000',
|
||||
};
|
||||
|
||||
export default Home;
|
||||
export default Checkmark;
|
||||
|
@ -18,6 +18,7 @@ type Props = {
|
||||
|
||||
const Svg = styled.svg`
|
||||
fill: rgba(${props => props.theme.colors.text.primary});
|
||||
stroke: rgba(${props => props.theme.colors.text.primary});
|
||||
`;
|
||||
|
||||
const Icon: React.FC<Props> = ({ width, height, viewBox, className, onClick, children }) => {
|
||||
|
@ -1,21 +1,12 @@
|
||||
import React from 'react';
|
||||
import Icon, { IconProps } from './Icon';
|
||||
|
||||
type Props = {
|
||||
size: number | string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
const Lock = ({ size, color }: Props) => {
|
||||
const Lock: React.FC<IconProps> = ({ width = '16px', height = '16px', className }) => {
|
||||
return (
|
||||
<svg fill={color} xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16">
|
||||
<path d="M9.25 7h-0.25v-3c0-1.654-1.346-3-3-3h-2c-1.654 0-3 1.346-3 3v3h-0.25c-0.412 0-0.75 0.338-0.75 0.75v7.5c0 0.412 0.338 0.75 0.75 0.75h8.5c0.412 0 0.75-0.338 0.75-0.75v-7.5c0-0.412-0.338-0.75-0.75-0.75zM3 4c0-0.551 0.449-1 1-1h2c0.551 0 1 0.449 1 1v3h-4v-3z" />
|
||||
</svg>
|
||||
<Icon width={width} height={height} className={className} viewBox="0 0 448 512">
|
||||
<path d="M400 224h-24v-72C376 68.2 307.8 0 224 0S72 68.2 72 152v72H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48zm-104 0H152v-72c0-39.7 32.3-72 72-72s72 32.3 72 72v72z" />
|
||||
</Icon>
|
||||
);
|
||||
};
|
||||
|
||||
Lock.defaultProps = {
|
||||
size: 16,
|
||||
color: '#000',
|
||||
};
|
||||
|
||||
export default Lock;
|
||||
|
@ -1,21 +1,12 @@
|
||||
import React from 'react';
|
||||
import Icon, { IconProps } from './Icon';
|
||||
|
||||
type Props = {
|
||||
size: number | string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
const Pencil = ({ size, color }: Props) => {
|
||||
const Sort: React.FC<IconProps> = ({ width = '16px', height = '16px', className }) => {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill={color} width={size} height={size} viewBox="0 0 16 16">
|
||||
<path d="M13.5 0c1.381 0 2.5 1.119 2.5 2.5 0 0.563-0.186 1.082-0.5 1.5l-1 1-3.5-3.5 1-1c0.418-0.314 0.937-0.5 1.5-0.5zM1 11.5l-1 4.5 4.5-1 9.25-9.25-3.5-3.5-9.25 9.25zM11.181 5.681l-7 7-0.862-0.862 7-7 0.862 0.862z" />
|
||||
</svg>
|
||||
<Icon width={width} height={height} className={className} viewBox="0 0 512 512">
|
||||
<path d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z" />
|
||||
</Icon>
|
||||
);
|
||||
};
|
||||
|
||||
Pencil.defaultProps = {
|
||||
size: 16,
|
||||
color: '#000',
|
||||
};
|
||||
|
||||
export default Pencil;
|
||||
export default Sort;
|
||||
|
12
web/src/shared/icons/Sort.tsx
Normal file
12
web/src/shared/icons/Sort.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import Icon, { IconProps } from './Icon';
|
||||
|
||||
const Sort: React.FC<IconProps> = ({ width = '16px', height = '16px', className }) => {
|
||||
return (
|
||||
<Icon width={width} height={height} className={className} viewBox="0 0 320 512">
|
||||
<path d="M41 288h238c21.4 0 32.1 25.9 17 41L177 448c-9.4 9.4-24.6 9.4-33.9 0L24 329c-15.1-15.1-4.4-41 17-41zm255-105L177 64c-9.4-9.4-24.6-9.4-33.9 0L24 183c-15.1 15.1-4.4 41 17 41h238c21.4 0 32.1-25.9 17-41z" />
|
||||
</Icon>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sort;
|
@ -1,5 +1,8 @@
|
||||
import Cross from './Cross';
|
||||
import Cog from './Cog';
|
||||
import Sort from './Sort';
|
||||
import Filter from './Filter';
|
||||
import BarChart from './BarChart';
|
||||
import Trash from './Trash';
|
||||
import CheckCircle from './CheckCircle';
|
||||
import Clock from './Clock';
|
||||
@ -58,6 +61,9 @@ export {
|
||||
Clock,
|
||||
CheckSquareOutline,
|
||||
CheckSquare,
|
||||
BarChart,
|
||||
Square,
|
||||
Filter,
|
||||
Sort,
|
||||
ToggleOn,
|
||||
};
|
||||
|
@ -2,6 +2,21 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@apollo/client@^3.0.0-rc.8":
|
||||
version "3.0.0-rc.8"
|
||||
resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.0.0-rc.8.tgz#70643547ed8bb10d1d96f64320c3510a57f0cf6a"
|
||||
integrity sha512-8Sw4Htao2mZb4vERbvMj9GOf4x/+CLYNuF5gULY7TtMWG4ZANLxbe1DeFCicxVo2xRVQ960nf5vVJhxKcjDOQA==
|
||||
dependencies:
|
||||
"@types/zen-observable" "^0.8.0"
|
||||
"@wry/equality" "^0.1.9"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
graphql-tag "^2.10.2"
|
||||
optimism "^0.12.1"
|
||||
symbol-observable "^1.2.0"
|
||||
ts-invariant "^0.4.4"
|
||||
tslib "^1.10.0"
|
||||
zen-observable "^0.8.14"
|
||||
|
||||
"@apollo/federation@0.13.2":
|
||||
version "0.13.2"
|
||||
resolved "https://registry.yarnpkg.com/@apollo/federation/-/federation-0.13.2.tgz#a9f842abd1619fe5cd732c56cfbc45dab0ae784a"
|
||||
@ -3637,6 +3652,13 @@
|
||||
"@types/node" ">=6"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@wry/context@^0.5.2":
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.5.2.tgz#f2a5d5ab9227343aa74c81e06533c1ef84598ec7"
|
||||
integrity sha512-B/JLuRZ/vbEKHRUiGj6xiMojST1kHhu4WcreLfNN7q9DqQFrb97cWgf/kiYsPSUCAMVN0HzfFc8XjJdzgZzfjw==
|
||||
dependencies:
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@wry/equality@^0.1.2", "@wry/equality@^0.1.9":
|
||||
version "0.1.9"
|
||||
resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.9.tgz#b13e18b7a8053c6858aa6c85b54911fb31e3a909"
|
||||
@ -8349,7 +8371,7 @@ graphql-request@^1.5.0:
|
||||
dependencies:
|
||||
cross-fetch "2.2.2"
|
||||
|
||||
graphql-tag@2.10.3, graphql-tag@^2.10.1, graphql-tag@^2.10.3:
|
||||
graphql-tag@2.10.3, graphql-tag@^2.10.1, graphql-tag@^2.10.2, graphql-tag@^2.10.3:
|
||||
version "2.10.3"
|
||||
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.3.tgz#ea1baba5eb8fc6339e4c4cf049dabe522b0edf03"
|
||||
integrity sha512-4FOv3ZKfA4WdOKJeHdz6B3F/vxBLSgmBcGeAFPf4n1F64ltJUvOOerNj0rsJxONQGdhUMynQIvd6LzB+1J5oKA==
|
||||
@ -11668,6 +11690,13 @@ optimism@^0.10.0:
|
||||
dependencies:
|
||||
"@wry/context" "^0.4.0"
|
||||
|
||||
optimism@^0.12.1:
|
||||
version "0.12.1"
|
||||
resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.12.1.tgz#933f9467b9aef0e601655adb9638f893e486ad02"
|
||||
integrity sha512-t8I7HM1dw0SECitBYAqFOVHoBAHEQBTeKjIL9y9ImHzAVkdyPK4ifTgM4VJRDtTUY4r/u5Eqxs4XcGPHaoPkeQ==
|
||||
dependencies:
|
||||
"@wry/context" "^0.5.2"
|
||||
|
||||
optimize-css-assets-webpack-plugin@5.0.3:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.3.tgz#e2f1d4d94ad8c0af8967ebd7cf138dcb1ef14572"
|
||||
@ -17236,7 +17265,7 @@ zen-observable-ts@^0.8.21:
|
||||
tslib "^1.9.3"
|
||||
zen-observable "^0.8.0"
|
||||
|
||||
zen-observable@^0.8.0:
|
||||
zen-observable@^0.8.0, zen-observable@^0.8.14:
|
||||
version "0.8.15"
|
||||
resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15"
|
||||
integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==
|
||||
|
Loading…
Reference in New Issue
Block a user