feature: add more to project pane
This commit is contained in:
parent
7e78ee36b4
commit
fba4de631f
@ -41,9 +41,11 @@ type ResolverRoot interface {
|
|||||||
Project() ProjectResolver
|
Project() ProjectResolver
|
||||||
ProjectLabel() ProjectLabelResolver
|
ProjectLabel() ProjectLabelResolver
|
||||||
Query() QueryResolver
|
Query() QueryResolver
|
||||||
|
RefreshToken() RefreshTokenResolver
|
||||||
Task() TaskResolver
|
Task() TaskResolver
|
||||||
TaskGroup() TaskGroupResolver
|
TaskGroup() TaskGroupResolver
|
||||||
TaskLabel() TaskLabelResolver
|
TaskLabel() TaskLabelResolver
|
||||||
|
Team() TeamResolver
|
||||||
UserAccount() UserAccountResolver
|
UserAccount() UserAccountResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,27 +92,27 @@ type ComplexityRoot struct {
|
|||||||
|
|
||||||
Project struct {
|
Project struct {
|
||||||
CreatedAt func(childComplexity int) int
|
CreatedAt func(childComplexity int) int
|
||||||
|
ID func(childComplexity int) int
|
||||||
Labels func(childComplexity int) int
|
Labels func(childComplexity int) int
|
||||||
Members func(childComplexity int) int
|
Members func(childComplexity int) int
|
||||||
Name func(childComplexity int) int
|
Name func(childComplexity int) int
|
||||||
Owner func(childComplexity int) int
|
Owner func(childComplexity int) int
|
||||||
ProjectID func(childComplexity int) int
|
|
||||||
TaskGroups func(childComplexity int) int
|
TaskGroups func(childComplexity int) int
|
||||||
Team func(childComplexity int) int
|
Team func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectLabel struct {
|
ProjectLabel struct {
|
||||||
ColorHex func(childComplexity int) int
|
ColorHex func(childComplexity int) int
|
||||||
CreatedDate func(childComplexity int) int
|
CreatedDate func(childComplexity int) int
|
||||||
Name func(childComplexity int) int
|
ID func(childComplexity int) int
|
||||||
ProjectLabelID func(childComplexity int) int
|
Name func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectMember struct {
|
ProjectMember struct {
|
||||||
FirstName func(childComplexity int) int
|
FirstName func(childComplexity int) int
|
||||||
|
ID func(childComplexity int) int
|
||||||
LastName func(childComplexity int) int
|
LastName func(childComplexity int) int
|
||||||
ProfileIcon func(childComplexity int) int
|
ProfileIcon func(childComplexity int) int
|
||||||
UserID func(childComplexity int) int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Query struct {
|
Query struct {
|
||||||
@ -126,7 +128,7 @@ type ComplexityRoot struct {
|
|||||||
RefreshToken struct {
|
RefreshToken struct {
|
||||||
CreatedAt func(childComplexity int) int
|
CreatedAt func(childComplexity int) int
|
||||||
ExpiresAt func(childComplexity int) int
|
ExpiresAt func(childComplexity int) int
|
||||||
TokenID func(childComplexity int) int
|
ID func(childComplexity int) int
|
||||||
UserID func(childComplexity int) int
|
UserID func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,43 +136,43 @@ type ComplexityRoot struct {
|
|||||||
Assigned func(childComplexity int) int
|
Assigned func(childComplexity int) int
|
||||||
CreatedAt func(childComplexity int) int
|
CreatedAt func(childComplexity int) int
|
||||||
Description func(childComplexity int) int
|
Description func(childComplexity int) int
|
||||||
|
ID func(childComplexity int) int
|
||||||
Labels func(childComplexity int) int
|
Labels func(childComplexity int) int
|
||||||
Name func(childComplexity int) int
|
Name func(childComplexity int) int
|
||||||
Position func(childComplexity int) int
|
Position func(childComplexity int) int
|
||||||
TaskGroup func(childComplexity int) int
|
TaskGroup func(childComplexity int) int
|
||||||
TaskID func(childComplexity int) int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskGroup struct {
|
TaskGroup struct {
|
||||||
CreatedAt func(childComplexity int) int
|
CreatedAt func(childComplexity int) int
|
||||||
Name func(childComplexity int) int
|
ID func(childComplexity int) int
|
||||||
Position func(childComplexity int) int
|
Name func(childComplexity int) int
|
||||||
ProjectID func(childComplexity int) int
|
Position func(childComplexity int) int
|
||||||
TaskGroupID func(childComplexity int) int
|
ProjectID func(childComplexity int) int
|
||||||
Tasks func(childComplexity int) int
|
Tasks func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskLabel struct {
|
TaskLabel struct {
|
||||||
AssignedDate func(childComplexity int) int
|
AssignedDate func(childComplexity int) int
|
||||||
ColorHex func(childComplexity int) int
|
ColorHex func(childComplexity int) int
|
||||||
|
ID func(childComplexity int) int
|
||||||
Name func(childComplexity int) int
|
Name func(childComplexity int) int
|
||||||
ProjectLabelID func(childComplexity int) int
|
ProjectLabelID func(childComplexity int) int
|
||||||
TaskLabelID func(childComplexity int) int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Team struct {
|
Team struct {
|
||||||
CreatedAt func(childComplexity int) int
|
CreatedAt func(childComplexity int) int
|
||||||
|
ID func(childComplexity int) int
|
||||||
Name func(childComplexity int) int
|
Name func(childComplexity int) int
|
||||||
TeamID func(childComplexity int) int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UserAccount struct {
|
UserAccount struct {
|
||||||
CreatedAt func(childComplexity int) int
|
CreatedAt func(childComplexity int) int
|
||||||
Email func(childComplexity int) int
|
Email func(childComplexity int) int
|
||||||
FirstName func(childComplexity int) int
|
FirstName func(childComplexity int) int
|
||||||
|
ID func(childComplexity int) int
|
||||||
LastName func(childComplexity int) int
|
LastName func(childComplexity int) int
|
||||||
ProfileIcon func(childComplexity int) int
|
ProfileIcon func(childComplexity int) int
|
||||||
UserID func(childComplexity int) int
|
|
||||||
Username func(childComplexity int) int
|
Username func(childComplexity int) int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,6 +198,8 @@ type MutationResolver interface {
|
|||||||
LogoutUser(ctx context.Context, input LogoutUser) (bool, error)
|
LogoutUser(ctx context.Context, input LogoutUser) (bool, error)
|
||||||
}
|
}
|
||||||
type ProjectResolver interface {
|
type ProjectResolver interface {
|
||||||
|
ID(ctx context.Context, obj *pg.Project) (uuid.UUID, error)
|
||||||
|
|
||||||
Team(ctx context.Context, obj *pg.Project) (*pg.Team, error)
|
Team(ctx context.Context, obj *pg.Project) (*pg.Team, error)
|
||||||
Owner(ctx context.Context, obj *pg.Project) (*ProjectMember, error)
|
Owner(ctx context.Context, obj *pg.Project) (*ProjectMember, error)
|
||||||
TaskGroups(ctx context.Context, obj *pg.Project) ([]pg.TaskGroup, error)
|
TaskGroups(ctx context.Context, obj *pg.Project) ([]pg.TaskGroup, error)
|
||||||
@ -203,6 +207,8 @@ type ProjectResolver interface {
|
|||||||
Labels(ctx context.Context, obj *pg.Project) ([]pg.ProjectLabel, error)
|
Labels(ctx context.Context, obj *pg.Project) ([]pg.ProjectLabel, error)
|
||||||
}
|
}
|
||||||
type ProjectLabelResolver interface {
|
type ProjectLabelResolver interface {
|
||||||
|
ID(ctx context.Context, obj *pg.ProjectLabel) (uuid.UUID, error)
|
||||||
|
|
||||||
ColorHex(ctx context.Context, obj *pg.ProjectLabel) (string, error)
|
ColorHex(ctx context.Context, obj *pg.ProjectLabel) (string, error)
|
||||||
Name(ctx context.Context, obj *pg.ProjectLabel) (*string, error)
|
Name(ctx context.Context, obj *pg.ProjectLabel) (*string, error)
|
||||||
}
|
}
|
||||||
@ -215,7 +221,11 @@ type QueryResolver interface {
|
|||||||
TaskGroups(ctx context.Context) ([]pg.TaskGroup, error)
|
TaskGroups(ctx context.Context) ([]pg.TaskGroup, error)
|
||||||
Me(ctx context.Context) (*pg.UserAccount, error)
|
Me(ctx context.Context) (*pg.UserAccount, error)
|
||||||
}
|
}
|
||||||
|
type RefreshTokenResolver interface {
|
||||||
|
ID(ctx context.Context, obj *pg.RefreshToken) (uuid.UUID, error)
|
||||||
|
}
|
||||||
type TaskResolver interface {
|
type TaskResolver interface {
|
||||||
|
ID(ctx context.Context, obj *pg.Task) (uuid.UUID, error)
|
||||||
TaskGroup(ctx context.Context, obj *pg.Task) (*pg.TaskGroup, error)
|
TaskGroup(ctx context.Context, obj *pg.Task) (*pg.TaskGroup, error)
|
||||||
|
|
||||||
Description(ctx context.Context, obj *pg.Task) (*string, error)
|
Description(ctx context.Context, obj *pg.Task) (*string, error)
|
||||||
@ -223,15 +233,23 @@ type TaskResolver interface {
|
|||||||
Labels(ctx context.Context, obj *pg.Task) ([]pg.TaskLabel, error)
|
Labels(ctx context.Context, obj *pg.Task) ([]pg.TaskLabel, error)
|
||||||
}
|
}
|
||||||
type TaskGroupResolver interface {
|
type TaskGroupResolver interface {
|
||||||
|
ID(ctx context.Context, obj *pg.TaskGroup) (uuid.UUID, error)
|
||||||
ProjectID(ctx context.Context, obj *pg.TaskGroup) (string, error)
|
ProjectID(ctx context.Context, obj *pg.TaskGroup) (string, error)
|
||||||
|
|
||||||
Tasks(ctx context.Context, obj *pg.TaskGroup) ([]pg.Task, error)
|
Tasks(ctx context.Context, obj *pg.TaskGroup) ([]pg.Task, error)
|
||||||
}
|
}
|
||||||
type TaskLabelResolver interface {
|
type TaskLabelResolver interface {
|
||||||
|
ID(ctx context.Context, obj *pg.TaskLabel) (uuid.UUID, error)
|
||||||
|
|
||||||
ColorHex(ctx context.Context, obj *pg.TaskLabel) (string, error)
|
ColorHex(ctx context.Context, obj *pg.TaskLabel) (string, error)
|
||||||
Name(ctx context.Context, obj *pg.TaskLabel) (*string, error)
|
Name(ctx context.Context, obj *pg.TaskLabel) (*string, error)
|
||||||
}
|
}
|
||||||
|
type TeamResolver interface {
|
||||||
|
ID(ctx context.Context, obj *pg.Team) (uuid.UUID, error)
|
||||||
|
}
|
||||||
type UserAccountResolver interface {
|
type UserAccountResolver interface {
|
||||||
|
ID(ctx context.Context, obj *pg.UserAccount) (uuid.UUID, error)
|
||||||
|
|
||||||
ProfileIcon(ctx context.Context, obj *pg.UserAccount) (*ProfileIcon, error)
|
ProfileIcon(ctx context.Context, obj *pg.UserAccount) (*ProfileIcon, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,6 +540,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Project.CreatedAt(childComplexity), true
|
return e.complexity.Project.CreatedAt(childComplexity), true
|
||||||
|
|
||||||
|
case "Project.id":
|
||||||
|
if e.complexity.Project.ID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Project.ID(childComplexity), true
|
||||||
|
|
||||||
case "Project.labels":
|
case "Project.labels":
|
||||||
if e.complexity.Project.Labels == nil {
|
if e.complexity.Project.Labels == nil {
|
||||||
break
|
break
|
||||||
@ -550,13 +575,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Project.Owner(childComplexity), true
|
return e.complexity.Project.Owner(childComplexity), true
|
||||||
|
|
||||||
case "Project.projectID":
|
|
||||||
if e.complexity.Project.ProjectID == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.Project.ProjectID(childComplexity), true
|
|
||||||
|
|
||||||
case "Project.taskGroups":
|
case "Project.taskGroups":
|
||||||
if e.complexity.Project.TaskGroups == nil {
|
if e.complexity.Project.TaskGroups == nil {
|
||||||
break
|
break
|
||||||
@ -585,6 +603,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.ProjectLabel.CreatedDate(childComplexity), true
|
return e.complexity.ProjectLabel.CreatedDate(childComplexity), true
|
||||||
|
|
||||||
|
case "ProjectLabel.id":
|
||||||
|
if e.complexity.ProjectLabel.ID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.ProjectLabel.ID(childComplexity), true
|
||||||
|
|
||||||
case "ProjectLabel.name":
|
case "ProjectLabel.name":
|
||||||
if e.complexity.ProjectLabel.Name == nil {
|
if e.complexity.ProjectLabel.Name == nil {
|
||||||
break
|
break
|
||||||
@ -592,13 +617,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.ProjectLabel.Name(childComplexity), true
|
return e.complexity.ProjectLabel.Name(childComplexity), true
|
||||||
|
|
||||||
case "ProjectLabel.projectLabelID":
|
|
||||||
if e.complexity.ProjectLabel.ProjectLabelID == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.ProjectLabel.ProjectLabelID(childComplexity), true
|
|
||||||
|
|
||||||
case "ProjectMember.firstName":
|
case "ProjectMember.firstName":
|
||||||
if e.complexity.ProjectMember.FirstName == nil {
|
if e.complexity.ProjectMember.FirstName == nil {
|
||||||
break
|
break
|
||||||
@ -606,6 +624,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.ProjectMember.FirstName(childComplexity), true
|
return e.complexity.ProjectMember.FirstName(childComplexity), true
|
||||||
|
|
||||||
|
case "ProjectMember.id":
|
||||||
|
if e.complexity.ProjectMember.ID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.ProjectMember.ID(childComplexity), true
|
||||||
|
|
||||||
case "ProjectMember.lastName":
|
case "ProjectMember.lastName":
|
||||||
if e.complexity.ProjectMember.LastName == nil {
|
if e.complexity.ProjectMember.LastName == nil {
|
||||||
break
|
break
|
||||||
@ -620,13 +645,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.ProjectMember.ProfileIcon(childComplexity), true
|
return e.complexity.ProjectMember.ProfileIcon(childComplexity), true
|
||||||
|
|
||||||
case "ProjectMember.userID":
|
|
||||||
if e.complexity.ProjectMember.UserID == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.ProjectMember.UserID(childComplexity), true
|
|
||||||
|
|
||||||
case "Query.findProject":
|
case "Query.findProject":
|
||||||
if e.complexity.Query.FindProject == nil {
|
if e.complexity.Query.FindProject == nil {
|
||||||
break
|
break
|
||||||
@ -710,12 +728,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.RefreshToken.ExpiresAt(childComplexity), true
|
return e.complexity.RefreshToken.ExpiresAt(childComplexity), true
|
||||||
|
|
||||||
case "RefreshToken.tokenId":
|
case "RefreshToken.id":
|
||||||
if e.complexity.RefreshToken.TokenID == nil {
|
if e.complexity.RefreshToken.ID == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.complexity.RefreshToken.TokenID(childComplexity), true
|
return e.complexity.RefreshToken.ID(childComplexity), true
|
||||||
|
|
||||||
case "RefreshToken.userId":
|
case "RefreshToken.userId":
|
||||||
if e.complexity.RefreshToken.UserID == nil {
|
if e.complexity.RefreshToken.UserID == nil {
|
||||||
@ -745,6 +763,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Task.Description(childComplexity), true
|
return e.complexity.Task.Description(childComplexity), true
|
||||||
|
|
||||||
|
case "Task.id":
|
||||||
|
if e.complexity.Task.ID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Task.ID(childComplexity), true
|
||||||
|
|
||||||
case "Task.labels":
|
case "Task.labels":
|
||||||
if e.complexity.Task.Labels == nil {
|
if e.complexity.Task.Labels == nil {
|
||||||
break
|
break
|
||||||
@ -773,13 +798,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Task.TaskGroup(childComplexity), true
|
return e.complexity.Task.TaskGroup(childComplexity), true
|
||||||
|
|
||||||
case "Task.taskID":
|
|
||||||
if e.complexity.Task.TaskID == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.Task.TaskID(childComplexity), true
|
|
||||||
|
|
||||||
case "TaskGroup.createdAt":
|
case "TaskGroup.createdAt":
|
||||||
if e.complexity.TaskGroup.CreatedAt == nil {
|
if e.complexity.TaskGroup.CreatedAt == nil {
|
||||||
break
|
break
|
||||||
@ -787,6 +805,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.TaskGroup.CreatedAt(childComplexity), true
|
return e.complexity.TaskGroup.CreatedAt(childComplexity), true
|
||||||
|
|
||||||
|
case "TaskGroup.id":
|
||||||
|
if e.complexity.TaskGroup.ID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.TaskGroup.ID(childComplexity), true
|
||||||
|
|
||||||
case "TaskGroup.name":
|
case "TaskGroup.name":
|
||||||
if e.complexity.TaskGroup.Name == nil {
|
if e.complexity.TaskGroup.Name == nil {
|
||||||
break
|
break
|
||||||
@ -808,13 +833,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.TaskGroup.ProjectID(childComplexity), true
|
return e.complexity.TaskGroup.ProjectID(childComplexity), true
|
||||||
|
|
||||||
case "TaskGroup.taskGroupID":
|
|
||||||
if e.complexity.TaskGroup.TaskGroupID == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.TaskGroup.TaskGroupID(childComplexity), true
|
|
||||||
|
|
||||||
case "TaskGroup.tasks":
|
case "TaskGroup.tasks":
|
||||||
if e.complexity.TaskGroup.Tasks == nil {
|
if e.complexity.TaskGroup.Tasks == nil {
|
||||||
break
|
break
|
||||||
@ -836,6 +854,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.TaskLabel.ColorHex(childComplexity), true
|
return e.complexity.TaskLabel.ColorHex(childComplexity), true
|
||||||
|
|
||||||
|
case "TaskLabel.id":
|
||||||
|
if e.complexity.TaskLabel.ID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.TaskLabel.ID(childComplexity), true
|
||||||
|
|
||||||
case "TaskLabel.name":
|
case "TaskLabel.name":
|
||||||
if e.complexity.TaskLabel.Name == nil {
|
if e.complexity.TaskLabel.Name == nil {
|
||||||
break
|
break
|
||||||
@ -850,13 +875,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.TaskLabel.ProjectLabelID(childComplexity), true
|
return e.complexity.TaskLabel.ProjectLabelID(childComplexity), true
|
||||||
|
|
||||||
case "TaskLabel.taskLabelID":
|
|
||||||
if e.complexity.TaskLabel.TaskLabelID == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.TaskLabel.TaskLabelID(childComplexity), true
|
|
||||||
|
|
||||||
case "Team.createdAt":
|
case "Team.createdAt":
|
||||||
if e.complexity.Team.CreatedAt == nil {
|
if e.complexity.Team.CreatedAt == nil {
|
||||||
break
|
break
|
||||||
@ -864,6 +882,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Team.CreatedAt(childComplexity), true
|
return e.complexity.Team.CreatedAt(childComplexity), true
|
||||||
|
|
||||||
|
case "Team.id":
|
||||||
|
if e.complexity.Team.ID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Team.ID(childComplexity), true
|
||||||
|
|
||||||
case "Team.name":
|
case "Team.name":
|
||||||
if e.complexity.Team.Name == nil {
|
if e.complexity.Team.Name == nil {
|
||||||
break
|
break
|
||||||
@ -871,13 +896,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.Team.Name(childComplexity), true
|
return e.complexity.Team.Name(childComplexity), true
|
||||||
|
|
||||||
case "Team.teamID":
|
|
||||||
if e.complexity.Team.TeamID == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.Team.TeamID(childComplexity), true
|
|
||||||
|
|
||||||
case "UserAccount.createdAt":
|
case "UserAccount.createdAt":
|
||||||
if e.complexity.UserAccount.CreatedAt == nil {
|
if e.complexity.UserAccount.CreatedAt == nil {
|
||||||
break
|
break
|
||||||
@ -899,6 +917,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.UserAccount.FirstName(childComplexity), true
|
return e.complexity.UserAccount.FirstName(childComplexity), true
|
||||||
|
|
||||||
|
case "UserAccount.id":
|
||||||
|
if e.complexity.UserAccount.ID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.UserAccount.ID(childComplexity), true
|
||||||
|
|
||||||
case "UserAccount.lastName":
|
case "UserAccount.lastName":
|
||||||
if e.complexity.UserAccount.LastName == nil {
|
if e.complexity.UserAccount.LastName == nil {
|
||||||
break
|
break
|
||||||
@ -913,13 +938,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
|
|
||||||
return e.complexity.UserAccount.ProfileIcon(childComplexity), true
|
return e.complexity.UserAccount.ProfileIcon(childComplexity), true
|
||||||
|
|
||||||
case "UserAccount.userID":
|
|
||||||
if e.complexity.UserAccount.UserID == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.UserAccount.UserID(childComplexity), true
|
|
||||||
|
|
||||||
case "UserAccount.username":
|
case "UserAccount.username":
|
||||||
if e.complexity.UserAccount.Username == nil {
|
if e.complexity.UserAccount.Username == nil {
|
||||||
break
|
break
|
||||||
@ -995,14 +1013,14 @@ var sources = []*ast.Source{
|
|||||||
scalar UUID
|
scalar UUID
|
||||||
|
|
||||||
type ProjectLabel {
|
type ProjectLabel {
|
||||||
projectLabelID: ID!
|
id: ID!
|
||||||
createdDate: Time!
|
createdDate: Time!
|
||||||
colorHex: String!
|
colorHex: String!
|
||||||
name: String
|
name: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaskLabel {
|
type TaskLabel {
|
||||||
taskLabelID: ID!
|
id: ID!
|
||||||
projectLabelID: UUID!
|
projectLabelID: UUID!
|
||||||
assignedDate: Time!
|
assignedDate: Time!
|
||||||
colorHex: String!
|
colorHex: String!
|
||||||
@ -1016,21 +1034,21 @@ type ProfileIcon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ProjectMember {
|
type ProjectMember {
|
||||||
userID: ID!
|
id: ID!
|
||||||
firstName: String!
|
firstName: String!
|
||||||
lastName: String!
|
lastName: String!
|
||||||
profileIcon: ProfileIcon!
|
profileIcon: ProfileIcon!
|
||||||
}
|
}
|
||||||
|
|
||||||
type RefreshToken {
|
type RefreshToken {
|
||||||
tokenId: ID!
|
id: ID!
|
||||||
userId: UUID!
|
userId: UUID!
|
||||||
expiresAt: Time!
|
expiresAt: Time!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserAccount {
|
type UserAccount {
|
||||||
userID: ID!
|
id: ID!
|
||||||
email: String!
|
email: String!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
firstName: String!
|
firstName: String!
|
||||||
@ -1040,13 +1058,13 @@ type UserAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Team {
|
type Team {
|
||||||
teamID: ID!
|
id: ID!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
name: String!
|
name: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Project {
|
type Project {
|
||||||
projectID: ID!
|
id: ID!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
name: String!
|
name: String!
|
||||||
team: Team!
|
team: Team!
|
||||||
@ -1057,7 +1075,7 @@ type Project {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TaskGroup {
|
type TaskGroup {
|
||||||
taskGroupID: ID!
|
id: ID!
|
||||||
projectID: String!
|
projectID: String!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
name: String!
|
name: String!
|
||||||
@ -1066,7 +1084,7 @@ type TaskGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Task {
|
type Task {
|
||||||
taskID: ID!
|
id: ID!
|
||||||
taskGroup: TaskGroup!
|
taskGroup: TaskGroup!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
name: String!
|
name: String!
|
||||||
@ -2563,7 +2581,7 @@ func (ec *executionContext) _ProfileIcon_bgColor(ctx context.Context, field grap
|
|||||||
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Project_projectID(ctx context.Context, field graphql.CollectedField, obj *pg.Project) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Project_id(ctx context.Context, field graphql.CollectedField, obj *pg.Project) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
@ -2574,13 +2592,13 @@ func (ec *executionContext) _Project_projectID(ctx context.Context, field graphq
|
|||||||
Object: "Project",
|
Object: "Project",
|
||||||
Field: field,
|
Field: field,
|
||||||
Args: nil,
|
Args: nil,
|
||||||
IsMethod: false,
|
IsMethod: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return obj.ProjectID, nil
|
return ec.resolvers.Project().ID(rctx, obj)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@ -2835,7 +2853,7 @@ func (ec *executionContext) _Project_labels(ctx context.Context, field graphql.C
|
|||||||
return ec.marshalNProjectLabel2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐProjectLabelᚄ(ctx, field.Selections, res)
|
return ec.marshalNProjectLabel2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐProjectLabelᚄ(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _ProjectLabel_projectLabelID(ctx context.Context, field graphql.CollectedField, obj *pg.ProjectLabel) (ret graphql.Marshaler) {
|
func (ec *executionContext) _ProjectLabel_id(ctx context.Context, field graphql.CollectedField, obj *pg.ProjectLabel) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
@ -2846,13 +2864,13 @@ func (ec *executionContext) _ProjectLabel_projectLabelID(ctx context.Context, fi
|
|||||||
Object: "ProjectLabel",
|
Object: "ProjectLabel",
|
||||||
Field: field,
|
Field: field,
|
||||||
Args: nil,
|
Args: nil,
|
||||||
IsMethod: false,
|
IsMethod: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return obj.ProjectLabelID, nil
|
return ec.resolvers.ProjectLabel().ID(rctx, obj)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@ -2968,7 +2986,7 @@ func (ec *executionContext) _ProjectLabel_name(ctx context.Context, field graphq
|
|||||||
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _ProjectMember_userID(ctx context.Context, field graphql.CollectedField, obj *ProjectMember) (ret graphql.Marshaler) {
|
func (ec *executionContext) _ProjectMember_id(ctx context.Context, field graphql.CollectedField, obj *ProjectMember) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
@ -2985,7 +3003,7 @@ func (ec *executionContext) _ProjectMember_userID(ctx context.Context, field gra
|
|||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return obj.UserID, nil
|
return obj.ID, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@ -3439,7 +3457,7 @@ func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.C
|
|||||||
return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res)
|
return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _RefreshToken_tokenId(ctx context.Context, field graphql.CollectedField, obj *pg.RefreshToken) (ret graphql.Marshaler) {
|
func (ec *executionContext) _RefreshToken_id(ctx context.Context, field graphql.CollectedField, obj *pg.RefreshToken) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
@ -3450,13 +3468,13 @@ func (ec *executionContext) _RefreshToken_tokenId(ctx context.Context, field gra
|
|||||||
Object: "RefreshToken",
|
Object: "RefreshToken",
|
||||||
Field: field,
|
Field: field,
|
||||||
Args: nil,
|
Args: nil,
|
||||||
IsMethod: false,
|
IsMethod: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return obj.TokenID, nil
|
return ec.resolvers.RefreshToken().ID(rctx, obj)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@ -3575,7 +3593,7 @@ func (ec *executionContext) _RefreshToken_createdAt(ctx context.Context, field g
|
|||||||
return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res)
|
return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Task_taskID(ctx context.Context, field graphql.CollectedField, obj *pg.Task) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Task_id(ctx context.Context, field graphql.CollectedField, obj *pg.Task) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
@ -3586,13 +3604,13 @@ func (ec *executionContext) _Task_taskID(ctx context.Context, field graphql.Coll
|
|||||||
Object: "Task",
|
Object: "Task",
|
||||||
Field: field,
|
Field: field,
|
||||||
Args: nil,
|
Args: nil,
|
||||||
IsMethod: false,
|
IsMethod: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return obj.TaskID, nil
|
return ec.resolvers.Task().ID(rctx, obj)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@ -3844,7 +3862,7 @@ func (ec *executionContext) _Task_labels(ctx context.Context, field graphql.Coll
|
|||||||
return ec.marshalNTaskLabel2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTaskLabelᚄ(ctx, field.Selections, res)
|
return ec.marshalNTaskLabel2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTaskLabelᚄ(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _TaskGroup_taskGroupID(ctx context.Context, field graphql.CollectedField, obj *pg.TaskGroup) (ret graphql.Marshaler) {
|
func (ec *executionContext) _TaskGroup_id(ctx context.Context, field graphql.CollectedField, obj *pg.TaskGroup) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
@ -3855,13 +3873,13 @@ func (ec *executionContext) _TaskGroup_taskGroupID(ctx context.Context, field gr
|
|||||||
Object: "TaskGroup",
|
Object: "TaskGroup",
|
||||||
Field: field,
|
Field: field,
|
||||||
Args: nil,
|
Args: nil,
|
||||||
IsMethod: false,
|
IsMethod: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return obj.TaskGroupID, nil
|
return ec.resolvers.TaskGroup().ID(rctx, obj)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@ -4048,7 +4066,7 @@ func (ec *executionContext) _TaskGroup_tasks(ctx context.Context, field graphql.
|
|||||||
return ec.marshalNTask2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTaskᚄ(ctx, field.Selections, res)
|
return ec.marshalNTask2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTaskᚄ(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _TaskLabel_taskLabelID(ctx context.Context, field graphql.CollectedField, obj *pg.TaskLabel) (ret graphql.Marshaler) {
|
func (ec *executionContext) _TaskLabel_id(ctx context.Context, field graphql.CollectedField, obj *pg.TaskLabel) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
@ -4059,13 +4077,13 @@ func (ec *executionContext) _TaskLabel_taskLabelID(ctx context.Context, field gr
|
|||||||
Object: "TaskLabel",
|
Object: "TaskLabel",
|
||||||
Field: field,
|
Field: field,
|
||||||
Args: nil,
|
Args: nil,
|
||||||
IsMethod: false,
|
IsMethod: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return obj.TaskLabelID, nil
|
return ec.resolvers.TaskLabel().ID(rctx, obj)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@ -4215,7 +4233,7 @@ func (ec *executionContext) _TaskLabel_name(ctx context.Context, field graphql.C
|
|||||||
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Team_teamID(ctx context.Context, field graphql.CollectedField, obj *pg.Team) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Team_id(ctx context.Context, field graphql.CollectedField, obj *pg.Team) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
@ -4226,13 +4244,13 @@ func (ec *executionContext) _Team_teamID(ctx context.Context, field graphql.Coll
|
|||||||
Object: "Team",
|
Object: "Team",
|
||||||
Field: field,
|
Field: field,
|
||||||
Args: nil,
|
Args: nil,
|
||||||
IsMethod: false,
|
IsMethod: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return obj.TeamID, nil
|
return ec.resolvers.Team().ID(rctx, obj)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@ -4317,7 +4335,7 @@ func (ec *executionContext) _Team_name(ctx context.Context, field graphql.Collec
|
|||||||
return ec.marshalNString2string(ctx, field.Selections, res)
|
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _UserAccount_userID(ctx context.Context, field graphql.CollectedField, obj *pg.UserAccount) (ret graphql.Marshaler) {
|
func (ec *executionContext) _UserAccount_id(ctx context.Context, field graphql.CollectedField, obj *pg.UserAccount) (ret graphql.Marshaler) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
@ -4328,13 +4346,13 @@ func (ec *executionContext) _UserAccount_userID(ctx context.Context, field graph
|
|||||||
Object: "UserAccount",
|
Object: "UserAccount",
|
||||||
Field: field,
|
Field: field,
|
||||||
Args: nil,
|
Args: nil,
|
||||||
IsMethod: false,
|
IsMethod: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return obj.UserID, nil
|
return ec.resolvers.UserAccount().ID(rctx, obj)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@ -6365,11 +6383,20 @@ func (ec *executionContext) _Project(ctx context.Context, sel ast.SelectionSet,
|
|||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "__typename":
|
case "__typename":
|
||||||
out.Values[i] = graphql.MarshalString("Project")
|
out.Values[i] = graphql.MarshalString("Project")
|
||||||
case "projectID":
|
case "id":
|
||||||
out.Values[i] = ec._Project_projectID(ctx, field, obj)
|
field := field
|
||||||
if out.Values[i] == graphql.Null {
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
atomic.AddUint32(&invalids, 1)
|
defer func() {
|
||||||
}
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
res = ec._Project_id(ctx, field, obj)
|
||||||
|
if res == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
case "createdAt":
|
case "createdAt":
|
||||||
out.Values[i] = ec._Project_createdAt(ctx, field, obj)
|
out.Values[i] = ec._Project_createdAt(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
@ -6472,11 +6499,20 @@ func (ec *executionContext) _ProjectLabel(ctx context.Context, sel ast.Selection
|
|||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "__typename":
|
case "__typename":
|
||||||
out.Values[i] = graphql.MarshalString("ProjectLabel")
|
out.Values[i] = graphql.MarshalString("ProjectLabel")
|
||||||
case "projectLabelID":
|
case "id":
|
||||||
out.Values[i] = ec._ProjectLabel_projectLabelID(ctx, field, obj)
|
field := field
|
||||||
if out.Values[i] == graphql.Null {
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
atomic.AddUint32(&invalids, 1)
|
defer func() {
|
||||||
}
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
res = ec._ProjectLabel_id(ctx, field, obj)
|
||||||
|
if res == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
case "createdDate":
|
case "createdDate":
|
||||||
out.Values[i] = ec._ProjectLabel_createdDate(ctx, field, obj)
|
out.Values[i] = ec._ProjectLabel_createdDate(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
@ -6529,8 +6565,8 @@ func (ec *executionContext) _ProjectMember(ctx context.Context, sel ast.Selectio
|
|||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "__typename":
|
case "__typename":
|
||||||
out.Values[i] = graphql.MarshalString("ProjectMember")
|
out.Values[i] = graphql.MarshalString("ProjectMember")
|
||||||
case "userID":
|
case "id":
|
||||||
out.Values[i] = ec._ProjectMember_userID(ctx, field, obj)
|
out.Values[i] = ec._ProjectMember_id(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
invalids++
|
||||||
}
|
}
|
||||||
@ -6699,25 +6735,34 @@ func (ec *executionContext) _RefreshToken(ctx context.Context, sel ast.Selection
|
|||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "__typename":
|
case "__typename":
|
||||||
out.Values[i] = graphql.MarshalString("RefreshToken")
|
out.Values[i] = graphql.MarshalString("RefreshToken")
|
||||||
case "tokenId":
|
case "id":
|
||||||
out.Values[i] = ec._RefreshToken_tokenId(ctx, field, obj)
|
field := field
|
||||||
if out.Values[i] == graphql.Null {
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
invalids++
|
defer func() {
|
||||||
}
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
res = ec._RefreshToken_id(ctx, field, obj)
|
||||||
|
if res == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
case "userId":
|
case "userId":
|
||||||
out.Values[i] = ec._RefreshToken_userId(ctx, field, obj)
|
out.Values[i] = ec._RefreshToken_userId(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
atomic.AddUint32(&invalids, 1)
|
||||||
}
|
}
|
||||||
case "expiresAt":
|
case "expiresAt":
|
||||||
out.Values[i] = ec._RefreshToken_expiresAt(ctx, field, obj)
|
out.Values[i] = ec._RefreshToken_expiresAt(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
atomic.AddUint32(&invalids, 1)
|
||||||
}
|
}
|
||||||
case "createdAt":
|
case "createdAt":
|
||||||
out.Values[i] = ec._RefreshToken_createdAt(ctx, field, obj)
|
out.Values[i] = ec._RefreshToken_createdAt(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
atomic.AddUint32(&invalids, 1)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
@ -6741,11 +6786,20 @@ func (ec *executionContext) _Task(ctx context.Context, sel ast.SelectionSet, obj
|
|||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "__typename":
|
case "__typename":
|
||||||
out.Values[i] = graphql.MarshalString("Task")
|
out.Values[i] = graphql.MarshalString("Task")
|
||||||
case "taskID":
|
case "id":
|
||||||
out.Values[i] = ec._Task_taskID(ctx, field, obj)
|
field := field
|
||||||
if out.Values[i] == graphql.Null {
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
atomic.AddUint32(&invalids, 1)
|
defer func() {
|
||||||
}
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
res = ec._Task_id(ctx, field, obj)
|
||||||
|
if res == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
case "taskGroup":
|
case "taskGroup":
|
||||||
field := field
|
field := field
|
||||||
out.Concurrently(i, func() (res graphql.Marshaler) {
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
@ -6836,11 +6890,20 @@ func (ec *executionContext) _TaskGroup(ctx context.Context, sel ast.SelectionSet
|
|||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "__typename":
|
case "__typename":
|
||||||
out.Values[i] = graphql.MarshalString("TaskGroup")
|
out.Values[i] = graphql.MarshalString("TaskGroup")
|
||||||
case "taskGroupID":
|
case "id":
|
||||||
out.Values[i] = ec._TaskGroup_taskGroupID(ctx, field, obj)
|
field := field
|
||||||
if out.Values[i] == graphql.Null {
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
atomic.AddUint32(&invalids, 1)
|
defer func() {
|
||||||
}
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
res = ec._TaskGroup_id(ctx, field, obj)
|
||||||
|
if res == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
case "projectID":
|
case "projectID":
|
||||||
field := field
|
field := field
|
||||||
out.Concurrently(i, func() (res graphql.Marshaler) {
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
@ -6906,11 +6969,20 @@ func (ec *executionContext) _TaskLabel(ctx context.Context, sel ast.SelectionSet
|
|||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "__typename":
|
case "__typename":
|
||||||
out.Values[i] = graphql.MarshalString("TaskLabel")
|
out.Values[i] = graphql.MarshalString("TaskLabel")
|
||||||
case "taskLabelID":
|
case "id":
|
||||||
out.Values[i] = ec._TaskLabel_taskLabelID(ctx, field, obj)
|
field := field
|
||||||
if out.Values[i] == graphql.Null {
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
atomic.AddUint32(&invalids, 1)
|
defer func() {
|
||||||
}
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
res = ec._TaskLabel_id(ctx, field, obj)
|
||||||
|
if res == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
case "projectLabelID":
|
case "projectLabelID":
|
||||||
out.Values[i] = ec._TaskLabel_projectLabelID(ctx, field, obj)
|
out.Values[i] = ec._TaskLabel_projectLabelID(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
@ -6968,20 +7040,29 @@ func (ec *executionContext) _Team(ctx context.Context, sel ast.SelectionSet, obj
|
|||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "__typename":
|
case "__typename":
|
||||||
out.Values[i] = graphql.MarshalString("Team")
|
out.Values[i] = graphql.MarshalString("Team")
|
||||||
case "teamID":
|
case "id":
|
||||||
out.Values[i] = ec._Team_teamID(ctx, field, obj)
|
field := field
|
||||||
if out.Values[i] == graphql.Null {
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
invalids++
|
defer func() {
|
||||||
}
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
res = ec._Team_id(ctx, field, obj)
|
||||||
|
if res == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
case "createdAt":
|
case "createdAt":
|
||||||
out.Values[i] = ec._Team_createdAt(ctx, field, obj)
|
out.Values[i] = ec._Team_createdAt(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
atomic.AddUint32(&invalids, 1)
|
||||||
}
|
}
|
||||||
case "name":
|
case "name":
|
||||||
out.Values[i] = ec._Team_name(ctx, field, obj)
|
out.Values[i] = ec._Team_name(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
invalids++
|
atomic.AddUint32(&invalids, 1)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
@ -7005,11 +7086,20 @@ func (ec *executionContext) _UserAccount(ctx context.Context, sel ast.SelectionS
|
|||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "__typename":
|
case "__typename":
|
||||||
out.Values[i] = graphql.MarshalString("UserAccount")
|
out.Values[i] = graphql.MarshalString("UserAccount")
|
||||||
case "userID":
|
case "id":
|
||||||
out.Values[i] = ec._UserAccount_userID(ctx, field, obj)
|
field := field
|
||||||
if out.Values[i] == graphql.Null {
|
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||||
atomic.AddUint32(&invalids, 1)
|
defer func() {
|
||||||
}
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
res = ec._UserAccount_id(ctx, field, obj)
|
||||||
|
if res == graphql.Null {
|
||||||
|
atomic.AddUint32(&invalids, 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
case "email":
|
case "email":
|
||||||
out.Values[i] = ec._UserAccount_email(ctx, field, obj)
|
out.Values[i] = ec._UserAccount_email(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
|
@ -110,7 +110,7 @@ type ProfileIcon struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ProjectMember struct {
|
type ProjectMember struct {
|
||||||
UserID uuid.UUID `json:"userID"`
|
ID uuid.UUID `json:"id"`
|
||||||
FirstName string `json:"firstName"`
|
FirstName string `json:"firstName"`
|
||||||
LastName string `json:"lastName"`
|
LastName string `json:"lastName"`
|
||||||
ProfileIcon *ProfileIcon `json:"profileIcon"`
|
ProfileIcon *ProfileIcon `json:"profileIcon"`
|
||||||
|
@ -2,14 +2,14 @@ scalar Time
|
|||||||
scalar UUID
|
scalar UUID
|
||||||
|
|
||||||
type ProjectLabel {
|
type ProjectLabel {
|
||||||
projectLabelID: ID!
|
id: ID!
|
||||||
createdDate: Time!
|
createdDate: Time!
|
||||||
colorHex: String!
|
colorHex: String!
|
||||||
name: String
|
name: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaskLabel {
|
type TaskLabel {
|
||||||
taskLabelID: ID!
|
id: ID!
|
||||||
projectLabelID: UUID!
|
projectLabelID: UUID!
|
||||||
assignedDate: Time!
|
assignedDate: Time!
|
||||||
colorHex: String!
|
colorHex: String!
|
||||||
@ -23,21 +23,21 @@ type ProfileIcon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ProjectMember {
|
type ProjectMember {
|
||||||
userID: ID!
|
id: ID!
|
||||||
firstName: String!
|
firstName: String!
|
||||||
lastName: String!
|
lastName: String!
|
||||||
profileIcon: ProfileIcon!
|
profileIcon: ProfileIcon!
|
||||||
}
|
}
|
||||||
|
|
||||||
type RefreshToken {
|
type RefreshToken {
|
||||||
tokenId: ID!
|
id: ID!
|
||||||
userId: UUID!
|
userId: UUID!
|
||||||
expiresAt: Time!
|
expiresAt: Time!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserAccount {
|
type UserAccount {
|
||||||
userID: ID!
|
id: ID!
|
||||||
email: String!
|
email: String!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
firstName: String!
|
firstName: String!
|
||||||
@ -47,13 +47,13 @@ type UserAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Team {
|
type Team {
|
||||||
teamID: ID!
|
id: ID!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
name: String!
|
name: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Project {
|
type Project {
|
||||||
projectID: ID!
|
id: ID!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
name: String!
|
name: String!
|
||||||
team: Team!
|
team: Team!
|
||||||
@ -64,7 +64,7 @@ type Project {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TaskGroup {
|
type TaskGroup {
|
||||||
taskGroupID: ID!
|
id: ID!
|
||||||
projectID: String!
|
projectID: String!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
name: String!
|
name: String!
|
||||||
@ -73,7 +73,7 @@ type TaskGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Task {
|
type Task {
|
||||||
taskID: ID!
|
id: ID!
|
||||||
taskGroup: TaskGroup!
|
taskGroup: TaskGroup!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
name: String!
|
name: String!
|
||||||
|
@ -190,6 +190,10 @@ func (r *mutationResolver) LogoutUser(ctx context.Context, input LogoutUser) (bo
|
|||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *projectResolver) ID(ctx context.Context, obj *pg.Project) (uuid.UUID, error) {
|
||||||
|
return obj.ProjectID, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *projectResolver) Team(ctx context.Context, obj *pg.Project) (*pg.Team, error) {
|
func (r *projectResolver) Team(ctx context.Context, obj *pg.Project) (*pg.Team, error) {
|
||||||
team, err := r.Repository.GetTeamByID(ctx, obj.TeamID)
|
team, err := r.Repository.GetTeamByID(ctx, obj.TeamID)
|
||||||
return &team, err
|
return &team, err
|
||||||
@ -226,6 +230,10 @@ func (r *projectResolver) Labels(ctx context.Context, obj *pg.Project) ([]pg.Pro
|
|||||||
return labels, err
|
return labels, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *projectLabelResolver) ID(ctx context.Context, obj *pg.ProjectLabel) (uuid.UUID, error) {
|
||||||
|
return obj.ProjectLabelID, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *projectLabelResolver) ColorHex(ctx context.Context, obj *pg.ProjectLabel) (string, error) {
|
func (r *projectLabelResolver) ColorHex(ctx context.Context, obj *pg.ProjectLabel) (string, error) {
|
||||||
labelColor, err := r.Repository.GetLabelColorByID(ctx, obj.LabelColorID)
|
labelColor, err := r.Repository.GetLabelColorByID(ctx, obj.LabelColorID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -235,7 +243,11 @@ func (r *projectLabelResolver) ColorHex(ctx context.Context, obj *pg.ProjectLabe
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *projectLabelResolver) Name(ctx context.Context, obj *pg.ProjectLabel) (*string, error) {
|
func (r *projectLabelResolver) Name(ctx context.Context, obj *pg.ProjectLabel) (*string, error) {
|
||||||
panic(fmt.Errorf("not implemented"))
|
var name *string
|
||||||
|
if obj.Name.Valid {
|
||||||
|
name = &obj.Name.String
|
||||||
|
}
|
||||||
|
return name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) Users(ctx context.Context) ([]pg.UserAccount, error) {
|
func (r *queryResolver) Users(ctx context.Context) ([]pg.UserAccount, error) {
|
||||||
@ -311,6 +323,14 @@ func (r *queryResolver) Me(ctx context.Context) (*pg.UserAccount, error) {
|
|||||||
return &user, err
|
return &user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *refreshTokenResolver) ID(ctx context.Context, obj *pg.RefreshToken) (uuid.UUID, error) {
|
||||||
|
return obj.TokenID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *taskResolver) ID(ctx context.Context, obj *pg.Task) (uuid.UUID, error) {
|
||||||
|
return obj.TaskID, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *taskResolver) TaskGroup(ctx context.Context, obj *pg.Task) (*pg.TaskGroup, error) {
|
func (r *taskResolver) TaskGroup(ctx context.Context, obj *pg.Task) (*pg.TaskGroup, error) {
|
||||||
taskGroup, err := r.Repository.GetTaskGroupByID(ctx, obj.TaskGroupID)
|
taskGroup, err := r.Repository.GetTaskGroupByID(ctx, obj.TaskGroupID)
|
||||||
return &taskGroup, err
|
return &taskGroup, err
|
||||||
@ -349,6 +369,10 @@ func (r *taskResolver) Labels(ctx context.Context, obj *pg.Task) ([]pg.TaskLabel
|
|||||||
return r.Repository.GetTaskLabelsForTaskID(ctx, obj.TaskID)
|
return r.Repository.GetTaskLabelsForTaskID(ctx, obj.TaskID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *taskGroupResolver) ID(ctx context.Context, obj *pg.TaskGroup) (uuid.UUID, error) {
|
||||||
|
return obj.TaskGroupID, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *taskGroupResolver) ProjectID(ctx context.Context, obj *pg.TaskGroup) (string, error) {
|
func (r *taskGroupResolver) ProjectID(ctx context.Context, obj *pg.TaskGroup) (string, error) {
|
||||||
return obj.ProjectID.String(), nil
|
return obj.ProjectID.String(), nil
|
||||||
}
|
}
|
||||||
@ -358,6 +382,10 @@ func (r *taskGroupResolver) Tasks(ctx context.Context, obj *pg.TaskGroup) ([]pg.
|
|||||||
return tasks, err
|
return tasks, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *taskLabelResolver) ID(ctx context.Context, obj *pg.TaskLabel) (uuid.UUID, error) {
|
||||||
|
return obj.TaskLabelID, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *taskLabelResolver) ColorHex(ctx context.Context, obj *pg.TaskLabel) (string, error) {
|
func (r *taskLabelResolver) ColorHex(ctx context.Context, obj *pg.TaskLabel) (string, error) {
|
||||||
projectLabel, err := r.Repository.GetProjectLabelByID(ctx, obj.ProjectLabelID)
|
projectLabel, err := r.Repository.GetProjectLabelByID(ctx, obj.ProjectLabelID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -382,6 +410,14 @@ func (r *taskLabelResolver) Name(ctx context.Context, obj *pg.TaskLabel) (*strin
|
|||||||
return &name.String, err
|
return &name.String, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *teamResolver) ID(ctx context.Context, obj *pg.Team) (uuid.UUID, error) {
|
||||||
|
return obj.TeamID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *userAccountResolver) ID(ctx context.Context, obj *pg.UserAccount) (uuid.UUID, error) {
|
||||||
|
return obj.UserID, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *userAccountResolver) ProfileIcon(ctx context.Context, obj *pg.UserAccount) (*ProfileIcon, error) {
|
func (r *userAccountResolver) ProfileIcon(ctx context.Context, obj *pg.UserAccount) (*ProfileIcon, error) {
|
||||||
initials := string([]rune(obj.FirstName)[0]) + string([]rune(obj.LastName)[0])
|
initials := string([]rune(obj.FirstName)[0]) + string([]rune(obj.LastName)[0])
|
||||||
profileIcon := &ProfileIcon{nil, &initials, &obj.ProfileBgColor}
|
profileIcon := &ProfileIcon{nil, &initials, &obj.ProfileBgColor}
|
||||||
@ -400,6 +436,9 @@ func (r *Resolver) ProjectLabel() ProjectLabelResolver { return &projectLabelRes
|
|||||||
// Query returns QueryResolver implementation.
|
// Query returns QueryResolver implementation.
|
||||||
func (r *Resolver) Query() QueryResolver { return &queryResolver{r} }
|
func (r *Resolver) Query() QueryResolver { return &queryResolver{r} }
|
||||||
|
|
||||||
|
// RefreshToken returns RefreshTokenResolver implementation.
|
||||||
|
func (r *Resolver) RefreshToken() RefreshTokenResolver { return &refreshTokenResolver{r} }
|
||||||
|
|
||||||
// Task returns TaskResolver implementation.
|
// Task returns TaskResolver implementation.
|
||||||
func (r *Resolver) Task() TaskResolver { return &taskResolver{r} }
|
func (r *Resolver) Task() TaskResolver { return &taskResolver{r} }
|
||||||
|
|
||||||
@ -409,6 +448,9 @@ func (r *Resolver) TaskGroup() TaskGroupResolver { return &taskGroupResolver{r}
|
|||||||
// TaskLabel returns TaskLabelResolver implementation.
|
// TaskLabel returns TaskLabelResolver implementation.
|
||||||
func (r *Resolver) TaskLabel() TaskLabelResolver { return &taskLabelResolver{r} }
|
func (r *Resolver) TaskLabel() TaskLabelResolver { return &taskLabelResolver{r} }
|
||||||
|
|
||||||
|
// Team returns TeamResolver implementation.
|
||||||
|
func (r *Resolver) Team() TeamResolver { return &teamResolver{r} }
|
||||||
|
|
||||||
// UserAccount returns UserAccountResolver implementation.
|
// UserAccount returns UserAccountResolver implementation.
|
||||||
func (r *Resolver) UserAccount() UserAccountResolver { return &userAccountResolver{r} }
|
func (r *Resolver) UserAccount() UserAccountResolver { return &userAccountResolver{r} }
|
||||||
|
|
||||||
@ -416,20 +458,9 @@ type mutationResolver struct{ *Resolver }
|
|||||||
type projectResolver struct{ *Resolver }
|
type projectResolver struct{ *Resolver }
|
||||||
type projectLabelResolver struct{ *Resolver }
|
type projectLabelResolver struct{ *Resolver }
|
||||||
type queryResolver struct{ *Resolver }
|
type queryResolver struct{ *Resolver }
|
||||||
|
type refreshTokenResolver struct{ *Resolver }
|
||||||
type taskResolver struct{ *Resolver }
|
type taskResolver struct{ *Resolver }
|
||||||
type taskGroupResolver struct{ *Resolver }
|
type taskGroupResolver struct{ *Resolver }
|
||||||
type taskLabelResolver struct{ *Resolver }
|
type taskLabelResolver struct{ *Resolver }
|
||||||
|
type teamResolver struct{ *Resolver }
|
||||||
type userAccountResolver struct{ *Resolver }
|
type userAccountResolver struct{ *Resolver }
|
||||||
|
|
||||||
// !!! WARNING !!!
|
|
||||||
// The code below was going to be deleted when updating resolvers. It has been copied here so you have
|
|
||||||
// one last chance to move it out of harms way if you want. There are two reasons this happens:
|
|
||||||
// - When renaming or deleting a resolver the old code will be put in here. You can safely delete
|
|
||||||
// it when you're done.
|
|
||||||
// - You have helper methods in this file. Move them out to keep these resolver files clean.
|
|
||||||
func (r *taskLabelResolver) ProjectLabelID(ctx context.Context, obj *pg.TaskLabel) (uuid.UUID, error) {
|
|
||||||
panic(fmt.Errorf("not implemented"))
|
|
||||||
}
|
|
||||||
func (r *userAccountResolver) DisplayName(ctx context.Context, obj *pg.UserAccount) (string, error) {
|
|
||||||
return obj.FirstName + " " + obj.LastName, nil
|
|
||||||
}
|
|
||||||
|
7
api/migrations/0017_add-profile-bg-delete-cascade.up.sql
Normal file
7
api/migrations/0017_add-profile-bg-delete-cascade.up.sql
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
ALTER TABLE task_assigned
|
||||||
|
DROP CONSTRAINT task_assigned_task_id_fkey,
|
||||||
|
ADD CONSTRAINT task_assigned_task_id_fkey
|
||||||
|
FOREIGN KEY (task_id)
|
||||||
|
REFERENCES task(task_id)
|
||||||
|
ON DELETE CASCADE;
|
||||||
|
|
69
assets/favicon.svg
Normal file
69
assets/favicon.svg
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="64"
|
||||||
|
height="64"
|
||||||
|
viewBox="0 0 12.7 12.7"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
sodipodi:docname="favicon.svg"
|
||||||
|
inkscape:version="0.92.4 5da689c313, 2019-01-14">
|
||||||
|
<metadata
|
||||||
|
id="metadata14">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs12" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1908"
|
||||||
|
inkscape:window-height="983"
|
||||||
|
id="namedview10"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="7.375"
|
||||||
|
inkscape:cx="5.2026609"
|
||||||
|
inkscape:cy="37.687216"
|
||||||
|
inkscape:window-x="6"
|
||||||
|
inkscape:window-y="6"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="g6" />
|
||||||
|
<g
|
||||||
|
transform="translate(-.26 -24.137) scale(.1249)"
|
||||||
|
id="g6"
|
||||||
|
style="stroke-width:17.47648118;stroke-miterlimit:4;stroke-dasharray:none">
|
||||||
|
<path
|
||||||
|
d="M50.886 286.515l-40.4-44.46 44.459-40.401 40.401 44.46z"
|
||||||
|
fill="none"
|
||||||
|
stroke="#000"
|
||||||
|
strokeWidth="11.90597031"
|
||||||
|
id="path2"
|
||||||
|
style="stroke-width:7.94385508;stroke-miterlimit:4;stroke-dasharray:none;stroke:#7367f0;stroke-opacity:1" />
|
||||||
|
<circle
|
||||||
|
cx="52.917"
|
||||||
|
cy="244.083"
|
||||||
|
r="11.025"
|
||||||
|
fill="#000"
|
||||||
|
id="circle4"
|
||||||
|
style="stroke-width:17.47648118;stroke-miterlimit:4;stroke-dasharray:none;fill:#7367f0;fill-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 295 KiB |
@ -24,7 +24,7 @@
|
|||||||
work correctly both with client-side routing and a non-root public URL.
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>React App</title>
|
<title>Citadel</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
@ -5,7 +5,10 @@ import { useHistory } from 'react-router';
|
|||||||
import UserIDContext from 'App/context';
|
import UserIDContext from 'App/context';
|
||||||
import { useMeQuery } from 'shared/generated/graphql';
|
import { useMeQuery } from 'shared/generated/graphql';
|
||||||
|
|
||||||
const GlobalTopNavbar: React.FC = () => {
|
type GlobalTopNavbarProps = {
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
const GlobalTopNavbar: React.FC<GlobalTopNavbarProps> = ({ name }) => {
|
||||||
const { loading, data } = useMeQuery();
|
const { loading, data } = useMeQuery();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { userID, setUserID } = useContext(UserIDContext);
|
const { userID, setUserID } = useContext(UserIDContext);
|
||||||
@ -41,6 +44,7 @@ const GlobalTopNavbar: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopNavbar
|
<TopNavbar
|
||||||
|
projectName={name}
|
||||||
bgColor={data ? data.me.profileIcon.bgColor ?? '#7367F0' : '#7367F0'}
|
bgColor={data ? data.me.profileIcon.bgColor ?? '#7367F0' : '#7367F0'}
|
||||||
firstName={data ? data.me.firstName : ''}
|
firstName={data ? data.me.firstName : ''}
|
||||||
lastName={data ? data.me.lastName : ''}
|
lastName={data ? data.me.lastName : ''}
|
||||||
|
@ -2,7 +2,6 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import jwtDecode from 'jwt-decode';
|
import jwtDecode from 'jwt-decode';
|
||||||
import { createBrowserHistory } from 'history';
|
import { createBrowserHistory } from 'history';
|
||||||
import { setAccessToken } from 'shared/utils/accessToken';
|
import { setAccessToken } from 'shared/utils/accessToken';
|
||||||
import GlobalTopNavbar from 'App/TopNavbar';
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import NormalizeStyles from './NormalizeStyles';
|
import NormalizeStyles from './NormalizeStyles';
|
||||||
import BaseStyles from './BaseStyles';
|
import BaseStyles from './BaseStyles';
|
||||||
@ -10,6 +9,7 @@ import Routes from './Routes';
|
|||||||
import { UserIDContext } from './context';
|
import { UserIDContext } from './context';
|
||||||
import Navbar from './Navbar';
|
import Navbar from './Navbar';
|
||||||
import { Router } from 'react-router';
|
import { Router } from 'react-router';
|
||||||
|
import { PopupProvider } from 'shared/components/PopupMenu';
|
||||||
|
|
||||||
const history = createBrowserHistory();
|
const history = createBrowserHistory();
|
||||||
|
|
||||||
@ -45,21 +45,22 @@ const App = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<UserIDContext.Provider value={{ userID, setUserID }}>
|
<UserIDContext.Provider value={{ userID, setUserID }}>
|
||||||
<NormalizeStyles />
|
<PopupProvider>
|
||||||
<BaseStyles />
|
<NormalizeStyles />
|
||||||
<Router history={history}>
|
<BaseStyles />
|
||||||
{loading ? (
|
<Router history={history}>
|
||||||
<div>loading</div>
|
{loading ? (
|
||||||
) : (
|
<div>loading</div>
|
||||||
<>
|
) : (
|
||||||
<Navbar />
|
<>
|
||||||
<MainContent>
|
<Navbar />
|
||||||
<GlobalTopNavbar />
|
<MainContent>
|
||||||
<Routes history={history} />
|
<Routes history={history} />
|
||||||
</MainContent>
|
</MainContent>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Router>
|
</Router>
|
||||||
|
</PopupProvider>
|
||||||
</UserIDContext.Provider>
|
</UserIDContext.Provider>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import React, { useState, useContext } from 'react';
|
import React, { useState, useContext } from 'react';
|
||||||
import Modal from 'shared/components/Modal';
|
import Modal from 'shared/components/Modal';
|
||||||
import TaskDetails from 'shared/components/TaskDetails';
|
import TaskDetails from 'shared/components/TaskDetails';
|
||||||
import PopupMenu from 'shared/components/PopupMenu';
|
import PopupMenu, { Popup, usePopup } from 'shared/components/PopupMenu';
|
||||||
import MemberManager from 'shared/components/MemberManager';
|
import MemberManager from 'shared/components/MemberManager';
|
||||||
import { useRouteMatch, useHistory } from 'react-router';
|
import { useRouteMatch, useHistory } from 'react-router';
|
||||||
import { useFindTaskQuery, useAssignTaskMutation, useUnassignTaskMutation } from 'shared/generated/graphql';
|
import { useFindTaskQuery, useAssignTaskMutation, useUnassignTaskMutation } from 'shared/generated/graphql';
|
||||||
import UserIDContext from 'App/context';
|
import UserIDContext from 'App/context';
|
||||||
|
import MiniProfile from 'shared/components/MiniProfile';
|
||||||
|
|
||||||
type DetailsProps = {
|
type DetailsProps = {
|
||||||
taskID: string;
|
taskID: string;
|
||||||
@ -13,7 +14,7 @@ type DetailsProps = {
|
|||||||
onTaskNameChange: (task: Task, newName: string) => void;
|
onTaskNameChange: (task: Task, newName: string) => void;
|
||||||
onTaskDescriptionChange: (task: Task, newDescription: string) => void;
|
onTaskDescriptionChange: (task: Task, newDescription: string) => void;
|
||||||
onDeleteTask: (task: Task) => void;
|
onDeleteTask: (task: Task) => void;
|
||||||
onOpenAddLabelPopup: (task: Task, bounds: ElementBounds) => void;
|
onOpenAddLabelPopup: (task: Task, $targetRef: React.RefObject<HTMLElement>) => void;
|
||||||
availableMembers: Array<TaskUser>;
|
availableMembers: Array<TaskUser>;
|
||||||
refreshCache: () => void;
|
refreshCache: () => void;
|
||||||
};
|
};
|
||||||
@ -31,8 +32,10 @@ const Details: React.FC<DetailsProps> = ({
|
|||||||
refreshCache,
|
refreshCache,
|
||||||
}) => {
|
}) => {
|
||||||
const { userID } = useContext(UserIDContext);
|
const { userID } = useContext(UserIDContext);
|
||||||
|
const { showPopup } = usePopup();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const match = useRouteMatch();
|
const match = useRouteMatch();
|
||||||
|
const [currentMemberTask, setCurrentMemberTask] = useState('');
|
||||||
const [memberPopupData, setMemberPopupData] = useState(initialMemberPopupState);
|
const [memberPopupData, setMemberPopupData] = useState(initialMemberPopupState);
|
||||||
const { loading, data, refetch } = useFindTaskQuery({ variables: { taskID } });
|
const { loading, data, refetch } = useFindTaskQuery({ variables: { taskID } });
|
||||||
const [assignTask] = useAssignTaskMutation({
|
const [assignTask] = useAssignTaskMutation({
|
||||||
@ -55,7 +58,7 @@ const Details: React.FC<DetailsProps> = ({
|
|||||||
}
|
}
|
||||||
const taskMembers = data.findTask.assigned.map(assigned => {
|
const taskMembers = data.findTask.assigned.map(assigned => {
|
||||||
return {
|
return {
|
||||||
userID: assigned.userID,
|
userID: assigned.id,
|
||||||
displayName: `${assigned.firstName} ${assigned.lastName}`,
|
displayName: `${assigned.firstName} ${assigned.lastName}`,
|
||||||
profileIcon: {
|
profileIcon: {
|
||||||
url: null,
|
url: null,
|
||||||
@ -76,6 +79,8 @@ const Details: React.FC<DetailsProps> = ({
|
|||||||
<TaskDetails
|
<TaskDetails
|
||||||
task={{
|
task={{
|
||||||
...data.findTask,
|
...data.findTask,
|
||||||
|
taskID: data.findTask.id,
|
||||||
|
taskGroup: { taskGroupID: data.findTask.taskGroup.id },
|
||||||
members: taskMembers,
|
members: taskMembers,
|
||||||
description: data.findTask.description ?? '',
|
description: data.findTask.description ?? '',
|
||||||
labels: [],
|
labels: [],
|
||||||
@ -84,42 +89,48 @@ const Details: React.FC<DetailsProps> = ({
|
|||||||
onTaskDescriptionChange={onTaskDescriptionChange}
|
onTaskDescriptionChange={onTaskDescriptionChange}
|
||||||
onDeleteTask={onDeleteTask}
|
onDeleteTask={onDeleteTask}
|
||||||
onCloseModal={() => history.push(projectURL)}
|
onCloseModal={() => history.push(projectURL)}
|
||||||
onOpenAddMemberPopup={(task, bounds) => {
|
onMemberProfile={($targetRef, memberID) => {
|
||||||
console.log(task, bounds);
|
showPopup(
|
||||||
setMemberPopupData({
|
$targetRef,
|
||||||
isOpen: true,
|
<Popup title={null} onClose={() => {}} tab={0}>
|
||||||
taskID: task.taskID,
|
<MiniProfile
|
||||||
top: bounds.position.top + bounds.size.height + 10,
|
profileIcon={taskMembers[0].profileIcon}
|
||||||
left: bounds.position.left,
|
displayName="Jordan Knott"
|
||||||
});
|
username="@jordanthedev"
|
||||||
|
bio="None"
|
||||||
|
onRemoveFromTask={() => {
|
||||||
|
unassignTask({ variables: { taskID: data.findTask.id, userID: userID ?? '' } });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popup>,
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
onOpenAddMemberPopup={(task, $targetRef) => {
|
||||||
|
console.log(`task: ${task.taskID}`);
|
||||||
|
showPopup(
|
||||||
|
$targetRef,
|
||||||
|
<Popup title="Members" tab={0} onClose={() => {}}>
|
||||||
|
<MemberManager
|
||||||
|
availableMembers={availableMembers}
|
||||||
|
activeMembers={taskMembers}
|
||||||
|
onMemberChange={(member, isActive) => {
|
||||||
|
console.log(`is active ${member.userID} - ${isActive}`);
|
||||||
|
if (isActive) {
|
||||||
|
assignTask({ variables: { taskID: data.findTask.id, userID: userID ?? '' } });
|
||||||
|
} else {
|
||||||
|
unassignTask({ variables: { taskID: data.findTask.id, userID: userID ?? '' } });
|
||||||
|
}
|
||||||
|
console.log(member, isActive);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popup>,
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
onOpenAddLabelPopup={onOpenAddLabelPopup}
|
onOpenAddLabelPopup={onOpenAddLabelPopup}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{memberPopupData.isOpen && (
|
|
||||||
<PopupMenu
|
|
||||||
title="Members"
|
|
||||||
top={memberPopupData.top}
|
|
||||||
onClose={() => setMemberPopupData(initialMemberPopupState)}
|
|
||||||
left={memberPopupData.left}
|
|
||||||
>
|
|
||||||
<MemberManager
|
|
||||||
availableMembers={availableMembers}
|
|
||||||
activeMembers={taskMembers}
|
|
||||||
onMemberChange={(member, isActive) => {
|
|
||||||
console.log(`is active ${member.userID} - ${isActive}`);
|
|
||||||
if (isActive) {
|
|
||||||
assignTask({ variables: { taskID: data.findTask.taskID, userID: userID ?? '' } });
|
|
||||||
} else {
|
|
||||||
unassignTask({ variables: { taskID: data.findTask.taskID, userID: userID ?? '' } });
|
|
||||||
}
|
|
||||||
console.log(member, isActive);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</PopupMenu>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,7 @@ import { Board } from './Styles';
|
|||||||
|
|
||||||
type KanbanBoardProps = {
|
type KanbanBoardProps = {
|
||||||
listsData: BoardState;
|
listsData: BoardState;
|
||||||
onOpenListActionsPopup: (isOpen: boolean, left: number, top: number, taskGroupID: string) => void;
|
onOpenListActionsPopup: ($targetRef: React.RefObject<HTMLElement>, taskGroupID: string) => void;
|
||||||
onCardDrop: (task: Task) => void;
|
onCardDrop: (task: Task) => void;
|
||||||
onListDrop: (taskGroup: TaskGroup) => void;
|
onListDrop: (taskGroup: TaskGroup) => void;
|
||||||
onCardCreate: (taskGroupID: string, name: string) => void;
|
onCardCreate: (taskGroupID: string, name: string) => void;
|
||||||
@ -31,8 +31,8 @@ const KanbanBoard: React.FC<KanbanBoardProps> = ({
|
|||||||
onCardClick={task => {
|
onCardClick={task => {
|
||||||
history.push(`${match.url}/c/${task.taskID}`);
|
history.push(`${match.url}/c/${task.taskID}`);
|
||||||
}}
|
}}
|
||||||
onExtraMenuOpen={(taskGroupID, pos, size) => {
|
onExtraMenuOpen={(taskGroupID, $targetRef) => {
|
||||||
onOpenListActionsPopup(true, pos.left, pos.top + size.height + 5, taskGroupID);
|
onOpenListActionsPopup($targetRef, taskGroupID);
|
||||||
}}
|
}}
|
||||||
onQuickEditorOpen={onQuickEditorOpen}
|
onQuickEditorOpen={onQuickEditorOpen}
|
||||||
onCardCreate={onCardCreate}
|
onCardCreate={onCardCreate}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useRef } from 'react';
|
||||||
import * as BoardStateUtils from 'shared/utils/boardState';
|
import * as BoardStateUtils from 'shared/utils/boardState';
|
||||||
|
import GlobalTopNavbar from 'App/TopNavbar';
|
||||||
import styled from 'styled-components/macro';
|
import styled from 'styled-components/macro';
|
||||||
|
import { Bolt, ToggleOn, Tags } from 'shared/icons';
|
||||||
|
import { usePopup, Popup } from 'shared/components/PopupMenu';
|
||||||
import { useParams, Route, useRouteMatch, useHistory, RouteComponentProps } from 'react-router-dom';
|
import { useParams, Route, useRouteMatch, useHistory, RouteComponentProps } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
useFindProjectQuery,
|
useFindProjectQuery,
|
||||||
@ -13,14 +16,19 @@ import {
|
|||||||
useDeleteTaskGroupMutation,
|
useDeleteTaskGroupMutation,
|
||||||
useUpdateTaskDescriptionMutation,
|
useUpdateTaskDescriptionMutation,
|
||||||
useAssignTaskMutation,
|
useAssignTaskMutation,
|
||||||
|
DeleteTaskDocument,
|
||||||
|
FindProjectDocument,
|
||||||
} from 'shared/generated/graphql';
|
} from 'shared/generated/graphql';
|
||||||
|
|
||||||
import QuickCardEditor from 'shared/components/QuickCardEditor';
|
import QuickCardEditor from 'shared/components/QuickCardEditor';
|
||||||
import PopupMenu from 'shared/components/PopupMenu';
|
|
||||||
import ListActions from 'shared/components/ListActions';
|
import ListActions from 'shared/components/ListActions';
|
||||||
import MemberManager from 'shared/components/MemberManager';
|
import MemberManager from 'shared/components/MemberManager';
|
||||||
import { LabelsPopup } from 'shared/components/PopupMenu/PopupMenu.stories';
|
import { LabelsPopup } from 'shared/components/PopupMenu/PopupMenu.stories';
|
||||||
import KanbanBoard from 'Projects/Project/KanbanBoard';
|
import KanbanBoard from 'Projects/Project/KanbanBoard';
|
||||||
|
import { mixin } from 'shared/utils/styles';
|
||||||
|
import LabelManager from 'shared/components/PopupMenu/LabelManager';
|
||||||
|
import LabelEditor from 'shared/components/PopupMenu/LabelEditor';
|
||||||
|
import produce from 'immer';
|
||||||
import Details from './Details';
|
import Details from './Details';
|
||||||
|
|
||||||
type TaskRouteProps = {
|
type TaskRouteProps = {
|
||||||
@ -45,6 +53,67 @@ const Title = styled.span`
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
type LabelManagerEditorProps = {
|
||||||
|
labels: Array<Label>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const LabelManagerEditor: React.FC<LabelManagerEditorProps> = ({ labels: initialLabels }) => {
|
||||||
|
const [labels, setLabels] = useState<Array<Label>>(initialLabels);
|
||||||
|
const [currentLabel, setCurrentLabel] = useState('');
|
||||||
|
const { setTab } = usePopup();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Popup title="Labels" tab={0} onClose={() => {}}>
|
||||||
|
<LabelManager
|
||||||
|
labels={labels}
|
||||||
|
onLabelCreate={() => {
|
||||||
|
setTab(2);
|
||||||
|
}}
|
||||||
|
onLabelEdit={labelId => {
|
||||||
|
setCurrentLabel(labelId);
|
||||||
|
setTab(1);
|
||||||
|
}}
|
||||||
|
onLabelToggle={labelId => {
|
||||||
|
setLabels(
|
||||||
|
produce(labels, draftState => {
|
||||||
|
const idx = labels.findIndex(label => label.labelId === labelId);
|
||||||
|
if (idx !== -1) {
|
||||||
|
draftState[idx] = { ...draftState[idx], active: !labels[idx].active };
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popup>
|
||||||
|
<Popup onClose={() => {}} title="Edit label" tab={1}>
|
||||||
|
<LabelEditor
|
||||||
|
label={labels.find(label => label.labelId === currentLabel) ?? null}
|
||||||
|
onLabelEdit={(_labelId, name, color) => {
|
||||||
|
setLabels(
|
||||||
|
produce(labels, draftState => {
|
||||||
|
const idx = labels.findIndex(label => label.labelId === currentLabel);
|
||||||
|
if (idx !== -1) {
|
||||||
|
draftState[idx] = { ...draftState[idx], name, color };
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
setTab(0);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popup>
|
||||||
|
<Popup onClose={() => {}} title="Create new label" tab={2}>
|
||||||
|
<LabelEditor
|
||||||
|
label={null}
|
||||||
|
onLabelEdit={(_labelId, name, color) => {
|
||||||
|
setLabels([...labels, { labelId: name, name, color, active: false }]);
|
||||||
|
setTab(0);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popup>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
interface ProjectParams {
|
interface ProjectParams {
|
||||||
projectId: string;
|
projectId: string;
|
||||||
}
|
}
|
||||||
@ -55,6 +124,34 @@ const initialQuickCardEditorState: QuickCardEditorState = { isOpen: false, top:
|
|||||||
const initialLabelsPopupState = { taskID: '', isOpen: false, top: 0, left: 0 };
|
const initialLabelsPopupState = { taskID: '', isOpen: false, top: 0, left: 0 };
|
||||||
const initialTaskDetailsState = { isOpen: false, taskID: '' };
|
const initialTaskDetailsState = { isOpen: false, taskID: '' };
|
||||||
|
|
||||||
|
const ProjectActions = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 12px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ProjectAction = styled.div`
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #c2c6dc;
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: ${mixin.lighten('#c2c6dc', 0.25)};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ProjectActionText = styled.span`
|
||||||
|
padding-left: 4px;
|
||||||
|
`;
|
||||||
|
|
||||||
const Project = () => {
|
const Project = () => {
|
||||||
const { projectId } = useParams<ProjectParams>();
|
const { projectId } = useParams<ProjectParams>();
|
||||||
const match = useRouteMatch();
|
const match = useRouteMatch();
|
||||||
@ -70,17 +167,16 @@ const Project = () => {
|
|||||||
|
|
||||||
const [deleteTaskGroup] = useDeleteTaskGroupMutation({
|
const [deleteTaskGroup] = useDeleteTaskGroupMutation({
|
||||||
onCompleted: deletedTaskGroupData => {
|
onCompleted: deletedTaskGroupData => {
|
||||||
setListsData(
|
setListsData(BoardStateUtils.deleteTaskGroup(listsData, deletedTaskGroupData.deleteTaskGroup.taskGroup.id));
|
||||||
BoardStateUtils.deleteTaskGroup(listsData, deletedTaskGroupData.deleteTaskGroup.taskGroup.taskGroupID),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [createTaskGroup] = useCreateTaskGroupMutation({
|
const [createTaskGroup] = useCreateTaskGroupMutation({
|
||||||
onCompleted: newTaskGroupData => {
|
onCompleted: newTaskGroupData => {
|
||||||
const newTaskGroup = {
|
const newTaskGroup = {
|
||||||
...newTaskGroupData.createTaskGroup,
|
taskGroupID: newTaskGroupData.createTaskGroup.id,
|
||||||
tasks: [],
|
tasks: [],
|
||||||
|
...newTaskGroupData.createTaskGroup,
|
||||||
};
|
};
|
||||||
setListsData(BoardStateUtils.addTaskGroup(listsData, newTaskGroup));
|
setListsData(BoardStateUtils.addTaskGroup(listsData, newTaskGroup));
|
||||||
},
|
},
|
||||||
@ -90,10 +186,43 @@ const Project = () => {
|
|||||||
onCompleted: newTaskData => {
|
onCompleted: newTaskData => {
|
||||||
const newTask = {
|
const newTask = {
|
||||||
...newTaskData.createTask,
|
...newTaskData.createTask,
|
||||||
|
taskID: newTaskData.createTask.id,
|
||||||
|
taskGroup: { taskGroupID: newTaskData.createTask.taskGroup.id },
|
||||||
labels: [],
|
labels: [],
|
||||||
};
|
};
|
||||||
setListsData(BoardStateUtils.addTask(listsData, newTask));
|
setListsData(BoardStateUtils.addTask(listsData, newTask));
|
||||||
},
|
},
|
||||||
|
update: (client, newTaskData) => {
|
||||||
|
const cacheData: any = client.readQuery({
|
||||||
|
query: FindProjectDocument,
|
||||||
|
variables: {
|
||||||
|
projectId: projectId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log(cacheData);
|
||||||
|
console.log(newTaskData);
|
||||||
|
const newTaskGroups = produce(cacheData.findProject.taskGroups, (draftState: any) => {
|
||||||
|
const targetIndex = draftState.findIndex(
|
||||||
|
(taskGroup: any) => taskGroup.id === newTaskData.data.createTask.taskGroup.id,
|
||||||
|
);
|
||||||
|
draftState[targetIndex] = {
|
||||||
|
...draftState[targetIndex],
|
||||||
|
tasks: [...draftState[targetIndex].tasks, { ...newTaskData.data.createTask }],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
console.log(newTaskGroups);
|
||||||
|
const newData = {
|
||||||
|
...cacheData.findProject,
|
||||||
|
taskGroups: newTaskGroups,
|
||||||
|
};
|
||||||
|
client.writeQuery({
|
||||||
|
query: FindProjectDocument,
|
||||||
|
variables: {
|
||||||
|
projectId: projectId,
|
||||||
|
},
|
||||||
|
data: { findProject: newData },
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [deleteTask] = useDeleteTaskMutation({
|
const [deleteTask] = useDeleteTaskMutation({
|
||||||
@ -105,50 +234,14 @@ const Project = () => {
|
|||||||
const [updateTaskName] = useUpdateTaskNameMutation({
|
const [updateTaskName] = useUpdateTaskNameMutation({
|
||||||
onCompleted: newTaskData => {
|
onCompleted: newTaskData => {
|
||||||
setListsData(
|
setListsData(
|
||||||
BoardStateUtils.updateTaskName(listsData, newTaskData.updateTaskName.taskID, newTaskData.updateTaskName.name),
|
BoardStateUtils.updateTaskName(listsData, newTaskData.updateTaskName.id, newTaskData.updateTaskName.name),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { loading, data, refetch } = useFindProjectQuery({
|
const { loading, data, refetch } = useFindProjectQuery({
|
||||||
variables: { projectId },
|
variables: { projectId },
|
||||||
onCompleted: newData => {
|
|
||||||
console.log('beep!');
|
|
||||||
const newListsData: BoardState = { tasks: {}, columns: {} };
|
|
||||||
newData.findProject.taskGroups.forEach(taskGroup => {
|
|
||||||
newListsData.columns[taskGroup.taskGroupID] = {
|
|
||||||
taskGroupID: taskGroup.taskGroupID,
|
|
||||||
name: taskGroup.name,
|
|
||||||
position: taskGroup.position,
|
|
||||||
tasks: [],
|
|
||||||
};
|
|
||||||
taskGroup.tasks.forEach(task => {
|
|
||||||
const taskMembers = task.assigned.map(assigned => {
|
|
||||||
return {
|
|
||||||
userID: assigned.userID,
|
|
||||||
displayName: `${assigned.firstName} ${assigned.lastName}`,
|
|
||||||
profileIcon: {
|
|
||||||
url: null,
|
|
||||||
initials: assigned.profileIcon.initials ?? '',
|
|
||||||
bgColor: assigned.profileIcon.bgColor ?? '#7367F0',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
newListsData.tasks[task.taskID] = {
|
|
||||||
taskID: task.taskID,
|
|
||||||
taskGroup: {
|
|
||||||
taskGroupID: taskGroup.taskGroupID,
|
|
||||||
},
|
|
||||||
name: task.name,
|
|
||||||
labels: [],
|
|
||||||
position: task.position,
|
|
||||||
description: task.description ?? undefined,
|
|
||||||
members: taskMembers,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
setListsData(newListsData);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
console.log(`loading ${loading} - ${data}`);
|
||||||
|
|
||||||
const onCardCreate = (taskGroupID: string, name: string) => {
|
const onCardCreate = (taskGroupID: string, name: string) => {
|
||||||
const taskGroupTasks = Object.values(listsData.tasks).filter(
|
const taskGroupTasks = Object.values(listsData.tasks).filter(
|
||||||
@ -163,15 +256,6 @@ const Project = () => {
|
|||||||
createTask({ variables: { taskGroupID, name, position } });
|
createTask({ variables: { taskGroupID, name, position } });
|
||||||
};
|
};
|
||||||
|
|
||||||
const onQuickEditorOpen = (e: ContextMenuEvent) => {
|
|
||||||
const currentTask = Object.values(listsData.tasks).find(task => task.taskID === e.taskID);
|
|
||||||
setQuickCardEditor({
|
|
||||||
top: e.top,
|
|
||||||
left: e.left,
|
|
||||||
isOpen: true,
|
|
||||||
task: currentTask,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const onCardDrop = (droppedTask: Task) => {
|
const onCardDrop = (droppedTask: Task) => {
|
||||||
updateTaskLocation({
|
updateTaskLocation({
|
||||||
variables: {
|
variables: {
|
||||||
@ -202,10 +286,50 @@ const Project = () => {
|
|||||||
|
|
||||||
const [assignTask] = useAssignTaskMutation();
|
const [assignTask] = useAssignTaskMutation();
|
||||||
|
|
||||||
|
const { showPopup } = usePopup();
|
||||||
|
const $labelsRef = useRef<HTMLDivElement>(null);
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <Title>Error Loading</Title>;
|
return (
|
||||||
|
<>
|
||||||
|
<GlobalTopNavbar name="Project" />
|
||||||
|
<Title>Error Loading</Title>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (data) {
|
if (data) {
|
||||||
|
const currentListsData: BoardState = { tasks: {}, columns: {} };
|
||||||
|
data.findProject.taskGroups.forEach(taskGroup => {
|
||||||
|
currentListsData.columns[taskGroup.id] = {
|
||||||
|
taskGroupID: taskGroup.id,
|
||||||
|
name: taskGroup.name,
|
||||||
|
position: taskGroup.position,
|
||||||
|
tasks: [],
|
||||||
|
};
|
||||||
|
taskGroup.tasks.forEach(task => {
|
||||||
|
const taskMembers = task.assigned.map(assigned => {
|
||||||
|
return {
|
||||||
|
userID: assigned.id,
|
||||||
|
displayName: `${assigned.firstName} ${assigned.lastName}`,
|
||||||
|
profileIcon: {
|
||||||
|
url: null,
|
||||||
|
initials: assigned.profileIcon.initials ?? '',
|
||||||
|
bgColor: assigned.profileIcon.bgColor ?? '#7367F0',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
currentListsData.tasks[task.id] = {
|
||||||
|
taskID: task.id,
|
||||||
|
taskGroup: {
|
||||||
|
taskGroupID: taskGroup.id,
|
||||||
|
},
|
||||||
|
name: task.name,
|
||||||
|
labels: [],
|
||||||
|
position: task.position,
|
||||||
|
description: task.description ?? undefined,
|
||||||
|
members: taskMembers,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
const availableMembers = data.findProject.members.map(member => {
|
const availableMembers = data.findProject.members.map(member => {
|
||||||
return {
|
return {
|
||||||
displayName: `${member.firstName} ${member.lastName}`,
|
displayName: `${member.firstName} ${member.lastName}`,
|
||||||
@ -214,38 +338,75 @@ const Project = () => {
|
|||||||
initials: member.profileIcon.initials ?? null,
|
initials: member.profileIcon.initials ?? null,
|
||||||
bgColor: member.profileIcon.bgColor ?? null,
|
bgColor: member.profileIcon.bgColor ?? null,
|
||||||
},
|
},
|
||||||
userID: member.userID,
|
userID: member.id,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
const onQuickEditorOpen = (e: ContextMenuEvent) => {
|
||||||
|
const currentTask = Object.values(currentListsData.tasks).find(task => task.taskID === e.taskID);
|
||||||
|
console.log(`currentTask: ${currentTask?.taskID}`);
|
||||||
|
setQuickCardEditor({
|
||||||
|
top: e.top,
|
||||||
|
left: e.left,
|
||||||
|
isOpen: true,
|
||||||
|
task: currentTask,
|
||||||
|
});
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<GlobalTopNavbar name={data.findProject.name} />
|
||||||
|
<ProjectActions>
|
||||||
|
<ProjectAction
|
||||||
|
ref={$labelsRef}
|
||||||
|
onClick={() => {
|
||||||
|
showPopup(
|
||||||
|
$labelsRef,
|
||||||
|
<LabelManagerEditor
|
||||||
|
labels={data.findProject.labels.map(label => {
|
||||||
|
return {
|
||||||
|
labelId: label.id,
|
||||||
|
name: label.name ?? '',
|
||||||
|
color: label.colorHex,
|
||||||
|
active: false,
|
||||||
|
};
|
||||||
|
})}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tags size={13} color="#c2c6dc" />
|
||||||
|
<ProjectActionText>Labels</ProjectActionText>
|
||||||
|
</ProjectAction>
|
||||||
|
<ProjectAction>
|
||||||
|
<ToggleOn size={13} color="#c2c6dc" />
|
||||||
|
<ProjectActionText>Fields</ProjectActionText>
|
||||||
|
</ProjectAction>
|
||||||
|
<ProjectAction>
|
||||||
|
<Bolt size={13} color="#c2c6dc" />
|
||||||
|
<ProjectActionText>Rules</ProjectActionText>
|
||||||
|
</ProjectAction>
|
||||||
|
</ProjectActions>
|
||||||
<KanbanBoard
|
<KanbanBoard
|
||||||
listsData={listsData}
|
listsData={currentListsData}
|
||||||
onCardDrop={onCardDrop}
|
onCardDrop={onCardDrop}
|
||||||
onListDrop={onListDrop}
|
onListDrop={onListDrop}
|
||||||
onCardCreate={onCardCreate}
|
onCardCreate={onCardCreate}
|
||||||
onCreateList={onCreateList}
|
onCreateList={onCreateList}
|
||||||
onQuickEditorOpen={onQuickEditorOpen}
|
onQuickEditorOpen={onQuickEditorOpen}
|
||||||
onOpenListActionsPopup={(isOpen, left, top, taskGroupID) => {
|
onOpenListActionsPopup={($targetRef, taskGroupID) => {
|
||||||
setPopupData({ isOpen, top, left, taskGroupID });
|
showPopup(
|
||||||
|
$targetRef,
|
||||||
|
<Popup title="List actions" tab={0} onClose={() => {}}>
|
||||||
|
<ListActions
|
||||||
|
taskGroupID={taskGroupID}
|
||||||
|
onArchiveTaskGroup={tgID => {
|
||||||
|
deleteTaskGroup({ variables: { taskGroupID: tgID } });
|
||||||
|
setPopupData(initialPopupState);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popup>,
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{popupData.isOpen && (
|
|
||||||
<PopupMenu
|
|
||||||
title="List Actions"
|
|
||||||
top={popupData.top}
|
|
||||||
onClose={() => setPopupData(initialPopupState)}
|
|
||||||
left={popupData.left}
|
|
||||||
>
|
|
||||||
<ListActions
|
|
||||||
taskGroupID={popupData.taskGroupID}
|
|
||||||
onArchiveTaskGroup={taskGroupID => {
|
|
||||||
deleteTaskGroup({ variables: { taskGroupID } });
|
|
||||||
setPopupData(initialPopupState);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</PopupMenu>
|
|
||||||
)}
|
|
||||||
{quickCardEditor.isOpen && (
|
{quickCardEditor.isOpen && (
|
||||||
<QuickCardEditor
|
<QuickCardEditor
|
||||||
isOpen
|
isOpen
|
||||||
@ -257,7 +418,35 @@ const Project = () => {
|
|||||||
updateTaskName({ variables: { taskID: cardId, name: cardName } });
|
updateTaskName({ variables: { taskID: cardId, name: cardName } });
|
||||||
}}
|
}}
|
||||||
onOpenPopup={() => console.log()}
|
onOpenPopup={() => console.log()}
|
||||||
onArchiveCard={(_listId: string, cardId: string) => deleteTask({ variables: { taskID: cardId } })}
|
onArchiveCard={(_listId: string, cardId: string) =>
|
||||||
|
deleteTask({
|
||||||
|
variables: { taskID: cardId },
|
||||||
|
update: client => {
|
||||||
|
const cacheData: any = client.readQuery({
|
||||||
|
query: FindProjectDocument,
|
||||||
|
variables: {
|
||||||
|
projectId: projectId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const newData = {
|
||||||
|
...cacheData.findProject,
|
||||||
|
taskGroups: cacheData.findProject.taskGroups.map((taskGroup: any) => {
|
||||||
|
return {
|
||||||
|
...taskGroup,
|
||||||
|
tasks: taskGroup.tasks.filter((t: any) => t.id !== cardId),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
client.writeQuery({
|
||||||
|
query: FindProjectDocument,
|
||||||
|
variables: {
|
||||||
|
projectId: projectId,
|
||||||
|
},
|
||||||
|
data: { findProject: newData },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
labels={[]}
|
labels={[]}
|
||||||
top={quickCardEditor.top}
|
top={quickCardEditor.top}
|
||||||
left={quickCardEditor.left}
|
left={quickCardEditor.left}
|
||||||
@ -269,7 +458,7 @@ const Project = () => {
|
|||||||
<Details
|
<Details
|
||||||
refreshCache={() => {
|
refreshCache={() => {
|
||||||
console.log('beep 2!');
|
console.log('beep 2!');
|
||||||
refetch();
|
// refetch();
|
||||||
}}
|
}}
|
||||||
availableMembers={availableMembers}
|
availableMembers={availableMembers}
|
||||||
projectURL={match.url}
|
projectURL={match.url}
|
||||||
@ -284,7 +473,7 @@ const Project = () => {
|
|||||||
setTaskDetails(initialTaskDetailsState);
|
setTaskDetails(initialTaskDetailsState);
|
||||||
deleteTask({ variables: { taskID: deletedTask.taskID } });
|
deleteTask({ variables: { taskID: deletedTask.taskID } });
|
||||||
}}
|
}}
|
||||||
onOpenAddLabelPopup={(task, bounds) => {}}
|
onOpenAddLabelPopup={(task, $targetRef) => {}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import styled from 'styled-components/macro';
|
import styled from 'styled-components/macro';
|
||||||
|
import GlobalTopNavbar from 'App/TopNavbar';
|
||||||
import { useGetProjectsQuery } from 'shared/generated/graphql';
|
import { useGetProjectsQuery } from 'shared/generated/graphql';
|
||||||
|
|
||||||
import ProjectGridItem from 'shared/components/ProjectGridItem';
|
import ProjectGridItem from 'shared/components/ProjectGridItem';
|
||||||
@ -40,13 +41,18 @@ const Projects = () => {
|
|||||||
if (data) {
|
if (data) {
|
||||||
const { projects } = data;
|
const { projects } = data;
|
||||||
return (
|
return (
|
||||||
<ProjectGrid>
|
<>
|
||||||
{projects.map(project => (
|
<GlobalTopNavbar name="Projects" />
|
||||||
<ProjectLink key={project.projectID} to={`/projects/${project.projectID}`}>
|
<ProjectGrid>
|
||||||
<ProjectGridItem project={{ ...project, teamTitle: project.team.name, taskGroups: [] }} />
|
{projects.map(project => (
|
||||||
</ProjectLink>
|
<ProjectLink key={project.id} to={`/projects/${project.id}`}>
|
||||||
))}
|
<ProjectGridItem
|
||||||
</ProjectGrid>
|
project={{ ...project, projectID: project.id, teamTitle: project.team.name, taskGroups: [] }}
|
||||||
|
/>
|
||||||
|
</ProjectLink>
|
||||||
|
))}
|
||||||
|
</ProjectGrid>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <div>Error!</div>;
|
return <div>Error!</div>;
|
||||||
|
2
web/src/citadel.d.ts
vendored
2
web/src/citadel.d.ts
vendored
@ -52,7 +52,7 @@ type Task = {
|
|||||||
name: string;
|
name: string;
|
||||||
position: number;
|
position: number;
|
||||||
labels: Label[];
|
labels: Label[];
|
||||||
description?: string;
|
description?: string | null;
|
||||||
members?: Array<TaskUser>;
|
members?: Array<TaskUser>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ export const CardComposerWrapper = styled.div<{ isOpen: boolean }>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const ListCard = styled.div`
|
export const ListCard = styled.div`
|
||||||
background-color: #fff;
|
background-color: ${props => mixin.lighten('#262c49', 0.05)};
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
${mixin.boxShadowCard}
|
${mixin.boxShadowCard}
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -55,9 +55,10 @@ export const ListCardEditor = styled(TextareaAutosize)`
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
&:focus {
|
|
||||||
border: none;
|
color: #c2c6dc;
|
||||||
outline: none;
|
l &:focus {
|
||||||
|
background-color: ${props => mixin.lighten('#262c49', 0.05)};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ export const Container = styled.div<{ left: number; top: number }>`
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
left: ${props => props.left}px;
|
left: ${props => props.left}px;
|
||||||
top: ${props => props.top}px;
|
top: ${props => props.top}px;
|
||||||
padding-top: 10px;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
padding-top: 10px;
|
||||||
height: auto;
|
height: auto;
|
||||||
width: auto;
|
width: auto;
|
||||||
transform: translate(-100%);
|
transform: translate(-100%);
|
||||||
@ -18,12 +18,12 @@ export const Wrapper = styled.div`
|
|||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
box-shadow: 0 5px 25px 0 rgba(0, 0, 0, 0.1);
|
box-shadow: 0 5px 25px 0 rgba(0, 0, 0, 0.1);
|
||||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
color: #c2c6dc;
|
color: #c2c6dc;
|
||||||
background: #262c49;
|
background: #262c49;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
border-color: #414561;
|
border-color: #414561;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export const AddCardContainer = styled.div`
|
|||||||
|
|
||||||
export const AddCardButton = styled.a`
|
export const AddCardButton = styled.a`
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
color: #5e6c84;
|
color: #c2c6dc;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -32,9 +32,9 @@ export const AddCardButton = styled.a`
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(9, 30, 66, 0.08);
|
color: #c2c6dc;
|
||||||
color: #172b4d;
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
background: rgb(115, 103, 240);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const Wrapper = styled.div`
|
export const Wrapper = styled.div`
|
||||||
@ -125,4 +125,5 @@ export const ListExtraMenuButtonWrapper = styled.div`
|
|||||||
top: 4px;
|
top: 4px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
|
padding-bottom: 0;
|
||||||
`;
|
`;
|
||||||
|
@ -26,7 +26,7 @@ type Props = {
|
|||||||
wrapperProps?: any;
|
wrapperProps?: any;
|
||||||
headerProps?: any;
|
headerProps?: any;
|
||||||
index?: number;
|
index?: number;
|
||||||
onExtraMenuOpen: (taskGroupID: string, pos: ElementPosition, size: ElementSize) => void;
|
onExtraMenuOpen: (taskGroupID: string, $targetRef: React.RefObject<HTMLElement>) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const List = React.forwardRef(
|
const List = React.forwardRef(
|
||||||
@ -78,20 +78,7 @@ const List = React.forwardRef(
|
|||||||
|
|
||||||
const handleExtraMenuOpen = () => {
|
const handleExtraMenuOpen = () => {
|
||||||
if ($extraActionsRef && $extraActionsRef.current) {
|
if ($extraActionsRef && $extraActionsRef.current) {
|
||||||
const pos = $extraActionsRef.current.getBoundingClientRect();
|
onExtraMenuOpen(id, $extraActionsRef);
|
||||||
onExtraMenuOpen(
|
|
||||||
id,
|
|
||||||
{
|
|
||||||
top: pos.top,
|
|
||||||
left: pos.left,
|
|
||||||
right: pos.right,
|
|
||||||
bottom: pos.bottom,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
width: pos.width,
|
|
||||||
height: pos.height,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
useOnEscapeKeyDown(isEditingTitle, onEscape);
|
useOnEscapeKeyDown(isEditingTitle, onEscape);
|
||||||
@ -116,7 +103,7 @@ const List = React.forwardRef(
|
|||||||
{children && children}
|
{children && children}
|
||||||
<AddCardContainer hidden={isComposerOpen}>
|
<AddCardContainer hidden={isComposerOpen}>
|
||||||
<AddCardButton onClick={() => onOpenComposer(id)}>
|
<AddCardButton onClick={() => onOpenComposer(id)}>
|
||||||
<Plus size={12} color="#42526e" />
|
<Plus size={12} color="#c2c6dc" />
|
||||||
<AddCardButtonText>Add another card</AddCardButtonText>
|
<AddCardButtonText>Add another card</AddCardButtonText>
|
||||||
</AddCardButton>
|
</AddCardButton>
|
||||||
</AddCardContainer>
|
</AddCardContainer>
|
||||||
|
@ -14,19 +14,19 @@ export const ListActionItem = styled.span`
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #172b4d;
|
color: #c2c6dc;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 0 -12px;
|
margin: 0 -12px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(9, 30, 66, 0.04);
|
background: rgb(115, 103, 240);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ListSeparator = styled.hr`
|
export const ListSeparator = styled.hr`
|
||||||
background-color: rgba(9, 30, 66, 0.13);
|
background-color: #414561;
|
||||||
border: 0;
|
border: 0;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
margin: 8px 0;
|
margin: 8px 0;
|
||||||
|
@ -29,7 +29,7 @@ type Props = {
|
|||||||
onCardCreate: (taskGroupID: string, name: string) => void;
|
onCardCreate: (taskGroupID: string, name: string) => void;
|
||||||
onQuickEditorOpen: (e: ContextMenuEvent) => void;
|
onQuickEditorOpen: (e: ContextMenuEvent) => void;
|
||||||
onCreateList: (listName: string) => void;
|
onCreateList: (listName: string) => void;
|
||||||
onExtraMenuOpen: (taskGroupID: string, pos: ElementPosition, size: ElementSize) => void;
|
onExtraMenuOpen: (taskGroupID: string, $targetRef: React.RefObject<HTMLElement>) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Lists: React.FC<Props> = ({
|
const Lists: React.FC<Props> = ({
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import TextareaAutosize from 'react-autosize-textarea/lib';
|
import TextareaAutosize from 'react-autosize-textarea/lib';
|
||||||
|
import { mixin } from 'shared/utils/styles';
|
||||||
|
|
||||||
export const MemberManagerWrapper = styled.div``;
|
export const MemberManagerWrapper = styled.div``;
|
||||||
|
|
||||||
@ -11,17 +12,27 @@ export const MemberManagerSearchWrapper = styled.div`
|
|||||||
export const MemberManagerSearch = styled(TextareaAutosize)`
|
export const MemberManagerSearch = styled(TextareaAutosize)`
|
||||||
margin: 4px 0 12px;
|
margin: 4px 0 12px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: #ebecf0;
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
border: none;
|
border-radius: 3px;
|
||||||
box-shadow: inset 0 0 0 2px #dfe1e6;
|
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #172b4d;
|
font-family: 'Droid Sans';
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
background: #262c49;
|
||||||
|
outline: none;
|
||||||
|
color: #c2c6dc;
|
||||||
|
border-color: #414561;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: rgb(115, 103, 240) 0px 0px 0px 1px;
|
||||||
|
background: ${mixin.darken('#262c49', 0.15)};
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const BoardMembersLabel = styled.h4`
|
export const BoardMembersLabel = styled.h4`
|
||||||
color: #5e6c84;
|
color: #c2c6dc;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
@ -52,7 +63,7 @@ export const BoardMemberListItemContent = styled.div`
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
color: #172b4d;
|
color: #c2c6dc;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ProfileIcon = styled.div`
|
export const ProfileIcon = styled.div`
|
||||||
@ -62,7 +73,7 @@ export const ProfileIcon = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: #fff;
|
color: #c2c6dc;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
background: rgb(115, 103, 240);
|
background: rgb(115, 103, 240);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -43,7 +43,7 @@ const MemberManager: React.FC<MemberManagerProps> = ({
|
|||||||
)
|
)
|
||||||
.map(member => {
|
.map(member => {
|
||||||
return (
|
return (
|
||||||
<BoardMembersListItem>
|
<BoardMembersListItem key={member.userID}>
|
||||||
<BoardMemberListItemContent
|
<BoardMemberListItemContent
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const isActive = activeMembers.findIndex(m => m.userID === member.userID) !== -1;
|
const isActive = activeMembers.findIndex(m => m.userID === member.userID) !== -1;
|
||||||
|
@ -11,7 +11,11 @@ export const ProfileIcon = styled.div<{ bgColor: string }>`
|
|||||||
margin: 2px;
|
margin: 2px;
|
||||||
background-color: ${props => props.bgColor};
|
background-color: ${props => props.bgColor};
|
||||||
border-radius: 25em;
|
border-radius: 25em;
|
||||||
display: block;
|
font-size: 16px;
|
||||||
|
color: #fff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -20,6 +24,7 @@ export const ProfileIcon = styled.div<{ bgColor: string }>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const ProfileInfo = styled.div`
|
export const ProfileInfo = styled.div`
|
||||||
|
color: #c2c6dc;
|
||||||
margin: 0 0 0 64px;
|
margin: 0 0 0 64px;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
`;
|
`;
|
||||||
@ -29,11 +34,11 @@ export const InfoTitle = styled.h3`
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
color: #172b4d;
|
color: #c2c6dc;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const InfoUsername = styled.p`
|
export const InfoUsername = styled.p`
|
||||||
color: #5e6c84;
|
color: #c2c6dc;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
`;
|
`;
|
||||||
@ -41,10 +46,29 @@ export const InfoUsername = styled.p`
|
|||||||
export const InfoBio = styled.p`
|
export const InfoBio = styled.p`
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
color: #5e6c84;
|
color: #c2c6dc;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const MiniProfileActions = styled.ul`
|
||||||
|
list-style-type: none;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const MiniProfileActionWrapper = styled.li``;
|
||||||
|
|
||||||
|
export const MiniProfileActionItem = styled.span`
|
||||||
|
color: #c2c6dc;
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
font-weight: 400;
|
||||||
|
padding: 6px 12px;
|
||||||
|
position: relative;
|
||||||
|
text-decoration: none;
|
||||||
|
&:hover {
|
||||||
|
background: rgb(115, 103, 240);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
@ -1,14 +1,25 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Profile, ProfileIcon, ProfileInfo, InfoTitle, InfoUsername, InfoBio } from './Styles';
|
import {
|
||||||
|
Profile,
|
||||||
|
ProfileIcon,
|
||||||
|
ProfileInfo,
|
||||||
|
InfoTitle,
|
||||||
|
InfoUsername,
|
||||||
|
InfoBio,
|
||||||
|
MiniProfileActions,
|
||||||
|
MiniProfileActionWrapper,
|
||||||
|
MiniProfileActionItem,
|
||||||
|
} from './Styles';
|
||||||
|
|
||||||
type MiniProfileProps = {
|
type MiniProfileProps = {
|
||||||
displayName: string;
|
displayName: string;
|
||||||
username: string;
|
username: string;
|
||||||
bio: string;
|
bio: string;
|
||||||
profileIcon: ProfileIcon;
|
profileIcon: ProfileIcon;
|
||||||
|
onRemoveFromTask: () => void;
|
||||||
};
|
};
|
||||||
const MiniProfile: React.FC<MiniProfileProps> = ({ displayName, username, bio, profileIcon }) => {
|
const MiniProfile: React.FC<MiniProfileProps> = ({ displayName, username, bio, profileIcon, onRemoveFromTask }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Profile>
|
<Profile>
|
||||||
@ -19,6 +30,17 @@ const MiniProfile: React.FC<MiniProfileProps> = ({ displayName, username, bio, p
|
|||||||
<InfoBio>{bio}</InfoBio>
|
<InfoBio>{bio}</InfoBio>
|
||||||
</ProfileInfo>
|
</ProfileInfo>
|
||||||
</Profile>
|
</Profile>
|
||||||
|
<MiniProfileActions>
|
||||||
|
<MiniProfileActionWrapper>
|
||||||
|
<MiniProfileActionItem
|
||||||
|
onClick={() => {
|
||||||
|
onRemoveFromTask();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Remove from card
|
||||||
|
</MiniProfileActionItem>
|
||||||
|
</MiniProfileActionWrapper>
|
||||||
|
</MiniProfileActions>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@ import styled from 'styled-components';
|
|||||||
import { mixin } from 'shared/utils/styles';
|
import { mixin } from 'shared/utils/styles';
|
||||||
|
|
||||||
export const ScrollOverlay = styled.div`
|
export const ScrollOverlay = styled.div`
|
||||||
z-index: 1000000;
|
z-index: 3000;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -4,25 +4,51 @@ import { Checkmark } from 'shared/icons';
|
|||||||
import { SaveButton, DeleteButton, LabelBox, EditLabelForm, FieldLabel, FieldName } from './Styles';
|
import { SaveButton, DeleteButton, LabelBox, EditLabelForm, FieldLabel, FieldName } from './Styles';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
label: Label;
|
label: Label | null;
|
||||||
onLabelEdit: (labelId: string, labelName: string, color: string) => void;
|
onLabelEdit: (labelId: string | null, labelName: string, color: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const LabelManager = ({ label, onLabelEdit }: Props) => {
|
const LabelManager = ({ label, onLabelEdit }: Props) => {
|
||||||
const [currentLabel, setCurrentLabel] = useState('');
|
console.log(label);
|
||||||
|
const [currentLabel, setCurrentLabel] = useState(label ? label.name : '');
|
||||||
|
const [currentColor, setCurrentColor] = useState<string | null>(label ? label.color : null);
|
||||||
return (
|
return (
|
||||||
<EditLabelForm>
|
<EditLabelForm>
|
||||||
<FieldLabel>Name</FieldLabel>
|
<FieldLabel>Name</FieldLabel>
|
||||||
<FieldName id="labelName" type="text" name="name" value={currentLabel} />
|
<FieldName
|
||||||
|
id="labelName"
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
onChange={e => {
|
||||||
|
setCurrentLabel(e.currentTarget.value);
|
||||||
|
}}
|
||||||
|
value={currentLabel}
|
||||||
|
/>
|
||||||
<FieldLabel>Select a color</FieldLabel>
|
<FieldLabel>Select a color</FieldLabel>
|
||||||
<div>
|
<div>
|
||||||
{Object.values(LabelColors).map(labelColor => (
|
{Object.values(LabelColors).map(labelColor => (
|
||||||
<LabelBox color={labelColor}>
|
<LabelBox
|
||||||
<Checkmark color="#fff" size={12} />
|
color={labelColor}
|
||||||
|
onClick={() => {
|
||||||
|
setCurrentColor(labelColor);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{labelColor === currentColor && <Checkmark color="#fff" size={12} />}
|
||||||
</LabelBox>
|
</LabelBox>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<SaveButton type="submit" value="Save" />
|
<SaveButton
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault();
|
||||||
|
console.log(currentColor);
|
||||||
|
if (currentColor) {
|
||||||
|
onLabelEdit(label ? label.labelId : null, currentLabel, currentColor);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
type="submit"
|
||||||
|
value="Save"
|
||||||
|
/>
|
||||||
<DeleteButton type="submit" value="Delete" />
|
<DeleteButton type="submit" value="Delete" />
|
||||||
</div>
|
</div>
|
||||||
</EditLabelForm>
|
</EditLabelForm>
|
||||||
|
@ -1,46 +1,78 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Pencil, Checkmark } from 'shared/icons';
|
import { Pencil, Checkmark } from 'shared/icons';
|
||||||
|
|
||||||
import { LabelSearch, ActiveIcon, Labels, Label, CardLabel, Section, SectionTitle, LabelIcon } from './Styles';
|
import {
|
||||||
|
LabelSearch,
|
||||||
|
ActiveIcon,
|
||||||
|
Labels,
|
||||||
|
Label,
|
||||||
|
CardLabel,
|
||||||
|
Section,
|
||||||
|
SectionTitle,
|
||||||
|
LabelIcon,
|
||||||
|
CreateLabelButton,
|
||||||
|
} from './Styles';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
labels?: Label[];
|
labels?: Label[];
|
||||||
onLabelToggle: (labelId: string) => void;
|
onLabelToggle: (labelId: string) => void;
|
||||||
onLabelEdit: (labelId: string, labelName: string, color: string) => void;
|
onLabelEdit: (labelId: string) => void;
|
||||||
|
onLabelCreate: () => void;
|
||||||
};
|
};
|
||||||
const LabelManager: React.FC<Props> = ({ labels, onLabelToggle, onLabelEdit }) => {
|
const LabelManager: React.FC<Props> = ({ labels, onLabelToggle, onLabelEdit, onLabelCreate }) => {
|
||||||
const [currentLabel, setCurrentLabel] = useState('');
|
const [currentLabel, setCurrentLabel] = useState('');
|
||||||
|
const [currentSearch, setCurrentSearch] = useState('');
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<LabelSearch type="text" />
|
<LabelSearch
|
||||||
|
type="text"
|
||||||
|
placeholder="search labels..."
|
||||||
|
onChange={e => {
|
||||||
|
setCurrentSearch(e.currentTarget.value);
|
||||||
|
}}
|
||||||
|
value={currentSearch}
|
||||||
|
/>
|
||||||
<Section>
|
<Section>
|
||||||
<SectionTitle>Labels</SectionTitle>
|
<SectionTitle>Labels</SectionTitle>
|
||||||
<Labels>
|
<Labels>
|
||||||
{labels &&
|
{labels &&
|
||||||
labels.map(label => (
|
labels
|
||||||
<Label>
|
.filter(label => currentSearch === '' || label.name.toLowerCase().startsWith(currentSearch.toLowerCase()))
|
||||||
<LabelIcon>
|
.map(label => (
|
||||||
<Pencil />
|
<Label key={label.labelId}>
|
||||||
</LabelIcon>
|
<LabelIcon
|
||||||
<CardLabel
|
onClick={() => {
|
||||||
key={label.labelId}
|
onLabelEdit(label.labelId);
|
||||||
color={label.color}
|
}}
|
||||||
active={currentLabel === label.labelId}
|
>
|
||||||
onMouseEnter={() => {
|
<Pencil color="#c2c6dc" />
|
||||||
setCurrentLabel(label.labelId);
|
</LabelIcon>
|
||||||
}}
|
<CardLabel
|
||||||
onClick={() => onLabelToggle(label.labelId)}
|
key={label.labelId}
|
||||||
>
|
color={label.color}
|
||||||
{label.name}
|
active={currentLabel === label.labelId}
|
||||||
{label.active && (
|
onMouseEnter={() => {
|
||||||
<ActiveIcon>
|
setCurrentLabel(label.labelId);
|
||||||
<Checkmark color="#fff" />
|
}}
|
||||||
</ActiveIcon>
|
onClick={() => onLabelToggle(label.labelId)}
|
||||||
)}
|
>
|
||||||
</CardLabel>
|
{label.name}
|
||||||
</Label>
|
{label.active && (
|
||||||
))}
|
<ActiveIcon>
|
||||||
|
<Checkmark color="#fff" />
|
||||||
|
</ActiveIcon>
|
||||||
|
)}
|
||||||
|
</CardLabel>
|
||||||
|
</Label>
|
||||||
|
))}
|
||||||
</Labels>
|
</Labels>
|
||||||
|
<CreateLabelButton
|
||||||
|
onClick={() => {
|
||||||
|
onLabelCreate();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Create a new label
|
||||||
|
</CreateLabelButton>
|
||||||
</Section>
|
</Section>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useRef } from 'react';
|
import React, { useState, useRef, createRef } from 'react';
|
||||||
import { action } from '@storybook/addon-actions';
|
import { action } from '@storybook/addon-actions';
|
||||||
import LabelColors from 'shared/constants/labelColors';
|
import LabelColors from 'shared/constants/labelColors';
|
||||||
import LabelManager from 'shared/components/PopupMenu/LabelManager';
|
import LabelManager from 'shared/components/PopupMenu/LabelManager';
|
||||||
@ -7,10 +7,12 @@ import ListActions from 'shared/components/ListActions';
|
|||||||
import MemberManager from 'shared/components/MemberManager';
|
import MemberManager from 'shared/components/MemberManager';
|
||||||
import DueDateManager from 'shared/components/DueDateManager';
|
import DueDateManager from 'shared/components/DueDateManager';
|
||||||
import MiniProfile from 'shared/components/MiniProfile';
|
import MiniProfile from 'shared/components/MiniProfile';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import PopupMenu from '.';
|
import PopupMenu, { PopupProvider, usePopup, Popup } from '.';
|
||||||
import NormalizeStyles from 'App/NormalizeStyles';
|
import NormalizeStyles from 'App/NormalizeStyles';
|
||||||
import BaseStyles from 'App/BaseStyles';
|
import BaseStyles from 'App/BaseStyles';
|
||||||
|
import produce from 'immer';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: PopupMenu,
|
component: PopupMenu,
|
||||||
@ -37,19 +39,93 @@ const labelData = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const OpenLabelBtn = styled.span``;
|
||||||
|
|
||||||
|
type TabProps = {
|
||||||
|
tab: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const LabelManagerEditor = () => {
|
||||||
|
const [labels, setLabels] = useState(labelData);
|
||||||
|
const [currentLabel, setCurrentLabel] = useState('');
|
||||||
|
const { setTab } = usePopup();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Popup title="Labels" tab={0} onClose={action('on close')}>
|
||||||
|
<LabelManager
|
||||||
|
labels={labels}
|
||||||
|
onLabelCreate={() => {
|
||||||
|
setTab(2);
|
||||||
|
}}
|
||||||
|
onLabelEdit={labelId => {
|
||||||
|
setCurrentLabel(labelId);
|
||||||
|
setTab(1);
|
||||||
|
}}
|
||||||
|
onLabelToggle={labelId => {
|
||||||
|
setLabels(
|
||||||
|
produce(labels, draftState => {
|
||||||
|
const idx = labels.findIndex(label => label.labelId === labelId);
|
||||||
|
if (idx !== -1) {
|
||||||
|
draftState[idx] = { ...draftState[idx], active: !labels[idx].active };
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popup>
|
||||||
|
<Popup onClose={action('on close')} title="Edit label" tab={1}>
|
||||||
|
<LabelEditor
|
||||||
|
label={labels.find(label => label.labelId === currentLabel) ?? null}
|
||||||
|
onLabelEdit={(_labelId, name, color) => {
|
||||||
|
setLabels(
|
||||||
|
produce(labels, draftState => {
|
||||||
|
const idx = labels.findIndex(label => label.labelId === currentLabel);
|
||||||
|
if (idx !== -1) {
|
||||||
|
draftState[idx] = { ...draftState[idx], name, color };
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
setTab(0);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popup>
|
||||||
|
<Popup onClose={action('on close')} title="Create new label" tab={2}>
|
||||||
|
<LabelEditor
|
||||||
|
label={null}
|
||||||
|
onLabelEdit={(_labelId, name, color) => {
|
||||||
|
setLabels([...labels, { labelId: name, name, color, active: false }]);
|
||||||
|
setTab(0);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popup>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const OpenLabelsButton = () => {
|
||||||
|
const $buttonRef = createRef<HTMLButtonElement>();
|
||||||
|
const [currentLabel, setCurrentLabel] = useState('');
|
||||||
|
const [labels, setLabels] = useState(labelData);
|
||||||
|
const { showPopup, setTab } = usePopup();
|
||||||
|
console.log(labels);
|
||||||
|
return (
|
||||||
|
<OpenLabelBtn
|
||||||
|
ref={$buttonRef}
|
||||||
|
onClick={() => {
|
||||||
|
showPopup($buttonRef, <LabelManagerEditor />);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Open
|
||||||
|
</OpenLabelBtn>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const LabelsPopup = () => {
|
export const LabelsPopup = () => {
|
||||||
const [isPopupOpen, setPopupOpen] = useState(false);
|
const [isPopupOpen, setPopupOpen] = useState(false);
|
||||||
return (
|
return (
|
||||||
<>
|
<PopupProvider>
|
||||||
{isPopupOpen && (
|
<OpenLabelsButton />
|
||||||
<PopupMenu title="Label" top={10} onClose={() => setPopupOpen(false)} left={10}>
|
</PopupProvider>
|
||||||
<LabelManager labels={labelData} onLabelToggle={action('label toggle')} onLabelEdit={action('label edit')} />
|
|
||||||
</PopupMenu>
|
|
||||||
)}
|
|
||||||
<button type="submit" onClick={() => setPopupOpen(true)}>
|
|
||||||
Open
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,7 +134,13 @@ export const LabelsLabelEditor = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isPopupOpen && (
|
{isPopupOpen && (
|
||||||
<PopupMenu title="Change Label" top={10} onClose={() => setPopupOpen(false)} left={10}>
|
<PopupMenu
|
||||||
|
onPrevious={action('on previous')}
|
||||||
|
title="Change Label"
|
||||||
|
top={10}
|
||||||
|
onClose={() => setPopupOpen(false)}
|
||||||
|
left={10}
|
||||||
|
>
|
||||||
<LabelEditor label={labelData[0]} onLabelEdit={action('label edit')} />
|
<LabelEditor label={labelData[0]} onLabelEdit={action('label edit')} />
|
||||||
</PopupMenu>
|
</PopupMenu>
|
||||||
)}
|
)}
|
||||||
@ -201,12 +283,19 @@ export const MiniProfilePopup = () => {
|
|||||||
<NormalizeStyles />
|
<NormalizeStyles />
|
||||||
<BaseStyles />
|
<BaseStyles />
|
||||||
{popupData.isOpen && (
|
{popupData.isOpen && (
|
||||||
<PopupMenu title="Due Date" top={popupData.top} onClose={() => setPopupData(initalState)} left={popupData.left}>
|
<PopupMenu
|
||||||
|
noHeader
|
||||||
|
title="Due Date"
|
||||||
|
top={popupData.top}
|
||||||
|
onClose={() => setPopupData(initalState)}
|
||||||
|
left={popupData.left}
|
||||||
|
>
|
||||||
<MiniProfile
|
<MiniProfile
|
||||||
displayName="Jordan Knott"
|
displayName="Jordan Knott"
|
||||||
profileIcon={{ url: null, bgColor: '#000', initials: 'JK' }}
|
profileIcon={{ url: null, bgColor: '#000', initials: 'JK' }}
|
||||||
username="@jordanthedev"
|
username="@jordanthedev"
|
||||||
bio="Stuff and things"
|
bio="Stuff and things"
|
||||||
|
onRemoveFromTask={action('mini profile')}
|
||||||
/>
|
/>
|
||||||
</PopupMenu>
|
</PopupMenu>
|
||||||
)}
|
)}
|
||||||
@ -236,3 +325,4 @@ export const MiniProfilePopup = () => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,20 +1,34 @@
|
|||||||
import styled, { css } from 'styled-components';
|
import styled, { css } from 'styled-components';
|
||||||
import { mixin } from 'shared/utils/styles';
|
import { mixin } from 'shared/utils/styles';
|
||||||
|
|
||||||
export const Container = styled.div<{ top: number; left: number; ref: any }>`
|
export const Container = styled.div<{ invert: boolean; top: number; left: number; ref: any }>`
|
||||||
left: ${props => props.left}px;
|
left: ${props => props.left}px;
|
||||||
top: ${props => props.top}px;
|
top: ${props => props.top}px;
|
||||||
background: #fff;
|
|
||||||
border-radius: 3px;
|
|
||||||
box-shadow: 0 8px 16px -4px rgba(9, 30, 66, 0.25), 0 0 0 1px rgba(9, 30, 66, 0.08);
|
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 304px;
|
width: 316px;
|
||||||
z-index: 100000000000;
|
padding-top: 10px;
|
||||||
&:focus {
|
height: auto;
|
||||||
outline: none;
|
z-index: 40000;
|
||||||
border: none;
|
${props =>
|
||||||
}
|
props.invert &&
|
||||||
|
css`
|
||||||
|
transform: translate(-100%);
|
||||||
|
`}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Wrapper = styled.div`
|
||||||
|
padding: 5px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 5px 25px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
color: #c2c6dc;
|
||||||
|
background: #262c49;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
border-color: #414561;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Header = styled.div`
|
export const Header = styled.div`
|
||||||
@ -26,10 +40,10 @@ export const Header = styled.div`
|
|||||||
|
|
||||||
export const HeaderTitle = styled.span`
|
export const HeaderTitle = styled.span`
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: #5e6c84;
|
color: #c2c6dc;
|
||||||
display: block;
|
display: block;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
border-bottom: 1px solid rgba(9, 30, 66, 0.13);
|
border-bottom: 1px solid #414561;
|
||||||
margin: 0 12px;
|
margin: 0 12px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 0 32px;
|
padding: 0 32px;
|
||||||
@ -46,23 +60,30 @@ export const Content = styled.div`
|
|||||||
padding: 0 12px 12px;
|
padding: 0 12px 12px;
|
||||||
`;
|
`;
|
||||||
export const LabelSearch = styled.input`
|
export const LabelSearch = styled.input`
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
transition-property: background-color, border-color, box-shadow;
|
||||||
|
transition-duration: 85ms;
|
||||||
|
transition-timing-function: ease;
|
||||||
margin: 4px 0 12px;
|
margin: 4px 0 12px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: #fafbfc;
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
border: none;
|
|
||||||
box-shadow: inset 0 0 0 2px #dfe1e6;
|
|
||||||
color: #172b4d;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
display: block;
|
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: 'Droid Sans';
|
font-family: 'Droid Sans';
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
transition-property: background-color, border-color, box-shadow;
|
|
||||||
transition-duration: 85ms;
|
background: #262c49;
|
||||||
transition-timing-function: ease;
|
outline: none;
|
||||||
|
color: #c2c6dc;
|
||||||
|
border-color: #414561;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: rgb(115, 103, 240) 0px 0px 0px 1px;
|
||||||
|
background: ${mixin.darken('#262c49', 0.15)};
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Section = styled.div`
|
export const Section = styled.div`
|
||||||
@ -70,7 +91,7 @@ export const Section = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const SectionTitle = styled.h4`
|
export const SectionTitle = styled.h4`
|
||||||
color: #5e6c84;
|
color: #c2c6dc;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
@ -95,7 +116,7 @@ export const CardLabel = styled.span<{ active: boolean; color: string }>`
|
|||||||
props.active &&
|
props.active &&
|
||||||
css`
|
css`
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
box-shadow: -8px 0 ${mixin.darken(props.color, 0.15)};
|
box-shadow: -8px 0 ${mixin.darken(props.color, 0.12)};
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
`}
|
`}
|
||||||
|
|
||||||
@ -113,6 +134,7 @@ export const CardLabel = styled.span<{ active: boolean; color: string }>`
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
min-height: 31px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CloseButton = styled.div`
|
export const CloseButton = styled.div`
|
||||||
@ -126,8 +148,6 @@ export const CloseButton = styled.div`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 40;
|
z-index: 40;
|
||||||
height: 20px;
|
|
||||||
width: 20px;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -142,14 +162,14 @@ export const LabelIcon = styled.div`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
height: 20px;
|
height: 100%;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
width: 20px;
|
width: auto;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(9, 30, 66, 0.08);
|
background: rgb(115, 103, 240);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -186,19 +206,27 @@ export const FieldLabel = styled.label`
|
|||||||
export const FieldName = styled.input`
|
export const FieldName = styled.input`
|
||||||
margin: 4px 0 12px;
|
margin: 4px 0 12px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: #fafbfc;
|
|
||||||
border: none;
|
|
||||||
box-shadow: inset 0 0 0 2px #dfe1e6;
|
|
||||||
color: #172b4d;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
display: block;
|
display: block;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
|
background: #262c49;
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: transparent;
|
||||||
|
border-image: initial;
|
||||||
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|
||||||
|
color: #c2c6dc;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: rgb(115, 103, 240) 0px 0px 0px 1px;
|
||||||
|
background: ${mixin.darken('#262c49', 0.15)};
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const LabelBox = styled.span<{ color: string }>`
|
export const LabelBox = styled.span<{ color: string }>`
|
||||||
@ -208,6 +236,7 @@ export const LabelBox = styled.span<{ color: string }>`
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
width: 48px;
|
width: 48px;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
background-color: ${props => props.color};
|
background-color: ${props => props.color};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@ -217,6 +246,7 @@ export const LabelBox = styled.span<{ color: string }>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const SaveButton = styled.input`
|
export const SaveButton = styled.input`
|
||||||
|
cursor: pointer;
|
||||||
background-color: #5aac44;
|
background-color: #5aac44;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
border: none;
|
border: none;
|
||||||
@ -239,8 +269,7 @@ export const DeleteButton = styled.input`
|
|||||||
border: none;
|
border: none;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-block;
|
type="submit"font-weight: 400;
|
||||||
font-weight: 400;
|
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
margin: 8px 4px 0 0;
|
margin: 8px 4px 0 0;
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
@ -248,3 +277,53 @@ export const DeleteButton = styled.input`
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
float: right;
|
float: right;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const CreateLabelButton = styled.button`
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 3px;
|
||||||
|
line-height: 20px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background-color: none;
|
||||||
|
text-align: center;
|
||||||
|
color: #c2c6dc;
|
||||||
|
margin: 8px 4px 0 0;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgb(115, 103, 240);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const PreviousButton = styled.div`
|
||||||
|
padding: 10px 12px 10px 8px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 40;
|
||||||
|
cursor: pointer;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ContainerDiamond = styled.div<{ invert: boolean }>`
|
||||||
|
top: 10px;
|
||||||
|
${props => (props.invert ? 'right: 10px; ' : 'left: 15px;')}
|
||||||
|
position: absolute;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
display: block;
|
||||||
|
transform: rotate(45deg) translate(-7px);
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
border-left: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
background: #262c49;
|
||||||
|
border-color: #414561;
|
||||||
|
`;
|
||||||
|
@ -1,30 +1,219 @@
|
|||||||
import React, { useRef } from 'react';
|
import React, { useRef, createContext, RefObject, useState, useContext } from 'react';
|
||||||
import { Cross } from 'shared/icons';
|
import { Cross, AngleLeft } from 'shared/icons';
|
||||||
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
import useOnOutsideClick from 'shared/hooks/onOutsideClick';
|
||||||
import { Container, Header, HeaderTitle, Content, CloseButton } from './Styles';
|
import { createPortal } from 'react-dom';
|
||||||
|
import produce from 'immer';
|
||||||
|
import {
|
||||||
|
Container,
|
||||||
|
ContainerDiamond,
|
||||||
|
Header,
|
||||||
|
HeaderTitle,
|
||||||
|
Content,
|
||||||
|
CloseButton,
|
||||||
|
PreviousButton,
|
||||||
|
Wrapper,
|
||||||
|
} from './Styles';
|
||||||
|
|
||||||
type Props = {
|
type PopupContextState = {
|
||||||
title: string;
|
show: (target: RefObject<HTMLElement>, content: JSX.Element) => void;
|
||||||
|
setTab: (newTab: number) => void;
|
||||||
|
getCurrentTab: () => number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type PopupProps = {
|
||||||
|
title: string | null;
|
||||||
|
onClose: () => void;
|
||||||
|
tab: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type PopupContainerProps = {
|
||||||
top: number;
|
top: number;
|
||||||
left: number;
|
left: number;
|
||||||
|
invert: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PopupMenu: React.FC<Props> = ({ title, top, left, onClose, children }) => {
|
const PopupContainer: React.FC<PopupContainerProps> = ({ top, left, onClose, children, invert }) => {
|
||||||
|
const $containerRef = useRef();
|
||||||
|
useOnOutsideClick($containerRef, true, onClose, null);
|
||||||
|
return (
|
||||||
|
<Container left={left} top={top} ref={$containerRef} invert={invert}>
|
||||||
|
{children}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const PopupContext = createContext<PopupContextState>({
|
||||||
|
show: () => {},
|
||||||
|
setTab: () => {},
|
||||||
|
getCurrentTab: () => 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const usePopup = () => {
|
||||||
|
const ctx = useContext<PopupContextState>(PopupContext);
|
||||||
|
return { showPopup: ctx.show, setTab: ctx.setTab, getCurrentTab: ctx.getCurrentTab };
|
||||||
|
};
|
||||||
|
|
||||||
|
type PopupState = {
|
||||||
|
isOpen: boolean;
|
||||||
|
left: number;
|
||||||
|
top: number;
|
||||||
|
invert: boolean;
|
||||||
|
currentTab: number;
|
||||||
|
previousTab: number;
|
||||||
|
content: JSX.Element | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { Provider, Consumer } = PopupContext;
|
||||||
|
|
||||||
|
const canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
|
||||||
|
|
||||||
|
const defaultState = {
|
||||||
|
isOpen: false,
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
invert: false,
|
||||||
|
currentTab: 0,
|
||||||
|
previousTab: 0,
|
||||||
|
content: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PopupProvider: React.FC = ({ children }) => {
|
||||||
|
const [currentState, setState] = useState<PopupState>(defaultState);
|
||||||
|
const show = (target: RefObject<HTMLElement>, content: JSX.Element) => {
|
||||||
|
console.log(target);
|
||||||
|
if (target && target.current) {
|
||||||
|
const bounds = target.current.getBoundingClientRect();
|
||||||
|
if (bounds.left + 304 + 30 > window.innerWidth) {
|
||||||
|
console.log('open!');
|
||||||
|
setState({
|
||||||
|
isOpen: true,
|
||||||
|
left: bounds.left + bounds.width,
|
||||||
|
top: bounds.top + bounds.height,
|
||||||
|
invert: true,
|
||||||
|
currentTab: 0,
|
||||||
|
previousTab: 0,
|
||||||
|
content,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('open NOT INVERT!');
|
||||||
|
setState({
|
||||||
|
isOpen: true,
|
||||||
|
left: bounds.left,
|
||||||
|
top: bounds.top + bounds.height,
|
||||||
|
invert: false,
|
||||||
|
currentTab: 0,
|
||||||
|
previousTab: 0,
|
||||||
|
content,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const portalTarget = canUseDOM ? document.body : null; // appease flow
|
||||||
|
|
||||||
|
const setTab = (newTab: number) => {
|
||||||
|
setState((prevState: PopupState) => {
|
||||||
|
return {
|
||||||
|
...prevState,
|
||||||
|
previousTab: currentState.currentTab,
|
||||||
|
currentTab: newTab,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCurrentTab = () => {
|
||||||
|
return currentState.currentTab;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Provider value={{ show, setTab, getCurrentTab }}>
|
||||||
|
{portalTarget &&
|
||||||
|
currentState.isOpen &&
|
||||||
|
createPortal(
|
||||||
|
<PopupContainer
|
||||||
|
invert={currentState.invert}
|
||||||
|
top={currentState.top}
|
||||||
|
left={currentState.left}
|
||||||
|
onClose={() => setState(defaultState)}
|
||||||
|
>
|
||||||
|
{currentState.content}
|
||||||
|
<ContainerDiamond invert={currentState.invert} />
|
||||||
|
</PopupContainer>,
|
||||||
|
portalTarget,
|
||||||
|
)}
|
||||||
|
{children}
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
title: string | null;
|
||||||
|
top: number;
|
||||||
|
left: number;
|
||||||
|
onClose: () => void;
|
||||||
|
onPrevious?: () => void | null;
|
||||||
|
noHeader?: boolean | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const PopupMenu: React.FC<Props> = ({ title, top, left, onClose, noHeader, children, onPrevious }) => {
|
||||||
const $containerRef = useRef();
|
const $containerRef = useRef();
|
||||||
useOnOutsideClick($containerRef, true, onClose, null);
|
useOnOutsideClick($containerRef, true, onClose, null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container left={left} top={top} ref={$containerRef}>
|
<Container invert={false} left={left} top={top} ref={$containerRef}>
|
||||||
<Header>
|
<Wrapper>
|
||||||
<HeaderTitle>{title}</HeaderTitle>
|
{onPrevious && (
|
||||||
<CloseButton onClick={() => onClose()}>
|
<PreviousButton onClick={onPrevious}>
|
||||||
<Cross />
|
<AngleLeft color="#c2c6dc" />
|
||||||
</CloseButton>
|
</PreviousButton>
|
||||||
</Header>
|
)}
|
||||||
<Content>{children}</Content>
|
{noHeader ? (
|
||||||
|
<CloseButton onClick={() => onClose()}>
|
||||||
|
<Cross color="#c2c6dc" />
|
||||||
|
</CloseButton>
|
||||||
|
) : (
|
||||||
|
<Header>
|
||||||
|
<HeaderTitle>{title}</HeaderTitle>
|
||||||
|
<CloseButton onClick={() => onClose()}>
|
||||||
|
<Cross color="#c2c6dc" />
|
||||||
|
</CloseButton>
|
||||||
|
</Header>
|
||||||
|
)}
|
||||||
|
<Content>{children}</Content>
|
||||||
|
</Wrapper>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const Popup: React.FC<PopupProps> = ({ title, onClose, tab, children }) => {
|
||||||
|
const { getCurrentTab, setTab } = usePopup();
|
||||||
|
if (getCurrentTab() !== tab) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Wrapper>
|
||||||
|
{tab > 0 && (
|
||||||
|
<PreviousButton
|
||||||
|
onClick={() => {
|
||||||
|
setTab(0);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AngleLeft color="#c2c6dc" />
|
||||||
|
</PreviousButton>
|
||||||
|
)}
|
||||||
|
{title && (
|
||||||
|
<Header>
|
||||||
|
<HeaderTitle>{title}</HeaderTitle>
|
||||||
|
</Header>
|
||||||
|
)}
|
||||||
|
<CloseButton onClick={() => onClose()}>
|
||||||
|
<Cross color="#c2c6dc" />
|
||||||
|
</CloseButton>
|
||||||
|
<Content>{children}</Content>
|
||||||
|
</Wrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default PopupMenu;
|
export default PopupMenu;
|
||||||
|
@ -61,7 +61,7 @@ export const Default = () => {
|
|||||||
onSaveName={action('on save name')}
|
onSaveName={action('on save name')}
|
||||||
onOpenComposer={action('on open composer')}
|
onOpenComposer={action('on open composer')}
|
||||||
tasks={[]}
|
tasks={[]}
|
||||||
onExtraMenuOpen={(taskGroupID, pos, size) => console.log(taskGroupID, pos, size)}
|
onExtraMenuOpen={(taskGroupID, $targetRef) => console.log(taskGroupID, $targetRef)}
|
||||||
>
|
>
|
||||||
<ListCards>
|
<ListCards>
|
||||||
<Card
|
<Card
|
||||||
|
@ -2,7 +2,7 @@ import styled, { keyframes } from 'styled-components';
|
|||||||
import TextareaAutosize from 'react-autosize-textarea';
|
import TextareaAutosize from 'react-autosize-textarea';
|
||||||
|
|
||||||
export const Wrapper = styled.div<{ open: boolean }>`
|
export const Wrapper = styled.div<{ open: boolean }>`
|
||||||
background: rgba(0, 0, 0, 0.6);
|
background: rgba(0, 0, 0, 0.4);
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -286,4 +286,7 @@ export const UnassignedLabel = styled.div`
|
|||||||
color: rgb(137, 147, 164);
|
color: rgb(137, 147, 164);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 32px;
|
||||||
`;
|
`;
|
||||||
|
@ -47,6 +47,7 @@ export const Default = () => {
|
|||||||
onTaskDescriptionChange={(_task, desc) => setDescription(desc)}
|
onTaskDescriptionChange={(_task, desc) => setDescription(desc)}
|
||||||
onDeleteTask={action('delete task')}
|
onDeleteTask={action('delete task')}
|
||||||
onCloseModal={action('close modal')}
|
onCloseModal={action('close modal')}
|
||||||
|
onMemberProfile={action('profile')}
|
||||||
onOpenAddMemberPopup={action('open add member popup')}
|
onOpenAddMemberPopup={action('open add member popup')}
|
||||||
onOpenAddLabelPopup={action('open add label popup')}
|
onOpenAddLabelPopup={action('open add label popup')}
|
||||||
/>
|
/>
|
||||||
|
@ -93,13 +93,27 @@ const DetailsEditor: React.FC<DetailsEditorProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type TaskAssigneeProps = {
|
||||||
|
member: TaskUser;
|
||||||
|
onMemberProfile: ($targetRef: React.RefObject<HTMLElement>, memberID: string) => void;
|
||||||
|
};
|
||||||
|
const TaskAssignee: React.FC<TaskAssigneeProps> = ({ member, onMemberProfile }) => {
|
||||||
|
const $memberRef = useRef<HTMLDivElement>(null);
|
||||||
|
return (
|
||||||
|
<TaskDetailAssignee ref={$memberRef} onClick={() => onMemberProfile($memberRef, member.userID)} key={member.userID}>
|
||||||
|
<ProfileIcon>{member.profileIcon.initials ?? ''}</ProfileIcon>
|
||||||
|
</TaskDetailAssignee>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
type TaskDetailsProps = {
|
type TaskDetailsProps = {
|
||||||
task: Task;
|
task: Task;
|
||||||
onTaskNameChange: (task: Task, newName: string) => void;
|
onTaskNameChange: (task: Task, newName: string) => void;
|
||||||
onTaskDescriptionChange: (task: Task, newDescription: string) => void;
|
onTaskDescriptionChange: (task: Task, newDescription: string) => void;
|
||||||
onDeleteTask: (task: Task) => void;
|
onDeleteTask: (task: Task) => void;
|
||||||
onOpenAddMemberPopup: (task: Task, bounds: ElementBounds) => void;
|
onOpenAddMemberPopup: (task: Task, $targetRef: React.RefObject<HTMLElement>) => void;
|
||||||
onOpenAddLabelPopup: (task: Task, bounds: ElementBounds) => void;
|
onOpenAddLabelPopup: (task: Task, $targetRef: React.RefObject<HTMLElement>) => void;
|
||||||
|
onMemberProfile: ($targetRef: React.RefObject<HTMLElement>, memberID: string) => void;
|
||||||
onCloseModal: () => void;
|
onCloseModal: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -111,6 +125,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
|||||||
onCloseModal,
|
onCloseModal,
|
||||||
onOpenAddMemberPopup,
|
onOpenAddMemberPopup,
|
||||||
onOpenAddLabelPopup,
|
onOpenAddLabelPopup,
|
||||||
|
onMemberProfile,
|
||||||
}) => {
|
}) => {
|
||||||
const [editorOpen, setEditorOpen] = useState(false);
|
const [editorOpen, setEditorOpen] = useState(false);
|
||||||
const [description, setDescription] = useState(task.description ?? '');
|
const [description, setDescription] = useState(task.description ?? '');
|
||||||
@ -130,23 +145,14 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
|||||||
const $unassignedRef = useRef<HTMLDivElement>(null);
|
const $unassignedRef = useRef<HTMLDivElement>(null);
|
||||||
const $addMemberRef = useRef<HTMLDivElement>(null);
|
const $addMemberRef = useRef<HTMLDivElement>(null);
|
||||||
const onUnassignedClick = () => {
|
const onUnassignedClick = () => {
|
||||||
const bounds = convertDivElementRefToBounds($unassignedRef);
|
onOpenAddMemberPopup(task, $unassignedRef);
|
||||||
if (bounds) {
|
|
||||||
onOpenAddMemberPopup(task, bounds);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const onAddMember = () => {
|
const onAddMember = () => {
|
||||||
const bounds = convertDivElementRefToBounds($addMemberRef);
|
onOpenAddMemberPopup(task, $addMemberRef);
|
||||||
if (bounds) {
|
|
||||||
onOpenAddMemberPopup(task, bounds);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const $addLabelRef = useRef<HTMLDivElement>(null);
|
const $addLabelRef = useRef<HTMLDivElement>(null);
|
||||||
const onAddLabel = () => {
|
const onAddLabel = () => {
|
||||||
const bounds = convertDivElementRefToBounds($addLabelRef);
|
onOpenAddLabelPopup(task, $addLabelRef);
|
||||||
if (bounds) {
|
|
||||||
onOpenAddLabelPopup(task, bounds);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
console.log(task);
|
console.log(task);
|
||||||
return (
|
return (
|
||||||
@ -204,14 +210,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{task.members &&
|
{task.members &&
|
||||||
task.members.map(member => {
|
task.members.map(member => <TaskAssignee member={member} onMemberProfile={onMemberProfile} />)}
|
||||||
console.log(member);
|
|
||||||
return (
|
|
||||||
<TaskDetailAssignee key={member.userID}>
|
|
||||||
<ProfileIcon>{member.profileIcon.initials ?? ''}</ProfileIcon>
|
|
||||||
</TaskDetailAssignee>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<TaskDetailsAddMember ref={$addMemberRef} onClick={onAddMember}>
|
<TaskDetailsAddMember ref={$addMemberRef} onClick={onAddMember}>
|
||||||
<TaskDetailsAddMemberIcon>
|
<TaskDetailsAddMemberIcon>
|
||||||
<Plus size={16} color="#c2c6dc" />
|
<Plus size={16} color="#c2c6dc" />
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import styled from 'styled-components';
|
import styled, { css } from 'styled-components';
|
||||||
|
import { mixin } from 'shared/utils/styles';
|
||||||
|
|
||||||
export const NavbarWrapper = styled.div`
|
export const NavbarWrapper = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -76,8 +77,10 @@ export const ProfileIcon = styled.div<{ bgColor: string }>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const ProjectMeta = styled.div`
|
export const ProjectMeta = styled.div`
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
padding-top: 9px;
|
||||||
|
margin-left: -14px;
|
||||||
|
align-items: center;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
min-height: 51px;
|
min-height: 51px;
|
||||||
`;
|
`;
|
||||||
@ -91,11 +94,11 @@ export const ProjectTabs = styled.div`
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ProjectTab = styled.span`
|
export const ProjectTab = styled.span<{ active?: boolean }>`
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
color: #c2c6dc;
|
color: #c2c6dc;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
cursor: default;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
min-width: 1px;
|
min-width: 1px;
|
||||||
@ -103,16 +106,71 @@ export const ProjectTab = styled.span`
|
|||||||
transition-property: box-shadow, color;
|
transition-property: box-shadow, color;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
|
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
|
|
||||||
box-shadow: inset 0 -2px #d85dd8;
|
&:not(:last-child) {
|
||||||
color: #d85dd8;
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
${props =>
|
||||||
|
props.active
|
||||||
|
? css`
|
||||||
|
box-shadow: inset 0 -2px #d85dd8;
|
||||||
|
color: #d85dd8;
|
||||||
|
`
|
||||||
|
: css`
|
||||||
|
&:hover {
|
||||||
|
box-shadow: inset 0 -2px #cbd4db;
|
||||||
|
color: ${mixin.lighten('#c2c6dc', 0.25)};
|
||||||
|
}
|
||||||
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ProjectName = styled.h1`
|
export const ProjectName = styled.h1`
|
||||||
color: #c2c6dc;
|
color: #c2c6dc;
|
||||||
margin-top: 9px;
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
padding: 6px 10px 6px 8px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ProjectSwitcher = styled.button`
|
||||||
|
font-size: 20px;
|
||||||
|
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
width: 100px;
|
||||||
|
border-radius: 3px;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 6px 4px;
|
||||||
|
background-color: none;
|
||||||
|
text-align: center;
|
||||||
|
color: #c2c6dc;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background: rgb(115, 103, 240);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Separator = styled.div`
|
||||||
|
color: #c2c6dc;
|
||||||
|
font-size: 16px;
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ProjectSettingsButton = styled.button`
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
line-height: 20px;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
background-color: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background: rgb(115, 103, 240);
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -38,6 +38,7 @@ export const Default = () => {
|
|||||||
<NormalizeStyles />
|
<NormalizeStyles />
|
||||||
<BaseStyles />
|
<BaseStyles />
|
||||||
<TopNavbar
|
<TopNavbar
|
||||||
|
projectName="Projects"
|
||||||
bgColor="#7367F0"
|
bgColor="#7367F0"
|
||||||
firstName="Jordan"
|
firstName="Jordan"
|
||||||
lastName="Knott"
|
lastName="Knott"
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { Bell } from 'shared/icons';
|
import { Star, Bell, Cog, AngleDown } from 'shared/icons';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
NotificationContainer,
|
NotificationContainer,
|
||||||
GlobalActions,
|
GlobalActions,
|
||||||
ProjectActions,
|
ProjectActions,
|
||||||
|
ProjectSwitcher,
|
||||||
|
Separator,
|
||||||
ProjectMeta,
|
ProjectMeta,
|
||||||
ProjectName,
|
ProjectName,
|
||||||
ProjectTabs,
|
ProjectTabs,
|
||||||
@ -13,6 +15,7 @@ import {
|
|||||||
NavbarHeader,
|
NavbarHeader,
|
||||||
Breadcrumbs,
|
Breadcrumbs,
|
||||||
BreadcrumpSeparator,
|
BreadcrumpSeparator,
|
||||||
|
ProjectSettingsButton,
|
||||||
ProfileIcon,
|
ProfileIcon,
|
||||||
ProfileContainer,
|
ProfileContainer,
|
||||||
ProfileNameWrapper,
|
ProfileNameWrapper,
|
||||||
@ -21,6 +24,7 @@ import {
|
|||||||
} from './Styles';
|
} from './Styles';
|
||||||
|
|
||||||
type NavBarProps = {
|
type NavBarProps = {
|
||||||
|
projectName: string;
|
||||||
onProfileClick: (bottom: number, right: number) => void;
|
onProfileClick: (bottom: number, right: number) => void;
|
||||||
onNotificationClick: () => void;
|
onNotificationClick: () => void;
|
||||||
bgColor: string;
|
bgColor: string;
|
||||||
@ -29,6 +33,7 @@ type NavBarProps = {
|
|||||||
initials: string;
|
initials: string;
|
||||||
};
|
};
|
||||||
const NavBar: React.FC<NavBarProps> = ({
|
const NavBar: React.FC<NavBarProps> = ({
|
||||||
|
projectName,
|
||||||
onProfileClick,
|
onProfileClick,
|
||||||
onNotificationClick,
|
onNotificationClick,
|
||||||
firstName,
|
firstName,
|
||||||
@ -47,10 +52,19 @@ const NavBar: React.FC<NavBarProps> = ({
|
|||||||
<NavbarHeader>
|
<NavbarHeader>
|
||||||
<ProjectActions>
|
<ProjectActions>
|
||||||
<ProjectMeta>
|
<ProjectMeta>
|
||||||
<ProjectName>Production Team</ProjectName>
|
<ProjectSwitcher>Projects</ProjectSwitcher>
|
||||||
|
<Separator>»</Separator>
|
||||||
|
<ProjectName>{projectName}</ProjectName>
|
||||||
|
<ProjectSettingsButton>
|
||||||
|
<AngleDown color="#c2c6dc" />
|
||||||
|
</ProjectSettingsButton>
|
||||||
|
<Star filled color="#c2c6dc" />
|
||||||
</ProjectMeta>
|
</ProjectMeta>
|
||||||
<ProjectTabs>
|
<ProjectTabs>
|
||||||
<ProjectTab>Board</ProjectTab>
|
<ProjectTab active>Board</ProjectTab>
|
||||||
|
<ProjectTab>Calender</ProjectTab>
|
||||||
|
<ProjectTab>Timeline</ProjectTab>
|
||||||
|
<ProjectTab>Wiki</ProjectTab>
|
||||||
</ProjectTabs>
|
</ProjectTabs>
|
||||||
</ProjectActions>
|
</ProjectActions>
|
||||||
<GlobalActions>
|
<GlobalActions>
|
||||||
|
@ -17,7 +17,7 @@ export type Scalars = {
|
|||||||
|
|
||||||
export type ProjectLabel = {
|
export type ProjectLabel = {
|
||||||
__typename?: 'ProjectLabel';
|
__typename?: 'ProjectLabel';
|
||||||
projectLabelID: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
createdDate: Scalars['Time'];
|
createdDate: Scalars['Time'];
|
||||||
colorHex: Scalars['String'];
|
colorHex: Scalars['String'];
|
||||||
name?: Maybe<Scalars['String']>;
|
name?: Maybe<Scalars['String']>;
|
||||||
@ -25,7 +25,7 @@ export type ProjectLabel = {
|
|||||||
|
|
||||||
export type TaskLabel = {
|
export type TaskLabel = {
|
||||||
__typename?: 'TaskLabel';
|
__typename?: 'TaskLabel';
|
||||||
taskLabelID: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
projectLabelID: Scalars['UUID'];
|
projectLabelID: Scalars['UUID'];
|
||||||
assignedDate: Scalars['Time'];
|
assignedDate: Scalars['Time'];
|
||||||
colorHex: Scalars['String'];
|
colorHex: Scalars['String'];
|
||||||
@ -41,7 +41,7 @@ export type ProfileIcon = {
|
|||||||
|
|
||||||
export type ProjectMember = {
|
export type ProjectMember = {
|
||||||
__typename?: 'ProjectMember';
|
__typename?: 'ProjectMember';
|
||||||
userID: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
firstName: Scalars['String'];
|
firstName: Scalars['String'];
|
||||||
lastName: Scalars['String'];
|
lastName: Scalars['String'];
|
||||||
profileIcon: ProfileIcon;
|
profileIcon: ProfileIcon;
|
||||||
@ -49,7 +49,7 @@ export type ProjectMember = {
|
|||||||
|
|
||||||
export type RefreshToken = {
|
export type RefreshToken = {
|
||||||
__typename?: 'RefreshToken';
|
__typename?: 'RefreshToken';
|
||||||
tokenId: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
userId: Scalars['UUID'];
|
userId: Scalars['UUID'];
|
||||||
expiresAt: Scalars['Time'];
|
expiresAt: Scalars['Time'];
|
||||||
createdAt: Scalars['Time'];
|
createdAt: Scalars['Time'];
|
||||||
@ -57,7 +57,7 @@ export type RefreshToken = {
|
|||||||
|
|
||||||
export type UserAccount = {
|
export type UserAccount = {
|
||||||
__typename?: 'UserAccount';
|
__typename?: 'UserAccount';
|
||||||
userID: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
email: Scalars['String'];
|
email: Scalars['String'];
|
||||||
createdAt: Scalars['Time'];
|
createdAt: Scalars['Time'];
|
||||||
firstName: Scalars['String'];
|
firstName: Scalars['String'];
|
||||||
@ -68,14 +68,14 @@ export type UserAccount = {
|
|||||||
|
|
||||||
export type Team = {
|
export type Team = {
|
||||||
__typename?: 'Team';
|
__typename?: 'Team';
|
||||||
teamID: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
createdAt: Scalars['Time'];
|
createdAt: Scalars['Time'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Project = {
|
export type Project = {
|
||||||
__typename?: 'Project';
|
__typename?: 'Project';
|
||||||
projectID: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
createdAt: Scalars['Time'];
|
createdAt: Scalars['Time'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
team: Team;
|
team: Team;
|
||||||
@ -87,7 +87,7 @@ export type Project = {
|
|||||||
|
|
||||||
export type TaskGroup = {
|
export type TaskGroup = {
|
||||||
__typename?: 'TaskGroup';
|
__typename?: 'TaskGroup';
|
||||||
taskGroupID: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
projectID: Scalars['String'];
|
projectID: Scalars['String'];
|
||||||
createdAt: Scalars['Time'];
|
createdAt: Scalars['Time'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
@ -97,7 +97,7 @@ export type TaskGroup = {
|
|||||||
|
|
||||||
export type Task = {
|
export type Task = {
|
||||||
__typename?: 'Task';
|
__typename?: 'Task';
|
||||||
taskID: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
taskGroup: TaskGroup;
|
taskGroup: TaskGroup;
|
||||||
createdAt: Scalars['Time'];
|
createdAt: Scalars['Time'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
@ -382,14 +382,29 @@ export type AssignTaskMutation = (
|
|||||||
{ __typename?: 'Mutation' }
|
{ __typename?: 'Mutation' }
|
||||||
& { assignTask: (
|
& { assignTask: (
|
||||||
{ __typename?: 'Task' }
|
{ __typename?: 'Task' }
|
||||||
& Pick<Task, 'taskID'>
|
& Pick<Task, 'id'>
|
||||||
& { assigned: Array<(
|
& { assigned: Array<(
|
||||||
{ __typename?: 'ProjectMember' }
|
{ __typename?: 'ProjectMember' }
|
||||||
& Pick<ProjectMember, 'userID' | 'firstName' | 'lastName'>
|
& Pick<ProjectMember, 'id' | 'firstName' | 'lastName'>
|
||||||
)> }
|
)> }
|
||||||
) }
|
) }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export type CreateProjectLabelMutationVariables = {
|
||||||
|
projectID: Scalars['UUID'];
|
||||||
|
labelColorID: Scalars['UUID'];
|
||||||
|
name: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type CreateProjectLabelMutation = (
|
||||||
|
{ __typename?: 'Mutation' }
|
||||||
|
& { createProjectLabel: (
|
||||||
|
{ __typename?: 'ProjectLabel' }
|
||||||
|
& Pick<ProjectLabel, 'id' | 'createdDate' | 'colorHex' | 'name'>
|
||||||
|
) }
|
||||||
|
);
|
||||||
|
|
||||||
export type CreateTaskMutationVariables = {
|
export type CreateTaskMutationVariables = {
|
||||||
taskGroupID: Scalars['String'];
|
taskGroupID: Scalars['String'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
@ -401,11 +416,18 @@ export type CreateTaskMutation = (
|
|||||||
{ __typename?: 'Mutation' }
|
{ __typename?: 'Mutation' }
|
||||||
& { createTask: (
|
& { createTask: (
|
||||||
{ __typename?: 'Task' }
|
{ __typename?: 'Task' }
|
||||||
& Pick<Task, 'taskID' | 'name' | 'position'>
|
& Pick<Task, 'id' | 'name' | 'position' | 'description'>
|
||||||
& { taskGroup: (
|
& { taskGroup: (
|
||||||
{ __typename?: 'TaskGroup' }
|
{ __typename?: 'TaskGroup' }
|
||||||
& Pick<TaskGroup, 'taskGroupID'>
|
& Pick<TaskGroup, 'id'>
|
||||||
) }
|
), assigned: Array<(
|
||||||
|
{ __typename?: 'ProjectMember' }
|
||||||
|
& Pick<ProjectMember, 'id' | 'firstName' | 'lastName'>
|
||||||
|
& { profileIcon: (
|
||||||
|
{ __typename?: 'ProfileIcon' }
|
||||||
|
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
||||||
|
) }
|
||||||
|
)> }
|
||||||
) }
|
) }
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -420,7 +442,7 @@ export type CreateTaskGroupMutation = (
|
|||||||
{ __typename?: 'Mutation' }
|
{ __typename?: 'Mutation' }
|
||||||
& { createTaskGroup: (
|
& { createTaskGroup: (
|
||||||
{ __typename?: 'TaskGroup' }
|
{ __typename?: 'TaskGroup' }
|
||||||
& Pick<TaskGroup, 'taskGroupID' | 'name' | 'position'>
|
& Pick<TaskGroup, 'id' | 'name' | 'position'>
|
||||||
) }
|
) }
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -449,10 +471,10 @@ export type DeleteTaskGroupMutation = (
|
|||||||
& Pick<DeleteTaskGroupPayload, 'ok' | 'affectedRows'>
|
& Pick<DeleteTaskGroupPayload, 'ok' | 'affectedRows'>
|
||||||
& { taskGroup: (
|
& { taskGroup: (
|
||||||
{ __typename?: 'TaskGroup' }
|
{ __typename?: 'TaskGroup' }
|
||||||
& Pick<TaskGroup, 'taskGroupID'>
|
& Pick<TaskGroup, 'id'>
|
||||||
& { tasks: Array<(
|
& { tasks: Array<(
|
||||||
{ __typename?: 'Task' }
|
{ __typename?: 'Task' }
|
||||||
& Pick<Task, 'taskID' | 'name'>
|
& Pick<Task, 'id' | 'name'>
|
||||||
)> }
|
)> }
|
||||||
) }
|
) }
|
||||||
) }
|
) }
|
||||||
@ -470,20 +492,23 @@ export type FindProjectQuery = (
|
|||||||
& Pick<Project, 'name'>
|
& Pick<Project, 'name'>
|
||||||
& { members: Array<(
|
& { members: Array<(
|
||||||
{ __typename?: 'ProjectMember' }
|
{ __typename?: 'ProjectMember' }
|
||||||
& Pick<ProjectMember, 'userID' | 'firstName' | 'lastName'>
|
& Pick<ProjectMember, 'id' | 'firstName' | 'lastName'>
|
||||||
& { profileIcon: (
|
& { profileIcon: (
|
||||||
{ __typename?: 'ProfileIcon' }
|
{ __typename?: 'ProfileIcon' }
|
||||||
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
||||||
) }
|
) }
|
||||||
|
)>, labels: Array<(
|
||||||
|
{ __typename?: 'ProjectLabel' }
|
||||||
|
& Pick<ProjectLabel, 'id' | 'createdDate' | 'colorHex' | 'name'>
|
||||||
)>, taskGroups: Array<(
|
)>, taskGroups: Array<(
|
||||||
{ __typename?: 'TaskGroup' }
|
{ __typename?: 'TaskGroup' }
|
||||||
& Pick<TaskGroup, 'taskGroupID' | 'name' | 'position'>
|
& Pick<TaskGroup, 'id' | 'name' | 'position'>
|
||||||
& { tasks: Array<(
|
& { tasks: Array<(
|
||||||
{ __typename?: 'Task' }
|
{ __typename?: 'Task' }
|
||||||
& Pick<Task, 'taskID' | 'name' | 'position' | 'description'>
|
& Pick<Task, 'id' | 'name' | 'position' | 'description'>
|
||||||
& { assigned: Array<(
|
& { assigned: Array<(
|
||||||
{ __typename?: 'ProjectMember' }
|
{ __typename?: 'ProjectMember' }
|
||||||
& Pick<ProjectMember, 'userID' | 'firstName' | 'lastName'>
|
& Pick<ProjectMember, 'id' | 'firstName' | 'lastName'>
|
||||||
& { profileIcon: (
|
& { profileIcon: (
|
||||||
{ __typename?: 'ProfileIcon' }
|
{ __typename?: 'ProfileIcon' }
|
||||||
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
||||||
@ -503,13 +528,13 @@ export type FindTaskQuery = (
|
|||||||
{ __typename?: 'Query' }
|
{ __typename?: 'Query' }
|
||||||
& { findTask: (
|
& { findTask: (
|
||||||
{ __typename?: 'Task' }
|
{ __typename?: 'Task' }
|
||||||
& Pick<Task, 'taskID' | 'name' | 'description' | 'position'>
|
& Pick<Task, 'id' | 'name' | 'description' | 'position'>
|
||||||
& { taskGroup: (
|
& { taskGroup: (
|
||||||
{ __typename?: 'TaskGroup' }
|
{ __typename?: 'TaskGroup' }
|
||||||
& Pick<TaskGroup, 'taskGroupID'>
|
& Pick<TaskGroup, 'id'>
|
||||||
), assigned: Array<(
|
), assigned: Array<(
|
||||||
{ __typename?: 'ProjectMember' }
|
{ __typename?: 'ProjectMember' }
|
||||||
& Pick<ProjectMember, 'userID' | 'firstName' | 'lastName'>
|
& Pick<ProjectMember, 'id' | 'firstName' | 'lastName'>
|
||||||
& { profileIcon: (
|
& { profileIcon: (
|
||||||
{ __typename?: 'ProfileIcon' }
|
{ __typename?: 'ProfileIcon' }
|
||||||
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
& Pick<ProfileIcon, 'url' | 'initials' | 'bgColor'>
|
||||||
@ -525,10 +550,10 @@ export type GetProjectsQuery = (
|
|||||||
{ __typename?: 'Query' }
|
{ __typename?: 'Query' }
|
||||||
& { projects: Array<(
|
& { projects: Array<(
|
||||||
{ __typename?: 'Project' }
|
{ __typename?: 'Project' }
|
||||||
& Pick<Project, 'projectID' | 'name'>
|
& Pick<Project, 'id' | 'name'>
|
||||||
& { team: (
|
& { team: (
|
||||||
{ __typename?: 'Team' }
|
{ __typename?: 'Team' }
|
||||||
& Pick<Team, 'teamID' | 'name'>
|
& Pick<Team, 'id' | 'name'>
|
||||||
) }
|
) }
|
||||||
)> }
|
)> }
|
||||||
);
|
);
|
||||||
@ -558,10 +583,10 @@ export type UnassignTaskMutation = (
|
|||||||
{ __typename?: 'Mutation' }
|
{ __typename?: 'Mutation' }
|
||||||
& { unassignTask: (
|
& { unassignTask: (
|
||||||
{ __typename?: 'Task' }
|
{ __typename?: 'Task' }
|
||||||
& Pick<Task, 'taskID'>
|
& Pick<Task, 'id'>
|
||||||
& { assigned: Array<(
|
& { assigned: Array<(
|
||||||
{ __typename?: 'ProjectMember' }
|
{ __typename?: 'ProjectMember' }
|
||||||
& Pick<ProjectMember, 'userID' | 'firstName' | 'lastName'>
|
& Pick<ProjectMember, 'id' | 'firstName' | 'lastName'>
|
||||||
)> }
|
)> }
|
||||||
) }
|
) }
|
||||||
);
|
);
|
||||||
@ -576,7 +601,7 @@ export type UpdateTaskDescriptionMutation = (
|
|||||||
{ __typename?: 'Mutation' }
|
{ __typename?: 'Mutation' }
|
||||||
& { updateTaskDescription: (
|
& { updateTaskDescription: (
|
||||||
{ __typename?: 'Task' }
|
{ __typename?: 'Task' }
|
||||||
& Pick<Task, 'taskID'>
|
& Pick<Task, 'id'>
|
||||||
) }
|
) }
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -590,7 +615,7 @@ export type UpdateTaskGroupLocationMutation = (
|
|||||||
{ __typename?: 'Mutation' }
|
{ __typename?: 'Mutation' }
|
||||||
& { updateTaskGroupLocation: (
|
& { updateTaskGroupLocation: (
|
||||||
{ __typename?: 'TaskGroup' }
|
{ __typename?: 'TaskGroup' }
|
||||||
& Pick<TaskGroup, 'taskGroupID' | 'position'>
|
& Pick<TaskGroup, 'id' | 'position'>
|
||||||
) }
|
) }
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -605,7 +630,7 @@ export type UpdateTaskLocationMutation = (
|
|||||||
{ __typename?: 'Mutation' }
|
{ __typename?: 'Mutation' }
|
||||||
& { updateTaskLocation: (
|
& { updateTaskLocation: (
|
||||||
{ __typename?: 'Task' }
|
{ __typename?: 'Task' }
|
||||||
& Pick<Task, 'taskID' | 'createdAt' | 'name' | 'position'>
|
& Pick<Task, 'id' | 'createdAt' | 'name' | 'position'>
|
||||||
) }
|
) }
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -619,7 +644,7 @@ export type UpdateTaskNameMutation = (
|
|||||||
{ __typename?: 'Mutation' }
|
{ __typename?: 'Mutation' }
|
||||||
& { updateTaskName: (
|
& { updateTaskName: (
|
||||||
{ __typename?: 'Task' }
|
{ __typename?: 'Task' }
|
||||||
& Pick<Task, 'taskID' | 'name' | 'position'>
|
& Pick<Task, 'id' | 'name' | 'position'>
|
||||||
) }
|
) }
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -627,12 +652,12 @@ export type UpdateTaskNameMutation = (
|
|||||||
export const AssignTaskDocument = gql`
|
export const AssignTaskDocument = gql`
|
||||||
mutation assignTask($taskID: UUID!, $userID: UUID!) {
|
mutation assignTask($taskID: UUID!, $userID: UUID!) {
|
||||||
assignTask(input: {taskID: $taskID, userID: $userID}) {
|
assignTask(input: {taskID: $taskID, userID: $userID}) {
|
||||||
|
id
|
||||||
assigned {
|
assigned {
|
||||||
userID
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
}
|
}
|
||||||
taskID
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -662,15 +687,63 @@ export function useAssignTaskMutation(baseOptions?: ApolloReactHooks.MutationHoo
|
|||||||
export type AssignTaskMutationHookResult = ReturnType<typeof useAssignTaskMutation>;
|
export type AssignTaskMutationHookResult = ReturnType<typeof useAssignTaskMutation>;
|
||||||
export type AssignTaskMutationResult = ApolloReactCommon.MutationResult<AssignTaskMutation>;
|
export type AssignTaskMutationResult = ApolloReactCommon.MutationResult<AssignTaskMutation>;
|
||||||
export type AssignTaskMutationOptions = ApolloReactCommon.BaseMutationOptions<AssignTaskMutation, AssignTaskMutationVariables>;
|
export type AssignTaskMutationOptions = ApolloReactCommon.BaseMutationOptions<AssignTaskMutation, AssignTaskMutationVariables>;
|
||||||
|
export const CreateProjectLabelDocument = gql`
|
||||||
|
mutation createProjectLabel($projectID: UUID!, $labelColorID: UUID!, $name: String!) {
|
||||||
|
createProjectLabel(input: {projectID: $projectID, labelColorID: $labelColorID, name: $name}) {
|
||||||
|
id
|
||||||
|
createdDate
|
||||||
|
colorHex
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type CreateProjectLabelMutationFn = ApolloReactCommon.MutationFunction<CreateProjectLabelMutation, CreateProjectLabelMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useCreateProjectLabelMutation__
|
||||||
|
*
|
||||||
|
* To run a mutation, you first call `useCreateProjectLabelMutation` within a React component and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useCreateProjectLabelMutation` 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 [createProjectLabelMutation, { data, loading, error }] = useCreateProjectLabelMutation({
|
||||||
|
* variables: {
|
||||||
|
* projectID: // value for 'projectID'
|
||||||
|
* labelColorID: // value for 'labelColorID'
|
||||||
|
* name: // value for 'name'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useCreateProjectLabelMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<CreateProjectLabelMutation, CreateProjectLabelMutationVariables>) {
|
||||||
|
return ApolloReactHooks.useMutation<CreateProjectLabelMutation, CreateProjectLabelMutationVariables>(CreateProjectLabelDocument, baseOptions);
|
||||||
|
}
|
||||||
|
export type CreateProjectLabelMutationHookResult = ReturnType<typeof useCreateProjectLabelMutation>;
|
||||||
|
export type CreateProjectLabelMutationResult = ApolloReactCommon.MutationResult<CreateProjectLabelMutation>;
|
||||||
|
export type CreateProjectLabelMutationOptions = ApolloReactCommon.BaseMutationOptions<CreateProjectLabelMutation, CreateProjectLabelMutationVariables>;
|
||||||
export const CreateTaskDocument = gql`
|
export const CreateTaskDocument = gql`
|
||||||
mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
|
mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
|
||||||
createTask(input: {taskGroupID: $taskGroupID, name: $name, position: $position}) {
|
createTask(input: {taskGroupID: $taskGroupID, name: $name, position: $position}) {
|
||||||
taskID
|
id
|
||||||
taskGroup {
|
|
||||||
taskGroupID
|
|
||||||
}
|
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
|
description
|
||||||
|
taskGroup {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
assigned {
|
||||||
|
id
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
profileIcon {
|
||||||
|
url
|
||||||
|
initials
|
||||||
|
bgColor
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -704,7 +777,7 @@ export type CreateTaskMutationOptions = ApolloReactCommon.BaseMutationOptions<Cr
|
|||||||
export const CreateTaskGroupDocument = gql`
|
export const CreateTaskGroupDocument = gql`
|
||||||
mutation createTaskGroup($projectID: String!, $name: String!, $position: Float!) {
|
mutation createTaskGroup($projectID: String!, $name: String!, $position: Float!) {
|
||||||
createTaskGroup(input: {projectID: $projectID, name: $name, position: $position}) {
|
createTaskGroup(input: {projectID: $projectID, name: $name, position: $position}) {
|
||||||
taskGroupID
|
id
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
}
|
}
|
||||||
@ -775,9 +848,9 @@ export const DeleteTaskGroupDocument = gql`
|
|||||||
ok
|
ok
|
||||||
affectedRows
|
affectedRows
|
||||||
taskGroup {
|
taskGroup {
|
||||||
taskGroupID
|
id
|
||||||
tasks {
|
tasks {
|
||||||
taskID
|
id
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -814,7 +887,7 @@ export const FindProjectDocument = gql`
|
|||||||
findProject(input: {projectId: $projectId}) {
|
findProject(input: {projectId: $projectId}) {
|
||||||
name
|
name
|
||||||
members {
|
members {
|
||||||
userID
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
profileIcon {
|
profileIcon {
|
||||||
@ -823,17 +896,23 @@ export const FindProjectDocument = gql`
|
|||||||
bgColor
|
bgColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
labels {
|
||||||
|
id
|
||||||
|
createdDate
|
||||||
|
colorHex
|
||||||
|
name
|
||||||
|
}
|
||||||
taskGroups {
|
taskGroups {
|
||||||
taskGroupID
|
id
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
tasks {
|
tasks {
|
||||||
taskID
|
id
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
description
|
description
|
||||||
assigned {
|
assigned {
|
||||||
userID
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
profileIcon {
|
profileIcon {
|
||||||
@ -876,15 +955,15 @@ export type FindProjectQueryResult = ApolloReactCommon.QueryResult<FindProjectQu
|
|||||||
export const FindTaskDocument = gql`
|
export const FindTaskDocument = gql`
|
||||||
query findTask($taskID: UUID!) {
|
query findTask($taskID: UUID!) {
|
||||||
findTask(input: {taskID: $taskID}) {
|
findTask(input: {taskID: $taskID}) {
|
||||||
taskID
|
id
|
||||||
name
|
name
|
||||||
description
|
description
|
||||||
position
|
position
|
||||||
taskGroup {
|
taskGroup {
|
||||||
taskGroupID
|
id
|
||||||
}
|
}
|
||||||
assigned {
|
assigned {
|
||||||
userID
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
profileIcon {
|
profileIcon {
|
||||||
@ -925,10 +1004,10 @@ export type FindTaskQueryResult = ApolloReactCommon.QueryResult<FindTaskQuery, F
|
|||||||
export const GetProjectsDocument = gql`
|
export const GetProjectsDocument = gql`
|
||||||
query getProjects {
|
query getProjects {
|
||||||
projects {
|
projects {
|
||||||
projectID
|
id
|
||||||
name
|
name
|
||||||
team {
|
team {
|
||||||
teamID
|
id
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1000,11 +1079,11 @@ export const UnassignTaskDocument = gql`
|
|||||||
mutation unassignTask($taskID: UUID!, $userID: UUID!) {
|
mutation unassignTask($taskID: UUID!, $userID: UUID!) {
|
||||||
unassignTask(input: {taskID: $taskID, userID: $userID}) {
|
unassignTask(input: {taskID: $taskID, userID: $userID}) {
|
||||||
assigned {
|
assigned {
|
||||||
userID
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
}
|
}
|
||||||
taskID
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -1037,7 +1116,7 @@ export type UnassignTaskMutationOptions = ApolloReactCommon.BaseMutationOptions<
|
|||||||
export const UpdateTaskDescriptionDocument = gql`
|
export const UpdateTaskDescriptionDocument = gql`
|
||||||
mutation updateTaskDescription($taskID: UUID!, $description: String!) {
|
mutation updateTaskDescription($taskID: UUID!, $description: String!) {
|
||||||
updateTaskDescription(input: {taskID: $taskID, description: $description}) {
|
updateTaskDescription(input: {taskID: $taskID, description: $description}) {
|
||||||
taskID
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -1070,7 +1149,7 @@ export type UpdateTaskDescriptionMutationOptions = ApolloReactCommon.BaseMutatio
|
|||||||
export const UpdateTaskGroupLocationDocument = gql`
|
export const UpdateTaskGroupLocationDocument = gql`
|
||||||
mutation updateTaskGroupLocation($taskGroupID: UUID!, $position: Float!) {
|
mutation updateTaskGroupLocation($taskGroupID: UUID!, $position: Float!) {
|
||||||
updateTaskGroupLocation(input: {taskGroupID: $taskGroupID, position: $position}) {
|
updateTaskGroupLocation(input: {taskGroupID: $taskGroupID, position: $position}) {
|
||||||
taskGroupID
|
id
|
||||||
position
|
position
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1104,7 +1183,7 @@ export type UpdateTaskGroupLocationMutationOptions = ApolloReactCommon.BaseMutat
|
|||||||
export const UpdateTaskLocationDocument = gql`
|
export const UpdateTaskLocationDocument = gql`
|
||||||
mutation updateTaskLocation($taskID: String!, $taskGroupID: String!, $position: Float!) {
|
mutation updateTaskLocation($taskID: String!, $taskGroupID: String!, $position: Float!) {
|
||||||
updateTaskLocation(input: {taskID: $taskID, taskGroupID: $taskGroupID, position: $position}) {
|
updateTaskLocation(input: {taskID: $taskID, taskGroupID: $taskGroupID, position: $position}) {
|
||||||
taskID
|
id
|
||||||
createdAt
|
createdAt
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
@ -1141,7 +1220,7 @@ export type UpdateTaskLocationMutationOptions = ApolloReactCommon.BaseMutationOp
|
|||||||
export const UpdateTaskNameDocument = gql`
|
export const UpdateTaskNameDocument = gql`
|
||||||
mutation updateTaskName($taskID: String!, $name: String!) {
|
mutation updateTaskName($taskID: String!, $name: String!) {
|
||||||
updateTaskName(input: {taskID: $taskID, name: $name}) {
|
updateTaskName(input: {taskID: $taskID, name: $name}) {
|
||||||
taskID
|
id
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
mutation assignTask($taskID: UUID!, $userID: UUID!) {
|
mutation assignTask($taskID: UUID!, $userID: UUID!) {
|
||||||
assignTask(input: {taskID: $taskID, userID: $userID}) {
|
assignTask(input: {taskID: $taskID, userID: $userID}) {
|
||||||
|
id
|
||||||
assigned {
|
assigned {
|
||||||
userID
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
}
|
}
|
||||||
taskID
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
web/src/shared/graphql/createProjectLabel.graphqls
Normal file
8
web/src/shared/graphql/createProjectLabel.graphqls
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
mutation createProjectLabel($projectID: UUID!, $labelColorID: UUID!, $name: String!) {
|
||||||
|
createProjectLabel(input:{projectID:$projectID, labelColorID: $labelColorID, name: $name}) {
|
||||||
|
id
|
||||||
|
createdDate
|
||||||
|
colorHex
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,21 @@
|
|||||||
mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
|
mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
|
||||||
createTask(input: { taskGroupID: $taskGroupID, name: $name, position: $position }) {
|
createTask(input: { taskGroupID: $taskGroupID, name: $name, position: $position }) {
|
||||||
taskID
|
id
|
||||||
taskGroup {
|
|
||||||
taskGroupID
|
|
||||||
}
|
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
|
description
|
||||||
|
taskGroup {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
assigned {
|
||||||
|
id
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
profileIcon {
|
||||||
|
url
|
||||||
|
initials
|
||||||
|
bgColor
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ mutation createTaskGroup( $projectID: String!, $name: String!, $position: Float!
|
|||||||
createTaskGroup(
|
createTaskGroup(
|
||||||
input: { projectID: $projectID, name: $name, position: $position }
|
input: { projectID: $projectID, name: $name, position: $position }
|
||||||
) {
|
) {
|
||||||
taskGroupID
|
id
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@ mutation deleteTaskGroup($taskGroupID: UUID!) {
|
|||||||
ok
|
ok
|
||||||
affectedRows
|
affectedRows
|
||||||
taskGroup {
|
taskGroup {
|
||||||
taskGroupID
|
id
|
||||||
tasks {
|
tasks {
|
||||||
taskID
|
id
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ query findProject($projectId: String!) {
|
|||||||
findProject(input: { projectId: $projectId }) {
|
findProject(input: { projectId: $projectId }) {
|
||||||
name
|
name
|
||||||
members {
|
members {
|
||||||
userID
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
profileIcon {
|
profileIcon {
|
||||||
@ -11,17 +11,23 @@ query findProject($projectId: String!) {
|
|||||||
bgColor
|
bgColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
labels {
|
||||||
|
id
|
||||||
|
createdDate
|
||||||
|
colorHex
|
||||||
|
name
|
||||||
|
}
|
||||||
taskGroups {
|
taskGroups {
|
||||||
taskGroupID
|
id
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
tasks {
|
tasks {
|
||||||
taskID
|
id
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
description
|
description
|
||||||
assigned {
|
assigned {
|
||||||
userID
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
profileIcon {
|
profileIcon {
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
query findTask($taskID: UUID!) {
|
query findTask($taskID: UUID!) {
|
||||||
findTask(input: {taskID: $taskID}) {
|
findTask(input: {taskID: $taskID}) {
|
||||||
taskID
|
id
|
||||||
name
|
name
|
||||||
description
|
description
|
||||||
position
|
position
|
||||||
taskGroup {
|
taskGroup {
|
||||||
taskGroupID
|
id
|
||||||
}
|
}
|
||||||
assigned {
|
assigned {
|
||||||
userID
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
profileIcon {
|
profileIcon {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
query getProjects {
|
query getProjects {
|
||||||
projects {
|
projects {
|
||||||
projectID
|
id
|
||||||
name
|
name
|
||||||
team {
|
team {
|
||||||
teamID
|
id
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
mutation unassignTask($taskID: UUID!, $userID: UUID!) {
|
mutation unassignTask($taskID: UUID!, $userID: UUID!) {
|
||||||
unassignTask(input: {taskID: $taskID, userID: $userID}) {
|
unassignTask(input: {taskID: $taskID, userID: $userID}) {
|
||||||
assigned {
|
assigned {
|
||||||
userID
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
}
|
}
|
||||||
taskID
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
mutation updateTaskDescription($taskID: UUID!, $description: String!) {
|
mutation updateTaskDescription($taskID: UUID!, $description: String!) {
|
||||||
updateTaskDescription(input: {taskID: $taskID, description: $description}) {
|
updateTaskDescription(input: {taskID: $taskID, description: $description}) {
|
||||||
taskID
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
mutation updateTaskGroupLocation($taskGroupID: UUID!, $position: Float!) {
|
mutation updateTaskGroupLocation($taskGroupID: UUID!, $position: Float!) {
|
||||||
updateTaskGroupLocation(input:{taskGroupID:$taskGroupID, position: $position}) {
|
updateTaskGroupLocation(input:{taskGroupID:$taskGroupID, position: $position}) {
|
||||||
taskGroupID
|
id
|
||||||
position
|
position
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
mutation updateTaskLocation($taskID: String!, $taskGroupID: String!, $position: Float!) {
|
mutation updateTaskLocation($taskID: String!, $taskGroupID: String!, $position: Float!) {
|
||||||
updateTaskLocation(input: { taskID: $taskID, taskGroupID: $taskGroupID, position: $position }) {
|
updateTaskLocation(input: { taskID: $taskID, taskGroupID: $taskGroupID, position: $position }) {
|
||||||
taskID
|
id
|
||||||
createdAt
|
createdAt
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
mutation updateTaskName($taskID: String!, $name: String!) {
|
mutation updateTaskName($taskID: String!, $name: String!) {
|
||||||
updateTaskName(input: { taskID: $taskID, name: $name }) {
|
updateTaskName(input: { taskID: $taskID, name: $name }) {
|
||||||
taskID
|
id
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
}
|
}
|
||||||
|
27
web/src/shared/icons/AngleDown.tsx
Normal file
27
web/src/shared/icons/AngleDown.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
width: number | string;
|
||||||
|
height: number | string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const AngleDown = ({ width, height, color }: Props) => {
|
||||||
|
return (
|
||||||
|
<svg width={width} height={height} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
|
||||||
|
<path
|
||||||
|
fill={color}
|
||||||
|
d="M143 352.3L7 216.3c-9.4-9.4-9.4-24.6 0-33.9l22.6-22.6c9.4-9.4 24.6-9.4 33.9 0l96.4 96.4 96.4-96.4c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9l-136 136c-9.2 9.4-24.4 9.4-33.8 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
AngleDown.defaultProps = {
|
||||||
|
width: 24,
|
||||||
|
height: 16,
|
||||||
|
color: '#000',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AngleDown;
|
||||||
|
|
24
web/src/shared/icons/AngleLeft.tsx
Normal file
24
web/src/shared/icons/AngleLeft.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
size: number | string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const AngleLeft = ({ size, color }: Props) => {
|
||||||
|
return (
|
||||||
|
<svg width={size} height={size} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 512">
|
||||||
|
<path
|
||||||
|
fill={color}
|
||||||
|
d="M31.7 239l136-136c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9L127.9 256l96.4 96.4c9.4 9.4 9.4 24.6 0 33.9L201.7 409c-9.4 9.4-24.6 9.4-33.9 0l-136-136c-9.5-9.4-9.5-24.6-.1-34z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
AngleLeft.defaultProps = {
|
||||||
|
size: 16,
|
||||||
|
color: '#000',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AngleLeft;
|
@ -7,8 +7,8 @@ type Props = {
|
|||||||
|
|
||||||
const Bell = ({ size, color }: Props) => {
|
const Bell = ({ size, color }: Props) => {
|
||||||
return (
|
return (
|
||||||
<svg fill={color} xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16">
|
<svg fill={color} xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 448 512">
|
||||||
<path d="M16.023 12.5c0-4.5-4-3.5-4-7 0-0.29-0.028-0.538-0.079-0.749-0.263-1.766-1.44-3.183-2.965-3.615 0.014-0.062 0.021-0.125 0.021-0.191 0-0.52-0.45-0.945-1-0.945s-1 0.425-1 0.945c0 0.065 0.007 0.129 0.021 0.191-1.71 0.484-2.983 2.208-3.020 4.273-0.001 0.030-0.001 0.060-0.001 0.091 0 3.5-4 2.5-4 7 0 1.191 2.665 2.187 6.234 2.439 0.336 0.631 1.001 1.061 1.766 1.061s1.43-0.43 1.766-1.061c3.568-0.251 6.234-1.248 6.234-2.439 0-0.004-0-0.007-0-0.011l0.024 0.011zM12.91 13.345c-0.847 0.226-1.846 0.389-2.918 0.479-0.089-1.022-0.947-1.824-1.992-1.824s-1.903 0.802-1.992 1.824c-1.072-0.090-2.071-0.253-2.918-0.479-1.166-0.311-1.724-0.659-1.928-0.845 0.204-0.186 0.762-0.534 1.928-0.845 1.356-0.362 3.1-0.561 4.91-0.561s3.554 0.199 4.91 0.561c1.166 0.311 1.724 0.659 1.928 0.845-0.204 0.186-0.762 0.534-1.928 0.845z" />
|
<path d="M439.39 362.29c-19.32-20.76-55.47-51.99-55.47-154.29 0-77.7-54.48-139.9-127.94-155.16V32c0-17.67-14.32-32-31.98-32s-31.98 14.33-31.98 32v20.84C118.56 68.1 64.08 130.3 64.08 208c0 102.3-36.15 133.53-55.47 154.29-6 6.45-8.66 14.16-8.61 21.71.11 16.4 12.98 32 32.1 32h383.8c19.12 0 32-15.6 32.1-32 .05-7.55-2.61-15.27-8.61-21.71zM67.53 368c21.22-27.97 44.42-74.33 44.53-159.42 0-.2-.06-.38-.06-.58 0-61.86 50.14-112 112-112s112 50.14 112 112c0 .2-.06.38-.06.58.11 85.1 23.31 131.46 44.53 159.42H67.53zM224 512c35.32 0 63.97-28.65 63.97-64H160.03c0 35.35 28.65 64 63.97 64z" />
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
24
web/src/shared/icons/Bolt.tsx
Normal file
24
web/src/shared/icons/Bolt.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
size: number | string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Bolt = ({ size, color }: Props) => {
|
||||||
|
return (
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" width={size} height={size}>
|
||||||
|
<path
|
||||||
|
fill={color}
|
||||||
|
d="M296 160H180.6l42.6-129.8C227.2 15 215.7 0 200 0H56C44 0 33.8 8.9 32.2 20.8l-32 240C-1.7 275.2 9.5 288 24 288h118.7L96.6 482.5c-3.6 15.2 8 29.5 23.3 29.5 8.4 0 16.4-4.4 20.8-12l176-304c9.3-15.9-2.2-36-20.7-36z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Bolt.defaultProps = {
|
||||||
|
size: 16,
|
||||||
|
color: '#000',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Bolt;
|
24
web/src/shared/icons/Cog.tsx
Normal file
24
web/src/shared/icons/Cog.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
size: number | string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Cog = ({ size, color }: Props) => {
|
||||||
|
return (
|
||||||
|
<svg width={size} height={size} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
|
<path
|
||||||
|
fill={color}
|
||||||
|
d="M487.4 315.7l-42.6-24.6c4.3-23.2 4.3-47 0-70.2l42.6-24.6c4.9-2.8 7.1-8.6 5.5-14-11.1-35.6-30-67.8-54.7-94.6-3.8-4.1-10-5.1-14.8-2.3L380.8 110c-17.9-15.4-38.5-27.3-60.8-35.1V25.8c0-5.6-3.9-10.5-9.4-11.7-36.7-8.2-74.3-7.8-109.2 0-5.5 1.2-9.4 6.1-9.4 11.7V75c-22.2 7.9-42.8 19.8-60.8 35.1L88.7 85.5c-4.9-2.8-11-1.9-14.8 2.3-24.7 26.7-43.6 58.9-54.7 94.6-1.7 5.4.6 11.2 5.5 14L67.3 221c-4.3 23.2-4.3 47 0 70.2l-42.6 24.6c-4.9 2.8-7.1 8.6-5.5 14 11.1 35.6 30 67.8 54.7 94.6 3.8 4.1 10 5.1 14.8 2.3l42.6-24.6c17.9 15.4 38.5 27.3 60.8 35.1v49.2c0 5.6 3.9 10.5 9.4 11.7 36.7 8.2 74.3 7.8 109.2 0 5.5-1.2 9.4-6.1 9.4-11.7v-49.2c22.2-7.9 42.8-19.8 60.8-35.1l42.6 24.6c4.9 2.8 11 1.9 14.8-2.3 24.7-26.7 43.6-58.9 54.7-94.6 1.5-5.5-.7-11.3-5.6-14.1zM256 336c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Cog.defaultProps = {
|
||||||
|
size: 16,
|
||||||
|
color: '#000',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Cog;
|
@ -7,8 +7,8 @@ type Props = {
|
|||||||
|
|
||||||
const Cross = ({ size, color }: Props) => {
|
const Cross = ({ size, color }: Props) => {
|
||||||
return (
|
return (
|
||||||
<svg fill={color} xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16">
|
<svg fill={color} width={size} height={size} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 352 512">
|
||||||
<path d="M15.854 12.854c-0-0-0-0-0-0l-4.854-4.854 4.854-4.854c0-0 0-0 0-0 0.052-0.052 0.090-0.113 0.114-0.178 0.066-0.178 0.028-0.386-0.114-0.529l-2.293-2.293c-0.143-0.143-0.351-0.181-0.529-0.114-0.065 0.024-0.126 0.062-0.178 0.114 0 0-0 0-0 0l-4.854 4.854-4.854-4.854c-0-0-0-0-0-0-0.052-0.052-0.113-0.090-0.178-0.114-0.178-0.066-0.386-0.029-0.529 0.114l-2.293 2.293c-0.143 0.143-0.181 0.351-0.114 0.529 0.024 0.065 0.062 0.126 0.114 0.178 0 0 0 0 0 0l4.854 4.854-4.854 4.854c-0 0-0 0-0 0-0.052 0.052-0.090 0.113-0.114 0.178-0.066 0.178-0.029 0.386 0.114 0.529l2.293 2.293c0.143 0.143 0.351 0.181 0.529 0.114 0.065-0.024 0.126-0.062 0.178-0.114 0-0 0-0 0-0l4.854-4.854 4.854 4.854c0 0 0 0 0 0 0.052 0.052 0.113 0.090 0.178 0.114 0.178 0.066 0.386 0.029 0.529-0.114l2.293-2.293c0.143-0.143 0.181-0.351 0.114-0.529-0.024-0.065-0.062-0.126-0.114-0.178z" />
|
<path d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z" />
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
36
web/src/shared/icons/Star.tsx
Normal file
36
web/src/shared/icons/Star.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
width: number | string;
|
||||||
|
height: number | string;
|
||||||
|
color: string;
|
||||||
|
filled: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Star = ({ width, height, color, filled }: Props) => {
|
||||||
|
return (
|
||||||
|
<svg width={width} height={height} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||||||
|
{filled ? (
|
||||||
|
<path
|
||||||
|
fill={color}
|
||||||
|
d="M259.3 17.8L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0z"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<path
|
||||||
|
fill={color}
|
||||||
|
d="M528.1 171.5L382 150.2 316.7 17.8c-11.7-23.6-45.6-23.9-57.4 0L194 150.2 47.9 171.5c-26.2 3.8-36.7 36.1-17.7 54.6l105.7 103-25 145.5c-4.5 26.3 23.2 46 46.4 33.7L288 439.6l130.7 68.7c23.2 12.2 50.9-7.4 46.4-33.7l-25-145.5 105.7-103c19-18.5 8.5-50.8-17.7-54.6zM388.6 312.3l23.7 138.4L288 385.4l-124.3 65.3 23.7-138.4-100.6-98 139-20.2 62.2-126 62.2 126 139 20.2-100.6 98z"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Star.defaultProps = {
|
||||||
|
width: 24,
|
||||||
|
height: 16,
|
||||||
|
color: '#000',
|
||||||
|
filled: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Star;
|
||||||
|
|
24
web/src/shared/icons/Tags.tsx
Normal file
24
web/src/shared/icons/Tags.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
size: number | string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Tags = ({ size, color }: Props) => {
|
||||||
|
return (
|
||||||
|
<svg width={size} height={size} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512">
|
||||||
|
<path
|
||||||
|
fill={color}
|
||||||
|
d="M497.941 225.941L286.059 14.059A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v204.118a48 48 0 0 0 14.059 33.941l211.882 211.882c18.744 18.745 49.136 18.746 67.882 0l204.118-204.118c18.745-18.745 18.745-49.137 0-67.882zM112 160c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm513.941 133.823L421.823 497.941c-18.745 18.745-49.137 18.745-67.882 0l-.36-.36L527.64 323.522c16.999-16.999 26.36-39.6 26.36-63.64s-9.362-46.641-26.36-63.64L331.397 0h48.721a48 48 0 0 1 33.941 14.059l211.882 211.882c18.745 18.745 18.745 49.137 0 67.882z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Tags.defaultProps = {
|
||||||
|
size: 16,
|
||||||
|
color: '#000',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Tags;
|
24
web/src/shared/icons/ToggleOn.tsx
Normal file
24
web/src/shared/icons/ToggleOn.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
size: number | string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ToggleOn = ({ size, color }: Props) => {
|
||||||
|
return (
|
||||||
|
<svg width={size} height={size} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||||||
|
<path
|
||||||
|
fill={color}
|
||||||
|
d="M384 64H192C86 64 0 150 0 256s86 192 192 192h192c106 0 192-86 192-192S490 64 384 64zm0 320c-70.8 0-128-57.3-128-128 0-70.8 57.3-128 128-128 70.8 0 128 57.3 128 128 0 70.8-57.3 128-128 128z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ToggleOn.defaultProps = {
|
||||||
|
size: 16,
|
||||||
|
color: '#000',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ToggleOn;
|
@ -1,6 +1,10 @@
|
|||||||
import Cross from './Cross';
|
import Cross from './Cross';
|
||||||
|
import Cog from './Cog';
|
||||||
|
import Bolt from './Bolt';
|
||||||
import Plus from './Plus';
|
import Plus from './Plus';
|
||||||
import Bell from './Bell';
|
import Bell from './Bell';
|
||||||
|
import AngleLeft from './AngleLeft';
|
||||||
|
import AngleDown from './AngleDown';
|
||||||
import Bin from './Bin';
|
import Bin from './Bin';
|
||||||
import Pencil from './Pencil';
|
import Pencil from './Pencil';
|
||||||
import Checkmark from './Checkmark';
|
import Checkmark from './Checkmark';
|
||||||
@ -13,5 +17,31 @@ import Stack from './Stack';
|
|||||||
import Question from './Question';
|
import Question from './Question';
|
||||||
import Exit from './Exit';
|
import Exit from './Exit';
|
||||||
import Ellipsis from './Ellipsis';
|
import Ellipsis from './Ellipsis';
|
||||||
|
import ToggleOn from './ToggleOn';
|
||||||
|
import Tags from './Tags';
|
||||||
|
import Star from './Star';
|
||||||
|
|
||||||
export { Cross, Plus, Bell, Ellipsis, Bin, Exit, Pencil, Stack, Question, Home, Citadel, Checkmark, User, Users, Lock };
|
export {
|
||||||
|
Star,
|
||||||
|
AngleDown,
|
||||||
|
Cross,
|
||||||
|
Cog,
|
||||||
|
Bolt,
|
||||||
|
Plus,
|
||||||
|
Bell,
|
||||||
|
AngleLeft,
|
||||||
|
Tags,
|
||||||
|
Ellipsis,
|
||||||
|
Bin,
|
||||||
|
Exit,
|
||||||
|
Pencil,
|
||||||
|
Stack,
|
||||||
|
Question,
|
||||||
|
Home,
|
||||||
|
Citadel,
|
||||||
|
Checkmark,
|
||||||
|
User,
|
||||||
|
Users,
|
||||||
|
Lock,
|
||||||
|
ToggleOn,
|
||||||
|
};
|
||||||
|
@ -2,7 +2,7 @@ import produce from 'immer';
|
|||||||
|
|
||||||
export const addTask = (currentState: BoardState, newTask: Task) => {
|
export const addTask = (currentState: BoardState, newTask: Task) => {
|
||||||
return produce(currentState, (draftState: BoardState) => {
|
return produce(currentState, (draftState: BoardState) => {
|
||||||
currentState.tasks[newTask.taskID] = newTask;
|
draftState.tasks[newTask.taskID] = newTask;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user